I want my black rectangles to move up and down in a loop, but I don't know how to do it. I tried, but I am having problem with MovingRect class.
Here is the whole code:
import pygame
import sys
pygame.init()
pygame.display.set_caption("My Game")
screen = pygame.display.set_mode((1200, 600))
clock = pygame.time.Clock()
BLUE = pygame.Color('dodgerblue3')
ORANGE = pygame.Color('sienna3')
BLACK = (0, 0, 0)
WHITE = (255,255,255)
RED = (255, 0, 0)
GREEN = (13, 255, 0)
YELLOW = (0, 255, 20)
BRIGHT_YELLOW = (255, 255, 20)
class MovingRect(pygame.Rect):
def __init__(self, x, y, w, h, vel):
# Calling the __init__ method of the parent class
super().__init__(x, y, w, h)
self.vel = vel
def update(self):
self.x += self.vel # Moving
if self.right > 600 or self.left < 320: # If it's not in this area
self.vel = -self.vel # Inverting the direction
def update2(self):
self.x += self.vel
if self.right > 1180 or self.left < 620:
self.vel = -self.vel
def update3(self):
self.y += self.vel
if self.top > 20 or self.bottom < 400:
self.vel = -self.vel
def quit_game():
pygame.quit()
sys.exit()
def text_objects(text, font):
textSurface = font.render(text, True, BLACK)
return textSurface, textSurface.get_rect()
def button(msg, x, y, w, h, ic, ac, action = None):
mouse = pygame.mouse.get_pos()
click = pygame.mouse.get_pressed()
if x + w > mouse[0] > x and y + h > mouse[1] > y:
pygame.draw.rect(screen, ac, (x, y, w, h))
if click[0] == 1 and action is not None:
action()
else:
pygame.draw.rect(screen, ic, (x, y, w, h))
smallText = pygame.font.Font("freesansbold.ttf",50)
textSurf, textRect = text_objects(msg, smallText)
textRect.center = ((x+(w/2)), (y+(h/2)))
screen.blit(textSurf, textRect)
def restart():
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
quit_game()
screen.fill(BLUE)
button("Restart", 525, 250, 150, 60, BRIGHT_YELLOW, YELLOW, menu)
button("Quit", 525, 350, 150, 60, BRIGHT_YELLOW, YELLOW, quit_game)
pygame.display.update()
pygame.display.flip()
clock.tick(60)
def front_page():
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
quit_game()
screen.fill(WHITE)
button("Start", 525, 250, 150, 60, BRIGHT_YELLOW, YELLOW, menu)
button("Quit", 525, 350, 150, 60, BRIGHT_YELLOW, YELLOW, quit_game)
pygame.display.update()
pygame.display.flip()
clock.tick(60)
def menu():
vel = 4
vel_left = 5
vel_right = -5
player = pygame.Rect(40, 45, 30, 30)
walls = [
pygame.Rect(0, 0, 1200, 20), pygame.Rect(0, 0, 20, 600),
pygame.Rect(0, 580, 1200, 20), pygame.Rect(1180, 0, 20, 600),
pygame.Rect(300, 0, 20, 530), pygame.Rect(20, 100, 230, 20),
pygame.Rect(70, 200, 230, 20), pygame.Rect(20, 300, 230, 20),
pygame.Rect(70, 400, 230, 20), pygame.Rect(600, 100, 20, 500)
]
movingrects = [
MovingRect(320, 120, 30, 30, vel_left),
MovingRect(320, 240, 30, 30, vel_left),
MovingRect(320, 360, 30, 30, vel_left),
MovingRect(570, 180, 30, 30, vel_right),
MovingRect(570, 300, 30, 30, vel_right),
MovingRect(570, 420, 30, 30, vel_right)
]
movingrects2 = [
MovingRect(1140, 120, 30, 30, vel_left),
MovingRect(1140, 240, 30, 30, vel_left),
MovingRect(1140, 360, 30, 30, vel_left),
MovingRect(620, 180, 30, 30, vel_right),
MovingRect(620, 300, 30, 30, vel_right),
MovingRect(620, 420, 30, 30, vel_right),
]
movingrects3 = [
MovingRect(700, 20, 30, 30, vel_left),
MovingRect(820, 20, 30, 30, vel_left),
MovingRect(940, 450, 30, 30, vel_right),
MovingRect(1060, 450, 30, 30, vel_right)
]
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
quit_game()
keys = pygame.key.get_pressed()
# Player coordinates
if keys[pygame.K_LEFT] and player.x > 0:
player.x -= vel
if keys[pygame.K_RIGHT] and player.x < 1200 - player.width:
player.x += vel
if keys[pygame.K_UP] and player.y > 0:
player.y -= vel
if keys[pygame.K_DOWN] and player.y < 600 - player.height:
player.y += vel
for wall in walls:
# Check if the player rectangle collides with a wall rectangle
if player.colliderect(wall):
print("Game over")
pygame.time.wait(1000)
restart()
for movingrect in movingrects:
movingrect.update() # Movement and bounds checking
if player.colliderect(movingrect):
print("Game over")
# TO DO #
for movingrect2 in movingrects2:
movingrect2.update2()
if player.colliderect(movingrect2):
print("Game over")
for movingrect3 in movingrects3:
movingrect3.update2()
if player.colliderect(movingrect3):
print("Game over")
# Drawing everything
screen.fill(WHITE)
pygame.draw.rect(screen, RED, player)
for wall in walls:
pygame.draw.rect(screen, BLACK, wall)
for movingrect in movingrects:
pygame.draw.rect(screen, GREEN, movingrect)
for movingrect2 in movingrects2:
pygame.draw.rect(screen, GREEN, movingrect2)
for movingrect3 in movingrects3:
pygame.draw.rect(screen, BLACK, movingrect3)
pygame.draw.rect(screen, RED, player)
pygame.display.update()
pygame.display.flip()
clock.tick(60)
def main():
scene = front_page # Set the current scene.
while scene is not None:
# Execute the current scene function. When it's done
# it returns either the next scene or None which we
# assign to the scene variable.
scene = scene()
main()
pygame.quit()
Here is the class for moving rectangles, black rectangles are in function update3
class MovingRect(pygame.Rect):
def __init__(self, x, y, w, h, vel):
# Calling the __init__ method of the parent class
super().__init__(x, y, w, h)
self.vel = vel
def update(self):
self.x += self.vel # Moving
if self.right > 600 or self.left < 320: # If it's not in this area
self.vel = -self.vel # Inverting the direction
def update2(self):
self.x += self.vel
if self.right > 1180 or self.left < 620:
self.vel = -self.vel
def update3(self):
self.y += self.vel
if self.top > 20 or self.bottom < 400:
self.vel = -self.vel
And here i am having problem when I call the class, I can't figure out when i write vel.bottom or vel.top why it doesn't work, but if I write vel.right or vel.left it works
movingrects3 = [
MovingRect(700, 20, 30, 30, vel_left),
MovingRect(820, 20, 30, 30, vel_left),
MovingRect(940, 450, 30, 30, vel_right),
MovingRect(1060, 450, 30, 30, vel_right)
]
The main issue with your code is that for all the MovingRectangles in movingrects3, you were updating them using the update2 method, instead of the update3 method. The update2 method only increments the x value, which moves the rectangle horizontally, instead of vertically. However, the update3 method does increment the y value, which will move the rectangles vertically.
To fix this problem:
First, I, of course, changed the line movingrect3.update2() to movingrect3.update3().
Then, I created screen_width, and screen_height variables, at the top of the script, which we can use for collision detection in the update3 method.
Lastly, I changed the collision detection code so that the rectangle will collide off of the bottom and top walls. To do this, I checked if the self.top was less than 20 (the height of the walls), or if the self.bottom was greater than screen_height minus 20. Remember that the point (0, 0) is at the top-left, in pygame.
Here is the fixed code:
import pygame
import sys
pygame.init()
pygame.display.set_caption("My Game")
screen_width, screen_height = 1200, 600
screen = pygame.display.set_mode((screen_width, screen_height))
clock = pygame.time.Clock()
BLUE = pygame.Color('dodgerblue3')
ORANGE = pygame.Color('sienna3')
BLACK = (0, 0, 0)
WHITE = (255,255,255)
RED = (255, 0, 0)
GREEN = (13, 255, 0)
YELLOW = (0, 255, 20)
BRIGHT_YELLOW = (255, 255, 20)
class MovingRect(pygame.Rect):
def __init__(self, x, y, w, h, vel):
# Calling the __init__ method of the parent class
super().__init__(x, y, w, h)
self.vel = vel
def update(self):
self.x += self.vel # Moving
if self.right > 600 or self.left < 320: # If it's not in this area
self.vel = -self.vel # Inverting the direction
def update2(self):
self.x += self.vel
if self.right > 1180 or self.left < 620:
self.vel = -self.vel
def update3(self):
self.y += self.vel
if self.top < 20 or self.bottom > screen_height-20:
self.vel = -self.vel
def quit_game():
pygame.quit()
sys.exit()
def text_objects(text, font):
textSurface = font.render(text, True, BLACK)
return textSurface, textSurface.get_rect()
def button(msg, x, y, w, h, ic, ac, action = None):
mouse = pygame.mouse.get_pos()
click = pygame.mouse.get_pressed()
if x + w > mouse[0] > x and y + h > mouse[1] > y:
pygame.draw.rect(screen, ac, (x, y, w, h))
if click[0] == 1 and action is not None:
action()
else:
pygame.draw.rect(screen, ic, (x, y, w, h))
smallText = pygame.font.Font("freesansbold.ttf",50)
textSurf, textRect = text_objects(msg, smallText)
textRect.center = ((x+(w/2)), (y+(h/2)))
screen.blit(textSurf, textRect)
def restart():
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
quit_game()
screen.fill(BLUE)
button("Restart", 525, 250, 150, 60, BRIGHT_YELLOW, YELLOW, menu)
button("Quit", 525, 350, 150, 60, BRIGHT_YELLOW, YELLOW, quit_game)
pygame.display.update()
pygame.display.flip()
clock.tick(60)
def front_page():
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
quit_game()
screen.fill(WHITE)
button("Start", 525, 250, 150, 60, BRIGHT_YELLOW, YELLOW, menu)
button("Quit", 525, 350, 150, 60, BRIGHT_YELLOW, YELLOW, quit_game)
pygame.display.update()
pygame.display.flip()
clock.tick(60)
def menu():
vel = 4
vel_left = 5
vel_right = -5
player = pygame.Rect(40, 45, 30, 30)
walls = [
pygame.Rect(0, 0, 1200, 20), pygame.Rect(0, 0, 20, 600),
pygame.Rect(0, 580, 1200, 20), pygame.Rect(1180, 0, 20, 600),
pygame.Rect(300, 0, 20, 530), pygame.Rect(20, 100, 230, 20),
pygame.Rect(70, 200, 230, 20), pygame.Rect(20, 300, 230, 20),
pygame.Rect(70, 400, 230, 20), pygame.Rect(600, 100, 20, 500)
]
movingrects = [
MovingRect(320, 120, 30, 30, vel_left),
MovingRect(320, 240, 30, 30, vel_left),
MovingRect(320, 360, 30, 30, vel_left),
MovingRect(570, 180, 30, 30, vel_right),
MovingRect(570, 300, 30, 30, vel_right),
MovingRect(570, 420, 30, 30, vel_right)
]
movingrects2 = [
MovingRect(1140, 120, 30, 30, vel_left),
MovingRect(1140, 240, 30, 30, vel_left),
MovingRect(1140, 360, 30, 30, vel_left),
MovingRect(620, 180, 30, 30, vel_right),
MovingRect(620, 300, 30, 30, vel_right),
MovingRect(620, 420, 30, 30, vel_right),
]
movingrects3 = [
MovingRect(700, 20, 30, 30, vel_left),
MovingRect(820, 20, 30, 30, vel_left),
MovingRect(940, 450, 30, 30, vel_right),
MovingRect(1060, 450, 30, 30, vel_right)
]
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
quit_game()
keys = pygame.key.get_pressed()
# Player coordinates
if keys[pygame.K_LEFT] and player.x > 0:
player.x -= vel
if keys[pygame.K_RIGHT] and player.x < 1200 - player.width:
player.x += vel
if keys[pygame.K_UP] and player.y > 0:
player.y -= vel
if keys[pygame.K_DOWN] and player.y < 600 - player.height:
player.y += vel
for wall in walls:
# Check if the player rectangle collides with a wall rectangle
if player.colliderect(wall):
print("Game over")
pygame.time.wait(1000)
restart()
for movingrect in movingrects:
movingrect.update() # Movement and bounds checking
if player.colliderect(movingrect):
print("Game over")
# TO DO #
for movingrect2 in movingrects2:
movingrect2.update2()
if player.colliderect(movingrect2):
print("Game over")
for movingrect3 in movingrects3:
movingrect3.update3()
if player.colliderect(movingrect3):
print("Game over")
# Drawing everything
screen.fill(WHITE)
pygame.draw.rect(screen, RED, player)
for wall in walls:
pygame.draw.rect(screen, BLACK, wall)
for movingrect in movingrects:
pygame.draw.rect(screen, GREEN, movingrect)
for movingrect2 in movingrects2:
pygame.draw.rect(screen, GREEN, movingrect2)
for movingrect3 in movingrects3:
pygame.draw.rect(screen, RED, movingrect3)
pygame.draw.rect(screen, BLACK, player)
pygame.display.update()
pygame.display.flip()
clock.tick(60)
def main():
scene = front_page # Set the current scene.
while scene is not None:
# Execute the current scene function. When it's done
# it returns either the next scene or None which we
# assign to the scene variable.
scene = scene()
main()
pygame.quit()
Of course, you may change the initial positions of these moving rectangles as you want, and you can also change the velocity, and collision detection.
Also, as a side note, you may want to look into object-oriented programming a little more. While the code works fine, it is not idiomatic, in an object-oriented sense. What would be common is to instead create one superclass called something like GameRectangle, without an update method, and create 3 more classes, maybe called Wall, GreenRect, and BlackRect which implement their own update method.
I hope this answer helped you, and if you have any further questions, please feel free to leave an answer below!
Related
This question already has answers here:
How do I detect collision in pygame?
(5 answers)
rect collision with list of rects
(2 answers)
Closed 9 months ago.
I am fairly new to python (I just started at the beginning of this year). I am working on this maze game project for a school assignment in which you use the up, down, and side keys to move a red square through a maze. the goal is to get to the end without colliding with one of the many black rectangles that make up the maze. I already know of one way to make it so when the square hits one of the rectangles the game ends (text will pop up on the screen asking if the player wants to play again). the way I have learned is to use the CollideRect function for every rectangle. (c.colliderect(r)). where c = cube (x, y) and r(1,2,3,etc.) = for each rectangle. but this way is very tedious because there are many rectangles used.
is there a simpler and much more efficient way to accomplish my goal?
I wanted to use color as the defining variable (if red == black -> gameover() in a sense) but I cannot find a way to accomplish this.
I also tried by defining the rectangles or putting them all under one class as well.
please let me know if there is a way to do this!
here is my code:
import pygame
import time
black = (0, 0, 0)
white = (255, 255, 255)
red = (255, 0, 0)
green = (0, 255, 0)
pygame.init()
size = (610, 410)
screen = pygame.display.set_mode(size)
pygame.display.set_caption("Maze Game")
screen.fill(white)
pygame.display.flip()
x = 20
y = 360
x_speed = 0
y_speed = 0
def cube(x, y):
c = pygame.Rect(x + x_speed, y + y_speed, 30, 30)
pygame.draw.rect(screen, red,[x + x_speed, y + y_speed, 30, 30])
return c
def rectangles():
#pygame.Rect([0, 0, 610, 410], 10)
#border wasnt working as one of these but works further down#
pygame.Rect(50, 60, 50, 340)
pygame.Rect(100, 60, 50, 50)
pygame.Rect(200, 10, 50, 300)
pygame.Rect(250, 10, 50, 50)
pygame.Rect(150, 150, 50, 200)
pygame.Rect(300, 100, 50, 50)
pygame.Rect(200, 300, 100, 50)
pygame.Rect(350, 60, 50, 340)
pygame.Rect(250, 200, 50, 100)
pygame.Rect(450, 10, 50, 340)
pygame.Rect(550, 60, 50, 340)
def gameover():
font = pygame.font.SysFont(None, 55)
text = font.render("Game Over! Play Again? (y or n)", True, green)
screen.blit(text, [20, 250])
pygame.display.flip()
done = False
while (done == False):
for event in pygame.event.get():
if (event.type == pygame.QUIT):
pygame.quit()
elif(event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE):
pygame.quit()
if(event.type == pygame.KEYDOWN):
if(event.key == pygame.K_y):
board1()
if(event.type == pygame.KEYDOWN):
if (event.key == pygame.K_n):
pygame.quit()
def board1():
x = 15
y = 360
x_speed = 0
y_speed = 0
done = False
while (not done):
for event in pygame.event.get():
if (event.type == pygame.QUIT):
pygame.quit()
elif(event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE):
pygame.quit()
if(event.type == pygame.KEYDOWN):
if(event.key == pygame.K_UP):
y_speed = -.1
if(event.key == pygame.K_DOWN):
y_speed = .1
if(event.key == pygame.K_LEFT):
x_speed = -.1
if(event.key == pygame.K_RIGHT):
x_speed = .1
if(event.type == pygame.KEYUP):
if (event.key == pygame.K_UP):
y_speed = 0
if (event.key == pygame.K_DOWN):
y_speed = 0
if (event.key == pygame.K_LEFT):
x_speed = 0
if (event.key == pygame.K_RIGHT):
x_speed = 0
screen.fill(white)
c = cube(x, y)
r = rectangles()
pygame.draw.rect(screen, black, [0, 0, 610, 410], 10)
pygame.draw.rect(screen, black, [50, 60, 50, 340])
pygame.draw.rect(screen, black, [100, 60, 50, 50])
pygame.draw.rect(screen, black, [200, 10, 50, 300])
pygame.draw.rect(screen, black, [250, 10, 50, 50])
pygame.draw.rect(screen, black, [150, 150, 50, 200])
pygame.draw.rect(screen, black, [300, 100, 50, 50])
pygame.draw.rect(screen, black, [200, 300, 100, 50])
pygame.draw.rect(screen, black, [350, 60, 50, 340])
pygame.draw.rect(screen, black, [250, 200, 50, 100])
pygame.draw.rect(screen, black, [450, 10, 50, 340])
pygame.draw.rect(screen, black, [550, 60, 50, 340])
pygame.display.flip()
x = x + x_speed
y = y + y_speed
if(c.colliderect(r)):
gameover()
board1()
Well if you just need to check whether any of the rectangles have collided with the player then you can simply add them all to a list and go through that list checking each one for a collision.
Something like this should work:
import pygame
import time
black = (0, 0, 0)
white = (255, 255, 255)
red = (255, 0, 0)
green = (0, 255, 0)
pygame.init()
size = (610, 410)
screen = pygame.display.set_mode(size)
pygame.display.set_caption("Maze Game")
screen.fill(white)
pygame.display.flip()
x = 20
y = 360
x_speed = 0
y_speed = 0
def cube(x, y):
c = pygame.Rect(x + x_speed, y + y_speed, 30, 30)
pygame.draw.rect(screen, red,[x + x_speed, y + y_speed, 30, 30])
return c
rects = []
def rectangles():
#pygame.Rect([0, 0, 610, 410], 10)
#border wasnt working as one of these but works further down#
# add them all to a list
rects.append(pygame.Rect(50, 60, 50, 340))
rects.append(pygame.Rect(100, 60, 50, 50))
rects.append(pygame.Rect(200, 10, 50, 300))
rects.append(pygame.Rect(250, 10, 50, 50))
rects.append(pygame.Rect(150, 150, 50, 200))
rects.append(pygame.Rect(300, 100, 50, 50))
rects.append(pygame.Rect(200, 300, 100, 50))
rects.append(pygame.Rect(350, 60, 50, 340))
rects.append(pygame.Rect(250, 200, 50, 100))
rects.append(pygame.Rect(450, 10, 50, 340))
rects.append(pygame.Rect(550, 60, 50, 340))
def gameover():
font = pygame.font.SysFont(None, 55)
text = font.render("Game Over! Play Again? (y or n)", True, green)
screen.blit(text, [20, 250])
pygame.display.flip()
done = False
while (done == False):
for event in pygame.event.get():
if (event.type == pygame.QUIT):
pygame.quit()
elif(event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE):
pygame.quit()
if(event.type == pygame.KEYDOWN):
if(event.key == pygame.K_y):
board1()
if(event.type == pygame.KEYDOWN):
if (event.key == pygame.K_n):
pygame.quit()
def board1():
x = 15
y = 360
x_speed = 0
y_speed = 0
done = False
while (not done):
for event in pygame.event.get():
if (event.type == pygame.QUIT):
pygame.quit()
elif(event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE):
pygame.quit()
if(event.type == pygame.KEYDOWN):
if(event.key == pygame.K_UP):
y_speed = -.1
if(event.key == pygame.K_DOWN):
y_speed = .1
if(event.key == pygame.K_LEFT):
x_speed = -.1
if(event.key == pygame.K_RIGHT):
x_speed = .1
if(event.type == pygame.KEYUP):
if (event.key == pygame.K_UP):
y_speed = 0
if (event.key == pygame.K_DOWN):
y_speed = 0
if (event.key == pygame.K_LEFT):
x_speed = 0
if (event.key == pygame.K_RIGHT):
x_speed = 0
screen.fill(white)
c = cube(x, y)
r = rectangles()
pygame.draw.rect(screen, black, [0, 0, 610, 410], 10)
pygame.draw.rect(screen, black, [50, 60, 50, 340])
pygame.draw.rect(screen, black, [100, 60, 50, 50])
pygame.draw.rect(screen, black, [200, 10, 50, 300])
pygame.draw.rect(screen, black, [250, 10, 50, 50])
pygame.draw.rect(screen, black, [150, 150, 50, 200])
pygame.draw.rect(screen, black, [300, 100, 50, 50])
pygame.draw.rect(screen, black, [200, 300, 100, 50])
pygame.draw.rect(screen, black, [350, 60, 50, 340])
pygame.draw.rect(screen, black, [250, 200, 50, 100])
pygame.draw.rect(screen, black, [450, 10, 50, 340])
pygame.draw.rect(screen, black, [550, 60, 50, 340])
pygame.display.flip()
x = x + x_speed
y = y + y_speed
# Check for each one of the walls
for rect in rects:
if c.colliderect(rect):
print("collision")
gameover()
board1()
However if you do want to detect by colour, its a bit more complex, but you can take a look at this:
Color collision detection in Pygame.
How do I make entities take damage with colors? I made a game with enemies shooting blue lasers and I want the player to take damage. And the player shoots a red laser. Upon detecting colors, I want a certain statement to be true. That would lower an entity's health by one. If color collision is a thing, it can be very useful for making many different games. Here is my code:
# importing packages
import pygame
import random
import time
import sys
# Initializing Pygame
pygame.init()
# Setting a display caption
pygame.display.set_caption("Space Invaders")
spaceship = pygame.image.load("spaceship2.png")
blue_enemy = pygame.image.load("blue_enemy.png")
green_enemy = pygame.image.load("green_enemy.png")
orange_enemy = pygame.image.load("orange_enemy.png")
pink_enemy = pygame.image.load("pink_enemy.png")
yellow_enemy = pygame.image.load("yellow_enemy.png")
# Creating a font
pygame.font.init()
font = pygame.font.SysFont("consolas", 30)
large_font = pygame.font.SysFont("consolas", 60)
small_font = pygame.font.SysFont("consolas", 20)
# Setting a display width and height and then creating it
display_width = 700
display_height = 500
display_size = [display_width, display_height]
game_display = pygame.display.set_mode(display_size)
intro_display = pygame.display.set_mode(display_size)
# Creating a way to add text to the screen
def message(sentence, color, x, y, font_type, display):
sentence = font_type.render(str.encode(sentence), True, color)
display.blit(sentence, [x, y])
def main():
global white
global black
global clock
# Spaceship coordinates
spaceship_x = 300
spaceship_y = 375
spaceship_x_change = 0
blue_enemy_health = 5
green_enemy_health = 5
orange_enemy_health = 5
pink_enemy_health = 5
yellow_enemy_health = 5
# Clock making
# Initializing pygame
pygame.init()
# Creating colors
red = (0, 0, 0)
blue = (0, 0, 255)
# clock stuff
clock = pygame.time.Clock()
time_elapsed_since_last_action = 0
time_elapsed_since_last_action2 = 0
time_elapsed_since_last_action3 = 0
# Creating a loop to keep program running
while True:
laser_rect = pygame.Rect(spaceship_x + 69, 70, 4, 310)
# --- Event Processing and controls
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_RIGHT:
spaceship_x_change = 10
elif event.key == pygame.K_LEFT:
spaceship_x_change = -10
elif event.key == pygame.K_r:
red = (255, 0, 0)
elif time_elapsed_since_last_action2 > 250:
pygame.draw.rect(game_display, red, laser_rect)
time_elapsed_since_last_action2 = 0
elif event.type == pygame.KEYUP:
spaceship_x_change = 0
red = (0, 0, 0)
spaceship_x += spaceship_x_change
# Preventing the ship from going off the screen
if spaceship_x > display_width - 140:
spaceship_x -= 10
if spaceship_x < 1:
spaceship_x += 10
# Setting Display color
game_display.fill(black)
laser_coords = [70, 209, 348, 505, 630]
random_x_coord = random.choice(laser_coords)
dt = clock.tick()
time_elapsed_since_last_action += dt
if time_elapsed_since_last_action > 500:
pygame.draw.rect(game_display, blue, [random_x_coord, 85, 6, 305])
time_elapsed_since_last_action = 0
time_elapsed_since_last_action2 += dt
# Creating a spaceship, lasers, and enemies
game_display.blit(spaceship, (spaceship_x, spaceship_y))
message(str(blue_enemy_health), white, 65, 10, font, game_display)
game_display.blit(blue_enemy, (20, 25))
message(str(green_enemy_health), white, 203, 10, font, game_display)
game_display.blit(green_enemy, (160, 25))
message(str(orange_enemy_health), white, 341, 10, font, game_display)
game_display.blit(orange_enemy, (300, 25))
message(str(pink_enemy_health), white, 496, 10, font, game_display)
game_display.blit(pink_enemy, (440, 25))
message(str(yellow_enemy_health), white, 623, 10, font, game_display)
game_display.blit(yellow_enemy, (580, 25))
health = 10
message("Spaceship durability: " + str(health), white, 20, 480, small_font, game_display)
# Updating Screen so changes take places
pygame.display.update()
# Setting FPS
FPS = pygame.time.Clock()
FPS.tick(60)
black = (0, 0, 0)
white = (255, 255, 255)
gray = (100, 100, 100)
while True:
intro_display.fill(black)
pygame.event.poll()
mouse = pygame.mouse.get_pos()
click = pygame.mouse.get_pressed()
message("Space Bugs", white, 180, 150, large_font, intro_display)
if 150 + 100 > mouse[0] > 150 and 350 + 50 > mouse[1] > 350:
pygame.draw.rect(game_display, gray, [150, 350, 100, 50])
if click[0] == 1:
break
else:
pygame.draw.rect(game_display, white, [150, 350, 100, 50])
if 450 + 100 > mouse[0] > 450 and 350 + 50 > mouse[1] > 350:
pygame.draw.rect(game_display, gray, [450, 350, 100, 50])
if click[0] == 1:
pygame.quit()
quit()
else:
pygame.draw.rect(game_display, white, [450, 350, 100, 50])
message("Start", black, 155, 360, font, intro_display)
message("Quit", black, 465, 360, font, intro_display)
# Go ahead and update the screen with what we've drawn.
pygame.display.update()
# Wrap-up
# Limit to 60 frames per second
clock = pygame.time.Clock()
clock.tick(60)
# Executing the function
if __name__ == "__main__":
main()
No, there is no such a "thing" as a "color collision". What color have the images? Are they uniformly colored? Most likely the pictures are only different in some details. A collision which checks for a uniform color is completely useless. A collision that also looks for a uniform color is almost useless.
If you detect a collision, you know the laser and the enemy. Hence, you know the color with which you represent them. All you have to do is do an additional check after the collision is detected.
Use pygame.sprite.Sprite to implement the objects. Add an attribute that indicates the color of the object:
class ColoredSprite(pygame.sprite.Sprite):
def __init__(self, x, y, image, color):
super().__init__()
self.image = image
self.rect = self.image.get_rect(center = (x, y)
slef.color = color
Manage the spites in pygame.sprite.Groups and use spritecollide to detect the collisions. Check the color attributes when a collision is detected
collide_list = sprite.spritecollide(sprite_group, False):
for other_sprite in collide_list:
if sprite.color == 'red' and other_sprite.color == 'blue':
# [...]
elif sprite.color == 'blue' and other_sprite.color == 'red':
# [...]
It is even possible to implement your own collision detection method and use it in combination with spritecollide by setting the optional collided argument:
def color_collision(sprite1, sprite2):
if sprite1.rect.colliderect(sprite2.rect):
return ((sprite1.color == 'red' and sprite2.color == 'blue') or
(sprite1.color == 'blue' and sprite2.color == 'red'))
return false
collide_list = sprite.spritecollide(sprite_group, False, color_collision):
for other_sprite in collide_list:
# [...]
Minimal example:
import pygame
pygame.init()
window = pygame.display.set_mode((250, 250))
sprite1 = pygame.sprite.Sprite()
sprite1.image = pygame.Surface((75, 75))
sprite1.image.fill('red')
sprite1.rect = pygame.Rect(*window.get_rect().center, 0, 0).inflate(75, 75)
sprite1.color = 'red'
sprite2 = pygame.sprite.Sprite()
sprite2.image = pygame.Surface((75, 75))
sprite2.image.fill('blue')
sprite2.rect = pygame.Rect(*window.get_rect().center, 0, 0).inflate(75, 75)
sprite2.color = 'blue'
all_group = pygame.sprite.Group([sprite2, sprite1])
def color_collision(sprite1, sprite2):
if sprite1.rect.colliderect(sprite2.rect):
return ((sprite1.color == 'red' and sprite2.color == 'blue') or
(sprite1.color == 'blue' and sprite2.color == 'red'))
return False
run = True
while run:
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
sprite1.rect.center = pygame.mouse.get_pos()
collide = pygame.sprite.spritecollide(sprite1, all_group, False, color_collision)
window.fill(0)
all_group.draw(window)
for s in collide:
pygame.draw.rect(window, (255, 255, 255), s.rect, 5, 1)
pygame.display.flip()
pygame.quit()
exit()
I have managed to display my sprite on the screen but am unable to move it. The keys for movement have been set.
I haven't really tried much that has caused anything to change.
import pygame
pygame.init()
window = pygame.display.set_mode((650, 630))
pygame.display.set_caption("PeaShooters")
avatar = pygame.image.load('Sprite 1 Red.png')
background = pygame.image.load('Bg.jpg')
white = (255, 255, 255)
class player(object):
def __init__(self, x, y, width, height):
self.x = 300
self.y = 500
self.width = 40
self.height = 60
self.vel = 9
def drawGrid():
window.blit(background, (0,0))
window.blit(avatar, (300, 500))
pygame.draw.line(window, white, [50,50], [50, 600], 5)
pygame.draw.line(window, white, [50,50], [600, 50], 5)
pygame.draw.line(window, white, [600,600], [600, 50], 5)
pygame.draw.line(window, white, [50,600], [600, 600], 5)
pygame.draw.line(window, white, [50,450], [600, 450], 5)
pygame.display.update()
av = player(300, 500, 40, 60)
running = True
while running:
pygame.time.delay(100)
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
keys = pygame.key.get_pressed()
if keys[pygame.K_w] and av.y > 440:
av.y -= av.vel
if keys[pygame.K_a] and av.x > 65:
av.x -= av.vel
if keys[pygame.K_s] and av.y < 530:
av.y += av.vel
if keys[pygame.K_d] and av.x < 525 :
av.x += av.vel
drawGrid()
window.blit(avatar, (x,y))
pygame.quit()
When I load the game the player should move which it is not doing.
You are updating your player positions inside the key press checks, but not using these values to blit your player in the right place. Try changing this line:
window.blit(avatar, (300, 500))
to
window.blit(avatar, (av.x, av.y))
I made a game in pygame which involves main menu, game loop, victory screen and crash screen. My game works how I want it to work, but I know everytime I change a screen, I am just going deeper into the loop and game can crash when i reach 1000 recursions (I think so?)). I don't know how to fix it, so if you could please Help me.
Here is the code:
import pygame
import sys
pygame.init()
pygame.display.set_caption("My Game")
screen_width, screen_height = 1200, 600
screen = pygame.display.set_mode((screen_width, screen_height))
clock = pygame.time.Clock()
BLUE = pygame.Color('dodgerblue3')
ORANGE = pygame.Color('sienna3')
BLACK = (0, 0, 0)
WHITE = (255,255,255)
RED = (255, 0, 0)
GREEN = (13, 255, 0)
YELLOW = (0, 255, 20)
BRIGHT_YELLOW = (255, 255, 20)
font = pygame.font.Font(None, 25)
frame_rate = 60
last_seconds = None
class Walls(pygame.Rect):
def __init__(self, x, y, w, h):
super().__init__(x, y, w, h)
class LeftRedRect(pygame.Rect):
def __init__(self, x, y, w, h, vel):
# Calling the __init__ method of the parent class
super().__init__(x, y, w, h)
self.vel = vel
def update(self):
self.x += self.vel # Moving
if self.right > 600 or self.left < 320: # If it's not in this area
self.vel = -self.vel # Inverting the direction
class RightRedRect(pygame.Rect):
def __init__(self, x, y, w, h, vel):
super().__init__(x, y, w, h)
self.vel = vel
def update(self):
self.x += self.vel
if self.right > 1180 or self.left < 620:
self.vel = -self.vel
class UpAndDownRedRect(pygame.Rect):
def __init__(self, x, y, w, h, vel):
super().__init__(x, y, w, h)
self.vel = vel
def update(self):
self.y += self.vel
if self.top < 20 or self.bottom > 535:
self.vel = -self.vel
def quit_game():
pygame.quit()
sys.exit()
def message_display(text):
largeText = pygame.font.Font(None, 115)
screen.blit(largeText.render(text, True, BLUE), (370, 250))
pygame.display.update()
pygame.time.wait(1500)
def text_objects(text, font):
textSurface = font.render(text, True, BLACK)
return textSurface, textSurface.get_rect()
def button(msg, x, y, w, h, ic, ac, action = None):
mouse = pygame.mouse.get_pos()
click = pygame.mouse.get_pressed()
if x + w > mouse[0] > x and y + h > mouse[1] > y:
pygame.draw.rect(screen, ac, (x, y, w, h))
if click[0] == 1 and action is not None:
action()
else:
pygame.draw.rect(screen, ic, (x, y, w, h))
smallText = pygame.font.Font("freesansbold.ttf",35)
textSurf, textRect = text_objects(msg, smallText)
textRect.center = ((x+(w/2)), (y+(h/2)))
screen.blit(textSurf, textRect)
def restart():
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
quit_game()
screen.fill(WHITE)
largeText = pygame.font.Font(None, 115)
screen.blit(largeText.render("You lost", True, BLUE), (420, 50))
button("Restart", 525, 250, 150, 60, BRIGHT_YELLOW, YELLOW, menu)
button("Quit", 525, 350, 150, 60, BRIGHT_YELLOW, YELLOW, quit_game)
pygame.display.update()
pygame.display.flip()
clock.tick(60)
def victory_screen():
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
quit_game()
screen.fill(WHITE)
#TO DO: POSITION THE TEXT#
largeText = pygame.font.Font(None, 115)
screen.blit(largeText.render("Congratulations!", True, BLUE), (300, 50))
largeText = pygame.font.Font(None, 60)
screen.blit(largeText.render("You beat the game!", True, BLUE), (400, 150))
button("Restart", 525, 250, 150, 60, BRIGHT_YELLOW, YELLOW, menu)
button("Quit", 525, 350, 150, 60, BRIGHT_YELLOW, YELLOW, quit_game)
pygame.display.update()
pygame.display.flip()
clock.tick(frame_rate)
def front_page():
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
quit_game()
screen.fill(WHITE)
largeText = pygame.font.Font(None, 115)
screen.blit(largeText.render("My Game", True, BLUE), (430, 50))
button("Start", 525, 250, 150, 60, BRIGHT_YELLOW, YELLOW, menu)
button("Quit", 525, 350, 150, 60, BRIGHT_YELLOW, YELLOW, quit_game)
pygame.display.update()
pygame.display.flip()
clock.tick(frame_rate)
def menu():
vel = 4
vel_left = 5
vel_right = -5
vel_up = 7
player = pygame.Rect(40, 45, 30, 30)
finish_line = pygame.Rect(620, 535, 560, 45)
walls = [
Walls(0, 0, 1200, 20), Walls(0, 0, 20, 600),
Walls(0, 580, 1200, 20), Walls(1180, 0, 20, 600),
Walls(300, 0, 20, 530), Walls(20, 100, 230, 20),
Walls(70, 200, 230, 20), Walls(20, 300, 230, 20),
Walls(70, 400, 230, 20), Walls(600, 100, 20, 500)
]
leftredrects = [
LeftRedRect(320, 120, 30, 30, vel_left),
LeftRedRect(320, 240, 30, 30, vel_left),
LeftRedRect(320, 360, 30, 30, vel_left),
LeftRedRect(570, 180, 30, 30, vel_right),
LeftRedRect(570, 300, 30, 30, vel_right),
LeftRedRect(570, 420, 30, 30, vel_right)
]
rightredrects = [
RightRedRect(1140, 120, 30, 30, vel_left),
RightRedRect(1140, 240, 30, 30, vel_left),
RightRedRect(1140, 360, 30, 30, vel_left),
RightRedRect(620, 180, 30, 30, vel_right),
RightRedRect(620, 300, 30, 30, vel_right),
RightRedRect(620, 420, 30, 30, vel_right),
]
upanddownredrects = [
UpAndDownRedRect(620, 20, 30, 30, vel_up),
UpAndDownRedRect(752, 505, 30, 30, vel_up),
UpAndDownRedRect(885, 20, 30, 30, vel_up),
UpAndDownRedRect(1016, 505, 30, 30, vel_up),
UpAndDownRedRect(1150, 20, 30, 30, vel_up)
]
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
quit_game()
keys = pygame.key.get_pressed()
# Player coordinates
if keys[pygame.K_LEFT] and player.x > 0:
player.x -= vel
if keys[pygame.K_RIGHT] and player.x < 1200 - player.width:
player.x += vel
if keys[pygame.K_UP] and player.y > 0:
player.y -= vel
if keys[pygame.K_DOWN] and player.y < 600 - player.height:
player.y += vel
# Game logic
for wall in walls:
# Check if the player rectangle collides with a wall rectangle
if player.colliderect(wall):
print("Game over")
# message_display("Game Over")
# restart()
for rect in rightredrects:
rect.update() # Movement and bounds checking
if player.colliderect(rect):
print("Game over")
# message_display("Game Over")
# restart()
for rect in leftredrects:
rect.update()
if player.colliderect(rect):
print("Game over")
# message_display("Game Over")
#restart()
for rect in upanddownredrects:
rect.update()
if player.colliderect(rect):
print("Game over")
#message_display("Game Over")
#restart()
if player.colliderect(finish_line):
print("You beat the game")
victory_screen()
# Drawing everything
screen.fill(WHITE)
pygame.draw.rect(screen, BRIGHT_YELLOW, finish_line)
for wall in walls:
pygame.draw.rect(screen, BLACK, wall)
for rect in rightredrects:
pygame.draw.rect(screen, RED, rect)
for rect in leftredrects:
pygame.draw.rect(screen, RED, rect)
for rect in upanddownredrects:
pygame.draw.rect(screen, RED, rect)
pygame.draw.rect(screen, GREEN, player)
pygame.display.update()
pygame.display.flip()
clock.tick(frame_rate)
def main():
scene = front_page # Set the current scene.
while scene is not None:
# Execute the current scene function. When it's done
# it returns either the next scene or None which we
# assign to the scene variable.
scene = scene()
main()
pygame.quit()
You could add a next_scene variable to your scene and set it to the next scene function when the button gets pressed. In the while loop you would have to check if next_scene is not None: and then return the next_scene to the main function where it will be called. It would be necessary to define nested callback functions to change the next_scene variable.
def front_page():
next_scene = None
def start_game():
nonlocal next_scene
# Set the `next_scene` variable in the enclosing scope
# to the `menu` function.
next_scene = menu
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
quit_game()
# Return the next scene to the `main` function if the variable is not None.
if next_scene is not None:
return next_scene
screen.fill(WHITE)
button("Start", 525, 250, 150, 60, BRIGHT_YELLOW, YELLOW, start_game)
button("Quit", 525, 350, 150, 60, BRIGHT_YELLOW, YELLOW, quit_game)
pygame.display.flip() # Don't call both display.update and display.flip.
clock.tick(60)
In the menu function you can just return the restart function when the player touches a wall or a moving rect:
for wall in walls:
# Check if the player rectangle collides with a wall rectangle
if player.colliderect(wall):
print("Game over")
return restart
for every place where you print('Game over') return True like i did in this part of your code:
for wall in walls:
# Check if the player rectangle collides with a wall rectangle
if player.colliderect(wall):
print("Game over")
return True
if you dont the game is still in the while loop and it will print "game over" until you can cook eggs on your computer or it crashes.
So I want to make a basic 2d game where you control a rectangle and if you touch a wall you die. I've created some walls Picture
but I am stuck now. I really don't know how does the code should look like even though I looked at the documentation. And second thing is that I am not sure how to create "Sprite". How do I make my rectangle as "Sprite" or it doesn't matter and it can stay just a normal rectangle that moves?
import pygame
pygame.init()
win = pygame.display.set_mode((1200, 600))
pygame.display.set_caption("My Game")
x = 40
y = 45
width = 30
height = 30
vel = 4
black = (0,0,0)
run = True
while run:
pygame.time.delay(15)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
win.fill((255,255,255))
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT] and x > 0:
x -= vel
if keys[pygame.K_RIGHT] and x < 1200 - width:
x += vel
if keys[pygame.K_UP] and y > 0:
y -= vel
if keys[pygame.K_DOWN] and y < 600 - height:
y += vel
pygame.draw.rect(win, (255, 0, 0), (x, y, width, height))
# Boundaries
pygame.draw.rect(win, (black), (0, 0, 1200, 20))
pygame.draw.rect(win, (black), (0, 0, 20, 600))
pygame.draw.rect(win, (black), (0, 580, 1200, 20))
pygame.draw.rect(win, (black), (1180, 0, 20, 600))
# Obstacle walls
pygame.draw.rect(win, (black), (300, 0, 20, 530))
pygame.draw.rect(win, (black), (20, 100, 230, 20))
pygame.draw.rect(win, (black), (70, 200, 230, 20))
pygame.draw.rect(win, (black), (20, 300, 230, 20))
pygame.draw.rect(win, (black), (70, 400, 230, 20))
# Middle Wall
pygame.draw.rect(win, (black), (600, 100, 20, 500))
pygame.display.update()
pygame.quit()
You don't need pygame sprites and sprite groups for the collision detection, you can just use pygame.Rects. I'd put all walls into a list and make them pygame.Rect objects, then it's possible to use the colliderect of the rects for the collisions. You also need a rect for the player (just replace the x, y, width, height variables with a rect). Iterate over the walls list with for loops to check if one collides with the player rect and also to draw them.
import pygame
pygame.init()
win = pygame.display.set_mode((1200, 600))
clock = pygame.time.Clock() # A clock to limit the frame rate.
BLACK = (0, 0, 0)
WHITE = (255,255,255)
RED = (255, 0, 0)
# The player variables have been replaced by a pygame.Rect.
player = pygame.Rect(40, 45, 30, 30)
vel = 4
# The walls are now pygame.Rects as well. Just put them into a list.
walls = [
pygame.Rect(0, 0, 1200, 20), pygame.Rect(0, 0, 20, 600),
pygame.Rect(0, 580, 1200, 20), pygame.Rect(1180, 0, 20, 600),
pygame.Rect(300, 0, 20, 530), pygame.Rect(20, 100, 230, 20),
pygame.Rect(70, 200, 230, 20), pygame.Rect(20, 300, 230, 20),
pygame.Rect(70, 400, 230, 20), pygame.Rect(600, 100, 20, 500),
]
run = True
while run:
# Handle the events.
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
keys = pygame.key.get_pressed()
# Update the player coordinates.
if keys[pygame.K_LEFT] and player.x > 0:
player.x -= vel
if keys[pygame.K_RIGHT] and player.x < 1200 - player.width:
player.x += vel
if keys[pygame.K_UP] and player.y > 0:
player.y -= vel
if keys[pygame.K_DOWN] and player.y < 600 - player.height:
player.y += vel
# Game logic.
for wall in walls:
# Check if the player rect collides with a wall rect.
if player.colliderect(wall):
print('Game over')
# Then quit or restart.
# Draw everything.
win.fill(WHITE)
pygame.draw.rect(win, RED, player)
# Use a for loop to draw the wall rects.
for wall in walls:
pygame.draw.rect(win, BLACK, wall)
pygame.display.update()
clock.tick(60) # Limit the frame rate to 60 FPS.
pygame.quit()