Related
I'm trying to make a flappy bird AI using OOP, so far everything seem to be working fine except for two problems. First my bird is flapping way to quickly. I created a user event and in the timer I put 200 milliseconds:
birdflap = pygame.USEREVENT
pygame.time.set_timer(birdflap, 200)
but for some reason, the wings are still flapping like crazy and I can't seem to understand what's causing it to do so. Secondly I had a problem with the bird rotating when it falls down. I made a function in my bird class called 'move' that creates gravity for the bird and causes it to turn using rotozoom in pygame to make it turn as it falls down.
def move(self):
self.bird_movement = 8
self.bird_movement += self.gravity
self.bird_rect.centery += self.bird_movement
pygame.transform.rotozoom(self.img[self.bird_index], -self.bird_movement * 3, 1)
The problem is that once the game starts, it falls but doesn't turn. I honestly don't know where to start with solving both of these issues. My full code is down below if anybody wanted to see what I have so far.
import pygame
import neat
import time
import os
import random
import sys
pygame.init()
clock = pygame.time.Clock()
# VARIABLES THAT DEFINE SCREEN SIZE
screen_width = 500
screen_height = 800
# CLOCK TO SET FRAME RATE
clock = pygame.time.Clock()
# VARIABLES THAT CONTAIN GAME IMAGES
bird_imgs = [pygame.transform.scale2x(pygame.image.load(os.path.join('assets', 'yellowbird-upflap.png'))), pygame.transform.scale2x(pygame.image.load(
os.path.join('assets', 'yellowbird-midflap.png'))), pygame.transform.scale2x(pygame.image.load(os.path.join('assets', 'yellowbird-downflap.png')))]
bg_img = pygame.transform.scale2x(pygame.image.load(os.path.join('assets', 'background-day.png' )))
# TIMER FOR BIRD FLAP IMAGES
birdflap = pygame.USEREVENT
pygame.time.set_timer(birdflap, 200)
class Bird:
img = bird_imgs
gravity = 0.25
def __init__(self, x, y):
self.x = x
self.y = y
self.bird_movement = 0
self.bird_index = 0
self.bird_rect = self.img[self.bird_index].get_rect(center = (self.x, self.y))
def bird_animation(self, win):
if self.bird_index < 2:
self.bird_index += 1
else:
self.bird_index = 0
win.blit(self.img[self.bird_index], self.bird_rect)
def move(self):
self.bird_movement = 8
self.bird_movement += self.gravity
self.bird_rect.centery += self.bird_movement
pygame.transform.rotozoom(self.img[self.bird_index], -self.bird_movement * 3, 1)
# FUNCTION TO DRAW THE WINDOW
def draw_window(win, bird):
win.blit(bg_img, (0,0))
bird.bird_animation(win)
pygame.display.update()
# MAIN FUNCTION OF OUR GAME
def main():
win = pygame.display.set_mode((screen_width, screen_height))
bird = Bird(200, 200)
run = True
while run:
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
if event.type == birdflap:
bird.bird_animation(win)
bird.move()
draw_window(win, bird)
clock.tick(60)
pygame.quit()
sys.exit()
main()
I tried using other modules in pygame, but that doesn't seem to solve my issue either. Right now I'm really lost.
The 1st problem is that bird_animation is called in draw_window so the bird is animated all over the time. The 2nd problem is that pygame.transform.rotozoom returns a new but rotated surface (see How do I rotate an image around its center using PyGame?). The method move has to create an image, that is used in an draw method:
class Bird:
img = bird_imgs
gravity = 0.25
def __init__(self, x, y):
self.x = x
self.y = y
self.bird_movement = 0
self.bird_index = 0
self.image = self.img[self.bird_index]
self.rect = self.image.get_rect(center = (self.x, self.y))
def bird_animation(self):
if self.bird_index < 2:
self.bird_index += 1
else:
self.bird_index = 0
def move(self):
self.bird_movement = 8
self.bird_movement += self.gravity
self.y += self.bird_movement
self.image = pygame.transform.rotozoom(self.img[self.bird_index], -self.bird_movement * 3, 1)
self.rect = self.image.get_rect(center = (self.x, self.y))
def draw(self, win)
win.blit(self.img[self.bird_index], self.bird_rect)
# FUNCTION TO DRAW THE WINDOW
def draw_window(win, bird):
win.blit(bg_img, (0,0))
bird.draw(win)
pygame.display.update()
def main():
win = pygame.display.set_mode((screen_width, screen_height))
bird = Bird(200, 200)
run = True
while run:
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
if event.type == birdflap:
bird.bird_animation()
bird.move()
draw_window(win, bird)
clock.tick(60)
pygame.quit()
sys.exit()
main()
This is the image Okay so I am not able to figure out how to delete the previous render of the object every frame from screen so as to not leave a trail behind, in other words I want the object to have the appearance of Movement rather than leaving a bunch of red squares behind it. Image has been inserted for understanding what I mean by "leaving a trail" The following is my code:-
import pygame
import random
WIDTH = 1000
ROWS = 25
WIN = pygame.display.set_mode((WIDTH,WIDTH))
pygame.display.set_caption("Particle Physics")
clock = pygame.time.Clock()
RED = (255, 0, 0)
GRAVITY = 2
wid = 5
class Square:
def __init__(self,x,y,width,color,vel_x,vel_y):
self.x = x
self.y = y
self.width = width
self.color = color
self.velx = vel_x
self.vely = vel_y
def draw(self):
pygame.draw.rect(WIN, self.color, (self.x, self.y, self.width, self.width))
def move(self):
self.x += self.velx
self.y += self.vely
self.vely += GRAVITY[enter image description here][1]
def particles():
pass
def main():
run = True
a,b = 500,300
c = random.randint(-20,20)
d = random.randint(-50,0)
square = Square(a,b,wid, RED, c, d)
while run:
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
square.move()
square.draw()
pygame.display.update()
pygame.time.delay(100)
#clock.tick(60)
pygame.quit()
main()
In the main function add the set background color at the start so as to delete the previous frames.
def main()
...
while run
....
screen.fill((255,255,255))
...
I know this question has been asked multiple times but I just cant wrap my head around the concept of collisions, now I know I am asking a lot but I will appreciate it greatly!, All I ask is someone to add collisions to my game and explain each step so I can try to understand whats going on,I tried youtube videos and they aren't explained very well or I just get overwhelmed which is what I feel right now, So I just want the player to stop when hitting the tree, something as simple as that! And if possible I want it to get the collision from a list for example I would have trees and other images in the list.
import pygame
import sys
import math
from pygame.locals import *
import tiles_list
pygame.init()
display_w = 800
display_h = 600
window = pygame.display.set_mode((display_w, display_h), HWSURFACE | DOUBLEBUF | RESIZABLE)
pygame.display.set_icon(pygame.image.load("game_icon.png"))
pygame.display.set_caption("Work in progress")
clock = pygame.time.Clock()
background = pygame.image.load("background.png")
class Player(object):
"""The controllable player in game"""
def __init__(self, x, y, width, height, speed):
self.x = x
self.y = y
self.width = width
self.height = height
self.image = pygame.image.load("sprite_sheet.png")
self.speed = speed
self.timer = 0
self.frames = 1
self.direction = 2
def animation(self):
x_coord = 50 * self.frames
y_coord = 50 * self.direction
self.character = self.image.subsurface(x_coord, y_coord, self.width, self.height)
self.timer += 0
if self.timer >= 10:
self.timer = 0
self.frames += 1
if self.frames >= 9:
self.frames = 1
def draw(self):
window.blit(self.character, (self.x, self.y))
self.rect = pygame.Rect(self.x, self.y, self.width, self.height)
def movement(self):
self.keys = pygame.key.get_pressed()
if self.keys[pygame.K_LEFT] or self.keys[pygame.K_a]:
self.x -= self.speed
self.direction = 1
self.timer += 2
if self.keys[pygame.K_RIGHT] or self.keys[pygame.K_d]:
self.x += self.speed
self.direction = 3
self.timer += 2
if self.keys[pygame.K_UP] or self.keys[pygame.K_w]:
self.y -= self.speed
self.direction = 0
self.timer += 2
if self.keys[pygame.K_DOWN] or self.keys[pygame.K_s]:
self.y += self.speed
self.direction = 2
self.timer += 2
if self.x >= 780:
self.x = 780
self.frames = 0
if self.y >= 555:
self.y = 555
self.frames = 0
if self.x <= 0:
self.x = 0
self.frames = 0
if self.y <= 0:
self.y = 0
self.frames = 0
player = Player(400, 300, 50, 50, 4.5)
class Tree:
def __init__(self, x, y, width, height):
self.x = x
self.y = y
self.width = width
self.height = height
self.image = (
pygame.transform.scale(tiles_list.tiles.subsurface(pygame.Rect(99, 147, self.width, self.height)),
(62, 82)))
def draw(self):
window.blit(self.image, (self.x, self.y))
tree = Tree(348, 300, 42, 62)
running = True
while running:
window.blit(background, (0, 0))
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
if event.type == VIDEORESIZE:
screen = pygame.display.set_mode((event.w, event.h), RESIZABLE)
elif event.type == pygame.KEYUP:
if player.keys:
player.frames = 0
dist_x = math.hypot(tree.x - player.x)
dist_y = math.hypot(tree.y - player.y) # Does nothing except calculate the distence
print("distx", dist_x, "disty", dist_y)
tree.draw()
player.movement()
player.animation()
player.draw()
clock.tick(60)
pygame.display.flip()
Fist of all I suggest that you start to try to implement the collision test, before you ask a question. If you get stuck, you can ask a question about the code that gets you stuck.
Anyway I'll give you some hints.
In common the collision detection is based on pygame.Rect. For instance create a rectangle from pygaem.Surface objects player.image and tree.image by get_rect(). Evaluate if the 2 objects are colliding by colliderect():
player_rect = player.image.get_rect(topleft = (player.x, player.y))
tree_rect = tree.image.get_rect(topleft = (tree.x, tree.y))
if player_rect.colliderect(tree_rect):
print("hit")
If you "just want the player to stop when hitting the tree", the store the position of the player and move the player. After that evaluate if the player hits the tree. If the player is hitting, then restore the position:
while running:
# [...]
# store position of player
player_pos = (player.x, player.y)
# move player
player.movement()
player_rect = player.image.get_rect(topleft = (player.x, player.y))
tree_rect = tree.image.get_rect(topleft = (tree.x, tree.y))
# test collision of player and tree
if player_rect.colliderect(tree_rect):
# restore player position
(player.x, player.y) = player_pos
See also How to detect collisions between two rectangular objects or images in pygame
I am willing to explain you the process of collisions.
In your game you have two objects - the tree and the player. So, you can say that if the x and y coordinates of the player are the same , then there occurs a collisions. You can use this concept and create variables for detecting collisions.
Thanks
I am trying to create a game using pygame for a school project. I would like obstacles(in this case boxes) which get in the way of the player. The player is able to destroy the boxes which would result in another box to be spawned in a random location at the same height.
I've split the code into 3 seperate modules seperating the sprites, the main code and the settings(game variables).
main:
import pygame as pg
import random
from sprites import *
from settings import *
import os
import sys
import time
class Game:
def __init__(init):#initialising the games properties(window,sound,speed,etc).
pg.init()
pg.mixer.init()
init.clock = pg.time.Clock()
init.screen = pg.display.set_mode((WIDTH,HEIGHT))
pg.display.set_caption(TITLE)
init.clock = pg.time.Clock()
init.running = True
init.font_name = pg.font.match_font(FONT_NAME)
init.data()
def data(load):
load.dir = os.path.dirname(__file__)
def new(new):#starts the game again.
new.score = 0
new.obstacles = pg.sprite.Group()
new.platforms = pg.sprite.Group()
new.bullets = pg.sprite.Group()
new.all_sprites = pg.sprite.Group()
new.player = Player(new)
new.all_sprites.add(new.player)
for plat in PLATFORM_LIST:
p = Platform(*plat)
new.all_sprites.add(p)
new.platforms.add(p)
for obs in OBSTACLE_LIST:
new.obstacle = Obstacle(*obs)
new.all_sprites.add(new.obstacle)
new.obstacles.add(new.obstacle)
new.run()
def run(run):
run.playing = True
while run.playing:
run.cooldown = 0
run.clock.tick(FPS)
run.events()
run.update()
run.draw()
def update(update):
bullet = Bullet
#game update.
update.all_sprites.update()
#spawning obstacles lower half
while len(update.obstacles) < 3:
width = random.randrange(50, 100)
update.obstacle = Obstacle(random.randrange(0, WIDTH - width),HEIGHT-100,100,50)
update.obstacles.add(update.obstacle)
update.all_sprites.add(update.obstacle)
#spawning obstacles randomly throughout the middle half
#spawning obstacles randomly throughout the map upper half
#check if bullet collides with an obstacles.
collide = pg.sprite.groupcollide(update.bullets,update.obstacles,True,False)
if collide:
update.obstacle.obs_health = update.obstacle.obs_health - bullet.damage
if update.obstacle.obs_health == 0:
update.obstacle.kill()
#check if player hits the sides of an obstacle.
if update.player.velocity.x >0:#when moving right.
collide = pg.sprite.spritecollide(update.player,update.obstacles,False)
if collide:
if update.player.pos.y >= collide[0].rect.centery+20:#if the player is above the platform.
update.player.pos.x = collide[0].rect.left - (PLAYER_WIDTH/2)
update.player.velocity.x = 0
update.player.acceleration.y = 0
if update.player.velocity.x <0:#when moving left.
collide = pg.sprite.spritecollide(update.player,update.obstacles,False)
if collide:
if update.player.pos.y >= collide[0].rect.centery:
update.player.pos.x = collide[0].rect.right + (PLAYER_WIDTH/2)
update.player.velocity.x = 0
#check if player hits side of platforms
if update.player.velocity.x >0 and (update.player.velocity.y < 0):#when moving right.
collide = pg.sprite.spritecollide(update.player,update.platforms,False)
if collide:
if update.player.pos.y < collide[0].rect.centery+50:#if the player is below the obstacle.
update.player.pos.x = collide[0].rect.left - (PLAYER_WIDTH/2)
update.player.velocity.x = 0
if update.player.velocity.x <0:#when moving left.
collide = pg.sprite.spritecollide(update.player,update.obstacles,False)
if collide:
if update.player.pos.y > collide[0].rect.centery:
update.player.pos.x = collide[0].rect.right + (PLAYER_WIDTH/2)
update.player.velocity.x = 0
#check if player hits a platform while ascending:
if update.player.velocity.y <0:#only when moving up.
collide = pg.sprite.spritecollide(update.player,update.platforms,False)
if collide:
if update.player.pos.y > collide[0].rect.bottom:
update.player.pos.y = collide[0].rect.bottom + (PLAYER_HEIGHT/2) + PLAYER_JUMP
update.player.velocity.y = 0
#check if a player hits a platform while falling.
if update.player.velocity.y >0:#only while falling will this apply.
collide = pg.sprite.spritecollide(update.player,update.platforms,False)#false allows you to avoid deleting the object you jump into.
if collide:
if update.player.pos.y < collide[0].rect.centery:#if the player is above the center of the platform.
update.player.pos.y = collide[0].rect.top +1
update.player.velocity.y = 0
collide = pg.sprite.spritecollide(update.player,update.obstacles,False)
if collide:
if update.player.pos.y < collide[0].rect.centery:
update.player.pos.y = collide[0].rect.top +1
update.player.velocity.y = 0
#spawning obstacles randomly throughout the map upper half
#spawning obstacles randomly throughout the middle half
def events(events):
events.cooldown += events.clock.get_time()
#processes inputs.
for event in pg.event.get():
#check for window closing.
if event.type == pg.QUIT:#if the 'x' button is clicked
if events.playing:
events.playing = False#stop the game loop.
events.running = False#stop the main loop.
if event.type == pg.KEYDOWN:
if event.key == pg.K_UP:
events.player.jump()
if event.key == pg.K_SPACE:
events.player.bullet_list.append(events.player.shoot())
#print(len(events.player.bullet_list))
def draw(draw):
draw.screen.fill(GREY)# creates a black screen.
draw.draw_text(str(draw.player.PLAYER_HEALTH),24,BLACK,WIDTH/32,HEIGHT /32)
draw.all_sprites.draw(draw.screen)#draws the sprites in the group all_sprites.
#after drawing the screen is flipped.
pg.display.flip()
def start_screen(start):#screen displayed when the game is started.
start.screen.fill(BGCOLOR)
start.draw_text(TITLE,48,WHITE,WIDTH/2,HEIGHT /4)
start.draw_text("Arrows to move,UP to jump", 22,WHITE,WIDTH/2,HEIGHT/2)
start.draw_text("Press a key to play",22,WHITE,WIDTH/2,HEIGHT*3/4)
pg.display.flip()
start.any_key()#temporary key to start system.
def any_key(wait):
waiting = True
while waiting:#a loop is used for the start screen until an action is done.
wait.clock.tick(FPS)#allows animations to
for event in pg.event.get():
if event.type == pg.QUIT:#if the 'x' button is pressed during the start screen.
waiting = False
wait.running = False#stops the main loop.
if event.type == pg.KEYUP:#if any key is released.
waiting = False
def over_screen(over):#displayed when the game ends.
if not over.running:
return#skips the over screen when 'x' button is pressed.
over.screen.fill(BGCOLOR)
over.draw_text('GAME OVER',48,WHITE,WIDTH/2,HEIGHT /4)
def draw_text(self, text, size, color, x, y):
font = pg.font.Font(self.font_name, size)#selects the chosen font.
text_surface = font.render(text, True, color)#creates the text with anti aliasing and the color chosen.
text_rect = text_surface.get_rect()
text_rect.midtop = (x, y)#position of text.
self.screen.blit(text_surface, text_rect)#renders text on screen.
g = Game()
g.start_screen()
while g.running:#the main loop.
g.new()
g.over_screen()
pg.quit()#closes the window.
sprites:
#Sprite class
import random
import pygame as pg
from settings import *
vec = pg.math.Vector2 #creates a 2D Vector which stores the x an y cordinates for the sprites.
class Player(pg.sprite.Sprite):
def __init__(self, game):#create initialise the properties of the sprite.
self.game = game#reference to variable in game class.
pg.sprite.Sprite.__init__(self)#provides functions for the sprite in other functions.
self.image = pg.Surface((PLAYER_WIDTH,PLAYER_HEIGHT))#creates a square for the Player to be used as a hitbox.
self.image.fill(GREEN)#place holder for the player.
self.rect = self.image.get_rect()
self.rect.center = (WIDTH/2),(HEIGHT/4)# allows you to move the character.
self.pos = vec(WIDTH/2,HEIGHT/2)#the center of the sprite.
self.velocity = vec(0,0)#the speed of the player.
self.acceleration = vec(0,0)#allows for the change in speed.
self.facing = 0 #direction the player is looking.
self.current = 0#current direction facing.
self.PLAYER_HEALTH = 1000
self.bullet_list = []
def jump(self):
hits = pg.sprite.spritecollide(self, self.game.platforms, False)
if hits:#only able to jump when colliding with platform.
self.velocity.y += -PLAYER_JUMP
collide = hits = pg.sprite.spritecollide(self, self.game.obstacles, False)
if collide:
self.velocity.y += -PLAYER_JUMP
def shoot(self):
#if game.cooldown > 400:
#cooldown = 0
self.bullet = Bullet(self,self.current,self.rect.centerx, self.rect.top)
self.bullet_list.append(self.bullet)
for bullet in self.bullet_list:
#self.bullet = Bullet(self.current,self.rect.centerx, self.rect.top)#creates bullet postioned in center.
self.game.all_sprites.add(self.bullet)
self.game.bullets.add(self.bullet)
#self.bullet = Bullet(self.current,self.rect.centerx, self.rect.top)#creates bullet postioned in center.
#self.game.all_sprites.add(self.bullet)
#self.game.bullets.add(self.bullet)
def update(self):
self.acceleration = vec(0,PLAYER_GRAV)#resets the position of player when not moving.
keys = pg.key.get_pressed()#inputs a pressed key.
if keys[pg.K_LEFT]:
self.acceleration.x = -PLAYER_ACC
self.facing = -1
self.current = self.facing
if keys[pg.K_RIGHT]:
self.acceleration.x = PLAYER_ACC
self.facing = 1
self.current = self.facing
if self.acceleration.x == 0:#if standing, the previous direction is saved
self.facing = self.current
#print(self.current)
#friction.
self.acceleration.x += self.velocity.x * PLAYER_FRICTION
#equation for displacment.
self.velocity += self.acceleration
self.pos += self.velocity + 0.5 * self.acceleration#moves thes players position to the new x,y co-ordinate.
#boundaries of screen.
if self.rect.right > WIDTH:
self.pos.x = WIDTH -(PLAYER_WIDTH * 0.5)#avoids overlapping the boundary.
self.velocity.x = 0 #avoids player sticking to walls by capping speed at boundaries.
self.acceleration.x = 0 #reduces the amount of 'jitter' when trying to move past boundaries.
if self.rect.left < 0 :
self.pos.x = (PLAYER_WIDTH * 0.5)#avoids overlapping the boundary.
# have to add half the player width to avoid player going into walls.
self.velocity.x = 0 #avoids player sticking to walls by stopping player at boundaries.
self.rect.midbottom = self.pos#tracks the position of the players center.
class Platform(pg.sprite.Sprite,):
def __init__(self, x, y, w, h):
pg.sprite.Sprite.__init__(self)
self.image = pg.Surface((w,h))
self.image.fill(BLACK)
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
class Obstacle(pg.sprite.Sprite):
def __init__(self,x,y,w,h):
pg.sprite.Sprite.__init__(self)
self.image = pg.Surface((w,h))
self.image.fill(BLUE)
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
self.obs_health = 100
class Bullet(pg.sprite.Sprite):
damage = 25
def __init__(self,player,current, x, y):
self.player = player#allows the bullet class to use player variables.
pg.sprite.Sprite.__init__(self)
self.image = pg.Surface((20,10))
self.image.fill(LBLUE)
self.rect = self.image.get_rect()
self.rect.right = x
self.rect.centery = y + (PLAYER_HEIGHT/2)
#self.damage = 25
self.velocity = vec(0,0)
if current == -1:#when looking left.
self.velocity = vec(-10,0)
if current == 1:#when looking right.
self.velocity = vec(10,0)
def update(self):
self.rect.right += self.velocity.x
#remove when moves of off screen.
if self.rect.right > WIDTH:
self.kill()
for bullet_amount in self.player.bullet_list:
self.player.bullet_list.pop(self.player.bullet_list.index(bullet_amount))
if self.rect.left <0:
self.kill()
for bullet_amount in self.player.bullet_list:
self.player.bullet_list.pop(self.player.bullet_list.index(bullet_amount))
#print(self.rect.x)
settings:
#settings
TITLE = "downpour"
WIDTH = 900
HEIGHT = 500
FPS = 60
FONT_NAME = 'Ariel'
#platforms
PLATFORM_LIST = [(0, HEIGHT - 50, WIDTH, 50),
(WIDTH -225 ,HEIGHT * 3/4 -50,200, 40),#(x,y,width,height)of the platforms.
(0 +25 ,HEIGHT * 3/4 -50,200, 40),
(0 +350,HEIGHT * 3/4 -150,200, 40)]
OBSTACLE_LIST = [(WIDTH/2,HEIGHT -50-50,100,50),(WIDTH/3,HEIGHT -50-50,100,50),(WIDTH/2,HEIGHT -50-50,100,50)]
#player properties
PLAYER_WIDTH = 50
PLAYER_HEIGHT = 50
PLAYER_ACC = 0.55
PLAYER_FRICTION = -0.05
PLAYER_GRAV = 0.8
PLAYER_JUMP = 15
#colors defines
WHITE = (255,255,255)
BLACK = (0,0,0)
GREY = (211,211,211)
RED = (255,0,0)
GREEN = (0,255,0)
BLUE = (0,0,255)
LBLUE = (132,112,255)
BGCOLOR = LBLUE
The problem I have encountered is with spawning a new box after destroying one of the multiple boxes. A box can be destroyed by depleting its health through shooting at it.
Lets say I have 3 boxes: A,B and C. when I try to destroy B or C, box A is the one that is destroyed and respawned.
I feel like it's an obvious answer...
code relating to the obstacle:
creating the class:
class Obstacle(pg.sprite.Sprite):
def __init__(self,x,y,w,h):
pg.sprite.Sprite.__init__(self)
self.image = pg.Surface((w,h))
self.image.fill(BLUE)
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
self.obs_health = 100
adding it to a Sprite group:
for obs in OBSTACLE_LIST:
new.obstacle = Obstacle(*obs)
new.all_sprites.add(new.obstacle)
new.obstacles.add(new.obstacle)
collisions:
collide = pg.sprite.groupcollide(update.bullets,update.obstacles,True,False)
if collide:
update.obstacle.obs_health = update.obstacle.obs_health - bullet.damage
if update.obstacle.obs_health == 0:
update.obstacle.kill()
spawning a new obstacle:
while len(update.obstacles) < 3:
width = random.randrange(50, 100)
update.obstacle = Obstacle(random.randrange(0, WIDTH - width),HEIGHT-100,100,50)
update.obstacles.add(update.obstacle)
update.all_sprites.add(update.obstacle)
First of all, for all instance methods, it would help the reader if you used the name self instead of all the custom names you're using such as new or update for the first argument.
After that rewrite, you code will look like follows:
collide = pg.sprite.groupcollide(self.bullets,self.obstacles,True,False)
if collide:
self.obstacle.obs_health = self.obstacle.obs_health - bullet.damage
if self.obstacle.obs_health == 0:
self.obstacle.kill()
Now ask yourself, why does the program know that the self.obstacle is the one that collided? Should self.obstacle even exist? It looks like self.obstacle was just used a temporary local variable upon creation of the Game class to add Obstacle's to self.obstacles.
If so just use a local variable as follows:
for obs in OBSTACLE_LIST:
obstacle = Obstacle(*obs)
self.all_sprites.add(obstacle)
self.obstacles.add(obstacle)
At this point, hopefully the error message will make it clear that referencing self.obstacle isn't going to work. pg.sprite.groupcollide returns you a Sprite_dict, so you need to extract the obstacle from collide to figure out what has collided.
#KentShikama Thanks for pointing that out.
I have fixed the issue by using the dictionary.
for obstacles, bullets in collide.items():
obstacles.obs_health = obstacles.obs_health - bullet.damage
if obstacles.obs_health == 0:
obstacles.kill()
i'm making a game about a car trying not to collide with pedestrian car.
I'm trying to add a collision to the user_car(aka Player class) with enemy(aka pedestrian_cars class), but i'm not exactly sure where(while loop?) and how to do it. Some variables maybe be bad but I will fix them later.
My program:
import pygame, random, math, sys
from pygame.locals import *
class Player(pygame.sprite.Sprite):
def __init__(self, starty):
pygame.sprite.Sprite.__init__(self)
# Images
self.aliveImage = pygame.image.load("playercar.png").convert_alpha()
#self.deadImage = pygame.image.load("data/PlayerExplode.png").convert_alpha()
self.image = self.aliveImage
self.rect = self.image.get_rect()
self.rect.x = 200
self.rect.y = starty - self.rect.height
self.speed = 7
self.dead = False
# Explode if you get hit, lose a life
def explode(self):
if not self.dead:
self.dead = True
self.image = self.deadImage
pygame.mixer.stop()
self.channel = self.explodeSound.play()
game.playerShots.empty()
game.enemyShots.empty()
game.wave.mship.empty()
game.lives.update(-1)
class pedestrian_cars(pygame.sprite.Sprite):
def __init__(self, starty,startx):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load("pedcar.png").convert_alpha()
self.rect = self.image.get_rect()
self.rect.y = starty - self.rect.height
self.rect.x = startx - self.rect.width
self.delta_y = 5 # 5
self.gravity = .5 #.5
self.has_spawned = False
def update(self):
self.rect.y += self.delta_y
def spawn(self):
if self.rect.y == 480 or self.has_spawned == False:
self.has_spawned = True
self.rect.x = random.randint(60,300)
self.rect.y = -10
def main():
""" Set up the game and run the main game loop """
pygame.mixer.pre_init(44100, -16, 2, 2048)
pygame.init() # prepare the pygame module for use
surfaceSz = 480 # Desired physical surface size, in pixels.
# Create surface of (width, height), and its window.
main_surface = pygame.display.set_mode((surfaceSz, surfaceSz))
#SPRITES###############################################################
user_car = Player(450)
enemy = pedestrian_cars(10,200)
#SPRITES################################################################
background_image = pygame.image.load("background2.png")
all_sprites = pygame.sprite.Group()
user_car.add(all_sprites)
enemy.add(all_sprites)
clock = pygame.time.Clock()
b1 = "background2.png"
back = pygame.image.load(b1).convert()
back2 = pygame.image.load(b1).convert()
y = 0
screenWidth = 600
screenHeight = 480
#Sound/Music#####################################
pygame.mixer.music.load("stilldre.wav")
pygame.mixer.music.play(-1)
#-################################################
while True:
ev = pygame.event.poll() # look for any event
if ev.type == pygame.QUIT: # window close button clicked?
break # ... leave game loop
sys.exit()
if not user_car.dead:
# Move the player
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT]:
user_car.rect.x = max(user_car.rect.x - user_car.speed, 116-user_car.rect.width)
elif keys[pygame.K_RIGHT]:
user_car.rect.x = min(user_car.rect.x + user_car.speed, 395-user_car.rect.width)
else:
# Go back to playing after the explosion sound finishes
if not self.channel.get_busy():
self.image = self.aliveImage
self.dead = False
self.rect.x = 200
# Update your game objects and data structures here...
all_sprites.update()
enemy.spawn()
main_surface.fill((0,200,255))
main_surface.blit(background_image, (0, 0))
main_surface.blit(back, (0,y))
main_surface.blit(back2,(0,y-screenHeight))
y = y + 8
if y == screenWidth:
y = 0
## if enemy.alive.x ==
## msElapsed = clock.tick(100)
## pygame.display.flip()
all_sprites.draw(main_surface)
# Now the surface is ready, tell pygame to display it!
pygame.display.flip()
clock.tick(200)
msElapsed = clock.tick(100)
pygame.quit() # once we leave the loop, close the window.
main()
You can simply check if the rects of your objects overlap with colliderect:
while True:
...
if user_car.rect.colliderect(enemy.rect):
do_something()
...