Chasing Sprites in Pygame - python

I have two sprites, a cat and a mouse, and I'm trying to make the cat chase the mouse. The cat should move towards the mouse and try to "catch" it no matter where the mouse is. If the mouse is above the cat, the cat will move up to try to "catch" it. The program runs and I can move the mouse with my arrow keys, but the cat won't move. Here is my code:
from pygame import *
size_x = 800
size_y = 600
class Object:
def disp(self, screen):
screen.blit(self.sprite, self.rect)
class Cat(Object):
def __init__(self):
self.sprite = image.load("cat.bmp")
self.rect = self.sprite.get_rect()
self.rect.centerx = size_x / 2
self.rect.centery = size_y / 2
self.move_x = 0
self.move_y = 0
def cycle(self):
# self.rect.centerx = 500 - abs(self.count)
# self.count += 2
# if self.count > 400:
# self.count = -400
self.rect.centerx += self.move_x
if self.rect.centerx < 0:
self.rect.centerx = 800
# self.rect.centery = 500 - abs(self.count)
# self.count += 2
# if self.count > 400:
# self.count = -400
self.rect.centery += self.move_y
if self.rect.centery < 0:
self.rect.centery = 800
def chase(self, mouse):
#These should move the cat towards the mouse.
#If the cat is to the left of the mouse, this should move the cat right.
if self.rect.centerx < mouse.rect.centerx:
self.move_x += 3
#If the cat is to the right of the mouse, this should move the cat left.
elif self.rect.centerx > mouse.rect.centerx:
self.move_x -= 3
#If the cat is above the mouse, this should move the cat down.
if self.rect.centery < mouse.rect.centery:
self.move_y += 3
#If the cat is below the mouse, this should move the cat up.
elif self.rect.centery > mouse.rect.centery:
self.move_y -= 3
class Mouse(Object):
def __init__(self):
self.sprite = image.load("mouse.bmp")
self.rect = self.sprite.get_rect()
self.rect.centerx = 100
self.rect.centery = 100
self.count = 0
self.move_x = 0
self.move_y = 0
def checkwith(self, otherrect):
if self.rect.colliderect(otherrect):
exit()
def cycle(self):
# self.rect.centerx = 500 - abs(self.count)
# self.count += 2
# if self.count > 400:
# self.count = -400
self.rect.centerx += self.move_x
if self.rect.centerx < 0:
self.rect.centerx = 800
# self.rect.centery = 500 - abs(self.count)
# self.count += 2
# if self.count > 400:
# self.count = -400
self.rect.centery += self.move_y
if self.rect.centery < 0:
self.rect.centery = 800
def right(self):
self.move_x += 10
def left(self):
self.move_x -= 10
def up(self):
self.move_y -= 10
def down(self):
self.move_y += 10
def stop_x(self):
self.move_x = 0
def stop_y(self):
self.move_y = 0
init()
screen = display.set_mode((size_x, size_y))
c = Cat()
m = Mouse()
clock = time.Clock()
while True:
for e in event.get():
if e.type == QUIT:
quit()
if e.type == KEYDOWN:
if e.key == K_RIGHT:
m.right()
elif e.key == K_LEFT:
m.left()
elif e.key == K_UP:
m.up()
elif e.key == K_DOWN:
m.down()
if e.type == KEYUP:
if e.key == K_RIGHT or e.key == K_LEFT:
m.stop_x()
if e.key == K_UP or e.key == K_DOWN:
m.stop_y()
c.chase(m)
m.cycle()
screen.fill((255,255,255))
m.disp(screen)
c.disp(screen)
display.flip()
clock.tick(60)

Your Cat class doesn't update its rect, like you do for the Mouse in Mouse.cycle().
Just copy-paste the cycle() method to the Cat class, and add c.cycle() to your main loop.

Shouldn't you have
self.rect.centerx += self.move_x
somewhere in the Cat class? (same for y of course)

Related

Player jumps only once using player.jump in pygame

I am trying to make my player jump (from this tutorial https://opensource.com/article/19/12/jumping-python-platformer-game) but it only jumps once when you press key_up or key "w". And when I look at the output produced in the terminal while I am running the game.py file I see that it was printed jump several times in the terminal.
game.py:
import pygame
import sys
import os
'''
Objects
'''
class Platform(pygame.sprite.Sprite):
# x location, y location, img width, img height, img file
def __init__(self,xloc,yloc,imgw,imgh,img):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load(os.path.join('images',img)).convert()
self.image.convert_alpha()
self.rect = self.image.get_rect()
self.rect.y = yloc
self.rect.x = xloc
class Player(pygame.sprite.Sprite):
'''
Spawn a player
'''
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.movex = 0
self.movey = 0
self.frame = 0
self.health = 10
# gravity variables here
self.collide_delta = 0
self.jump_delta = 6
self.score = 1
self.images = []
for i in range(1,9):
img = pygame.image.load(os.path.join('images','spr' + str(i) + '.png')).convert()
img.convert_alpha()
img.set_colorkey(ALPHA)
self.images.append(img)
self.image = self.images[0]
self.rect = self.image.get_rect()
def jump(self,platform_list):
self.jump_delta = 0
def gravity(self):
self.movey += 3.2 # how fast player falls
if self.movey >= 15:
self.movey = 6
if self.rect.bottom > worldy and self.movey >= 0: # <-- uses bottom
self.movey = 0
self.rect.bottom = worldy # <-- uses bottom
def control(self,x,y):
'''
control player movement
'''
self.movex += x
self.movey += y
def update(self):
'''
Update sprite position
'''
plat_hit_list = pygame.sprite.spritecollide(self, plat_list, False)
for p in plat_hit_list:
self.collide_delta = 0 # stop jumping
self.movey = 0
if self.rect.y > p.rect.y:
self.rect.y = p.rect.y+ty
else:
self.rect.y = p.rect.y-ty
if self.collide_delta < 6 and self.jump_delta < 6:
self.jump_delta = 6*2
self.movey -= 33 # how high to jump
self.collide_delta += 6
self.jump_delta += 6
self.rect.x = self.rect.x + self.movex
self.rect.y = self.rect.y + self.movey
# moving left
if self.movex < 0:
self.frame += 1
if self.frame > ani*3:
self.frame = 0
self.image = self.images[self.frame//ani]
# moving right
if self.movex > 0:
self.frame += 1
if self.frame > ani*3:
self.frame = 0
self.image = self.images[(self.frame//ani)+4]
# collisions
enemy_hit_list = pygame.sprite.spritecollide(self, enemy_list, False)
for enemy in enemy_hit_list:
self.health -= 1
print(self.health)
plat_hit_list = pygame.sprite.spritecollide(self, plat_list, False)
for p in plat_hit_list:
self.rect.bottom = p.rect.top
ground_hit_list = pygame.sprite.spritecollide(self, ground_list, False)
for g in ground_hit_list:
self.movey = 0
self.rect.y = worldy-ty-ty
self.collide_delta = 0 # stop jumping
if self.rect.y > g.rect.y:
self.health -= 1
print(self.health)
class Enemy(pygame.sprite.Sprite):
'''
Spawn an enemy
'''
def __init__(self,x,y,img):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load(os.path.join('images',img))
#self.image.convert_alpha()
#self.image.set_colorkey(ALPHA)
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
self.counter = 0
def move(self):
'''
enemy movement
'''
distance = 80
speed = 8
if self.counter >= 0 and self.counter <= distance:
self.rect.x += speed
elif self.counter >= distance and self.counter <= distance*2:
self.rect.x -= speed
else:
self.counter = 0
self.counter += 1
class Level():
def bad(lvl,eloc):
if lvl == 1:
enemy = Enemy(eloc[0],eloc[1],'yeti.png') # spawn enemy
enemy_list = pygame.sprite.Group() # create enemy group
enemy_list.add(enemy) # add enemy to group
if lvl == 2:
print("Level " + str(lvl) )
return enemy_list
def loot(lvl,lloc):
print(lvl)
def ground(lvl,gloc,tx,ty):
ground_list = pygame.sprite.Group()
i=0
if lvl == 1:
while i < len(gloc):
ground = Platform(gloc[i],worldy-ty,tx,ty,'ground.png')
ground_list.add(ground)
i=i+1
if lvl == 2:
print("Level " + str(lvl) )
return ground_list
def platform(lvl,tx,ty):
plat_list = pygame.sprite.Group()
ploc = []
i=0
if lvl == 1:
ploc.append((0,worldy-ty-128,3))
ploc.append((300,worldy-ty-256,3))
ploc.append((500,worldy-ty-128,4))
while i < len(ploc):
j=0
while j <= ploc[i][2]:
plat = Platform((ploc[i][0]+(j*tx)),ploc[i][1],tx,ty,'ground.png')
plat_list.add(plat)
j=j+1
print('run' + str(i) + str(ploc[i]))
i=i+1
if lvl == 2:
print("Level " + str(lvl) )
return plat_list
'''
Setup
'''
worldx = 960
worldy = 720
fps = 40 # frame rate
ani = 4 # animation cycles
clock = pygame.time.Clock()
pygame.init()
main = True
BLUE = (25,25,200)
BLACK = (23,23,23 )
WHITE = (254,254,254)
ALPHA = (0,255,0)
world = pygame.display.set_mode([worldx,worldy])
backdrop = pygame.image.load(os.path.join('images','stage.png')).convert()
backdropbox = world.get_rect()
player = Player() # spawn player
player.rect.x = 0
player.rect.y = 0
player_list = pygame.sprite.Group()
player_list.add(player)
steps = 10 # how fast to move
eloc = []
eloc = [200,20]
gloc = []
#gloc = [0,630,64,630,128,630,192,630,256,630,320,630,384,630]
tx = 64 #tile size
ty = 64 #tile size
i=0
while i <= (worldx/tx)+tx:
gloc.append(i*tx)
i=i+1
enemy_list = Level.bad( 1, eloc )
ground_list = Level.ground( 1,gloc,tx,ty )
plat_list = Level.platform( 1,tx,ty )
'''
Main loop
'''
while main == True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit(); sys.exit()
main = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT or event.key == ord('a'):
print("LEFT")
player.control(-steps,0)
if event.key == pygame.K_RIGHT or event.key == ord('d'):
print("RIGHT")
player.control(steps,0)
if event.key == pygame.K_UP or event.key == ord('w'):
print('jump')
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT or event.key == ord('a'):
player.control(steps,0)
if event.key == pygame.K_RIGHT or event.key == ord('d'):
player.control(-steps,0)
if event.key == pygame.K_UP or event.key == ord('w'):
player.jump(plat_list)
if event.key == ord('q'):
pygame.quit()
sys.exit()
main = False
world.blit(backdrop, backdropbox)
player.gravity() # check gravity
player.update()
player_list.draw(world)
enemy_list.draw(world)
ground_list.draw(world)
plat_list.draw(world)
for e in enemy_list:
e.move()
pygame.display.flip()
clock.tick(fps)
The original images are from here https://opengameart.org/sites/default/files/opp2_sprites.zip but I have separated in imgur for easy explanation:
content folder images:
For enemy (sprit) is yeti.png:
For background is stage.png: https://imgur.com/YyiEJ0q
and the image of the player: spr.png:
To do a jump, self.collide_delta and self.jump_delta have to be less than 6. See your code:
if self.collide_delta < 6 and self.jump_delta < 6:
self.jump_delta = 6*2
The issue is that self.collide_delta is not set 0, when the player hits a platform:
(in the 2nd case)
plat_hit_list = pygame.sprite.spritecollide(self, plat_list, False)
for p in plat_hit_list:
self.rect.bottom = p.rect.top
self.collide_delta = 0 # <----- this is missing

Pygame Collision with variable speed

it would be really amazing if you could help us with this problem . We're currently working on a game project at school and we want to create a Bomberman-like labyrinth game.
The problem is the following:
the position and the speed of the bombs depend on the mouse which is tracked using float values but is getting way too high if you click far away so it can skip collision detection because it just goes too fast at times. Now there are some other weird errors when you line up the bomb with the bottom of a block and some other collisions.
Is the method colliderect the error ? Do we need to check for each site or are there any better solutions to this problem. We also thought about just using 4 directions but even that didn't work out properly.
I really hope somebody out there can help.
class Block( pygame.sprite.Sprite):
def __init__(self,color = SCHWARZ, width = 40, height = 40, movable = 0):
super().__init__()
self.width = width
self.height = height
self.color = color
self.movable = movable
self.image = pygame.Surface((width,height))
self.image.fill(color)
self.properties()
def properties(self):
self.rect = self.image.get_rect()
self.origin_x = self.rect.centerx
self.origin_y = self.rect.centery
def set_pos(self, x, y):
self.rect.x = x
self.rect.y = y
def render(self,window):
pygame.draw.rect(window,self.color,(self.rect.x,self.rect.y,self.width,self.height))
class Bomb(Block):
def __init__(self,player, target_x, target_y,countdown,zeit,color = BLAU):
super().__init__(color, width = 20, height = 20)
self.target_x = round(target_x)
self.target_y = round(target_y)
self.countdown = countdown
self.zeit = zeit
self.player_x = player.rect.left + player.width/2
self.player_y = player.rect.top + player.height/2
self.set_pos(player.rect.center[0]-self.width/2,player.rect.center[1]-self.height/2)
self.truepos = list(self.rect.center)
self.setspeed(3)
def setspeed(self,factor):
self.speed_x = (self.target_x - self.player_x)/100
self.speed_y = (self.target_y - self.player_y)/100
"""self.direction = [0,0]
if self.target_x - self.player_x < 0:
self.direction[0] = -1
elif self.target_x - self.player_x > 0:
self.direction[0] = 1
if self.target_y - self.player_y > 0:
self.direction[1] = 1
elif self.target_y - self.player_y < 0:
self.direction[1] = -1
self.speed_x = self.direction[0]* factor
self.speed_y = self.direction[1]* factor
print(self.speed_x)
print(self.speed_y)"""
def move(self):
if self.speed_x != 0:
self.collision()
if self.speed_y != 0:
self.collision()
def update(self):
self.move()
if self.countdown > 0:
self.countdown -= self.zeit
elif self.countdown <= 0:
bomblist_list.remove(self)
def collision(self):
for block in block_list:
if block.movable != 1:
if self.rect.colliderect(block.rect):
self.distance = [abs(block.rect.centerx - (self.truepos[0] + self.speed_x)), abs(block.rect.centery - (self.truepos[1] + self.speed_y))]
if self.distance[0] > self.distance[1]:
if self.speed_x < 0:
self.rect.left = block.rect.right - self.speed_x
elif self.speed_x > 0:
self.rect.right = block.rect.left -self.speed_x
self.speed_x = -self.speed_x
elif self.distance[0] < self.distance[1]:
if self.speed_y < 0:
self.rect.top = block.rect.bottom - self.speed_y
elif self.speed_y > 0:
self.rect.bottom = block.rect.top - self.speed_y
self.speed_y = -self.speed_y
self.truepos[0] += self.speed_x
self.truepos[1] += self.speed_y
self.rect.center = self.truepos
# -------- Main Program Loop -----------
while not done:
clock.tick(fps)
millisekunde = float(clock.tick(fps))
zeit = millisekunde /500
vergangen += zeit
# --- Main event loop
for event in pygame.event.get(): # User macht irgendwas
if event.type == pygame.QUIT: # Wenn der User Quit klickt
done = True # Verlässt die Schleife
elif event.type == pygame.KEYDOWN:
pass
#if event.key == pygame.K_UP:
#if e
elif event.type == pygame.MOUSEBUTTONDOWN:
if event.button == 1:
mx,my = pygame.mouse.get_pos()
bomb = Bomb(player,mx,my,3,zeit)
bomblist_list.append(bomb)
planted = True
keys = pygame.key.get_pressed()
if keys[pygame.K_RIGHT]:
player.move(speedx,0)
if keys[pygame.K_LEFT]:
player.move(-speedx,0)
if keys[pygame.K_DOWN]:
player.move(0,speedy)
if keys[pygame.K_UP]:
player.move(0,-speedy)
if planted:
for bomb in bomblist_list:
bomb.update()
screen.fill(SCHWARZ)
for block in block_list:
block.render(screen)
if planted:
for bomb in bomblist_list:
bomb.render(screen)
pygame.draw.rect(screen,red,player.rect)
pygame.display.update()
pygame.quit()
When checking collision on fast moving items that can pass an object in one frame, what you want to do is store it's position on the last frame and get it's position on the current frame. With this you can check if a it should have collided with anything between the last and current frame.
Then you can amend it's position by putting it back to where it should have stopped and subsequently draw the object.

Python throws the error "RuntimeError: maximum recursion depth exceeded while calling a Python object"

#imports
import pygame
#globals
SCREENWIDTH = 800
SCREENHEIGHT = 480
class Player(pygame.sprite.Sprite()):
#relevant variables
change_x = 0
change_y = 0
level = None
def __init__(self):
pygame.sprite.Sprite.__init__()
self.width = 25
self.height = 25
self.image = pygame.Surface([width,height])
self.image.fill(pygame.color.Color('RED'))
def update(self):
""" Move the player. """
# Move left/right
self.rect.x += self.change_x
# See if we hit anything
block_hit_list = pygame.sprite.spritecollide(self, self.level.platform_list, False)
for block in block_hit_list:
# If we are moving right,
# set our right side to the left side of the item we hit
if self.change_x > 0:
self.rect.right = block.rect.left
elif self.change_x < 0:
# Otherwise if we are moving left, do the opposite.
self.rect.left = block.rect.right
self.change_x = 0
# Move up/down
self.rect.y += self.change_y
# Check and see if we hit anything
block_hit_list = pygame.sprite.spritecollide(self, self.level.platform_list, False)
for block in block_hit_list:
# Reset our position based on the top/bottom of the object.
if self.change_y > 0:
self.rect.bottom = block.rect.top
elif self.change_y < 0:
self.rect.top = block.rect.bottom
# Stop our vertical movement
self.change_y = 0
def go_left(self):
self.change_x = -1
def go_right(self):
self.change_x = 1
def go_up(self):
self.change_y = -1
def go_down(self):
self.change_y = 1
def stop(self):
self.change_x = 0
#collideable object
class Wall(pygame.sprite.Sprite):
level = None
def __init__(self, width, height):
pygame.sprite.Sprite.__init__()
self.image = pygame.Surface([width,height])
self.image.fill(pygame.color.Color('Yellow'))
self.rect = self.image.get_rect()
#collideable object that will later take players to different rooms
class Door(Wall):
level = None
def __init__(self):
Wall.__init__()
self.width = 5
self.height = 30
class Level(object):
background = None
world_shift_x = 0
world_shift_y=0
level_limit_x = -1000
level_limit_y = -2000
def __init__(self, player):
self.wall_list = pygame.sprite.Group()
self.enemy_list = pygame.sprite.Group()
self.door_list = pygame.sprite.Group()
def update(self):
self.wall_list.update()
self.enemy_list.update()
self.door_list.update()
def draw(self):
screen.fill(pygame.color.Color('Black'))
self.wall_list.draw(screen)
self.enemy_list.draw(screen)
self.door_list.draw(screen)
def shift_world(self, shift_x, shift_y):
#scrolls the screen at a speed of "shift x or y"
self.world_shift_x += shift_x
self.world_shift_y += shift_y
#shifts items within the world with the world
for wall in self.wall_list:
wall.rect.x += shift_x
wall.rect.y += shift_y
for door in self.door_list:
door.rect.x += shift_x
door.rect.y += shift_y
for enemy in self.enemy_list:
enemy.rect.x += shift_x
enemy.rect.y += shift_y
class Level01(Level):
#test level
def __init__(self,player):
Level.__init__()
self.level_limit_x = -1000
self.level_limit_y = -2000
level = [[200,800,0,SCREENHEIGHT],
[200,600,50,SCREENHEIGHT],
[850,200,50,0],
[600,200,50,-50]
]
for wall in level:
block = Wall(wall[0], wall[1])
block.x = wall[2]
block.y = wall[3]
block.player = player
self.wall_list.add(wall)
def main():
pygame.init()
size = [SCREENWIDTH, SCREENHEIGHT]
screen = pygame.display.set_mode(size)
pygame.display.set_caption("Game")
player = Player()
level_list = []
level_list.append(Level_01(player))
current_levelno = 0
current_level = level_list[current_level_no]
active_sprite_list = pygame.sprite.Group()
player.level = current_level
player.rect.x = 340
player.rect.y = SCREEN_HEIGHT - player.rect.height
active_sprite_list.add(player)
done = False
clock = pygame.time.Clock()
while not done:
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_a:
player.go_left()
if event.key == pygame.K_d:
player.go_right()
if event.key == pygame.K_w:
player.jump()
if event.type == pygame.KEYUP:
if event.key == pygame.K_a and player.change_x < 0:
player.stop()
if event.key == pygame.K_d and player.change_x > 0:
player.stop()
active_sprite_list.update()
current_level.update()
if player.rect.right >= 380:
diff_x = player.rect.right - 380
player.rect.right = 380
current_level.shift_world(-diff_x)
if player.rect.left <= 120:
diff_x = 120 - player.rect.left
player.rect.left = 120
current_level.shift_world(diff_x)
if player.rect.bottom <= 700:
diff_y = player.rect.bottom - 700
player.rect.bottom = 700
current_level.shift_world(-diff_y)
if player.rect.top >= 100:
diff_y = 100 - player.rect.bottom
player.rect.bottom = 100
current_level.shift_world(diff_y)
current_position = player.rect.x + current_level.world_shift
if current_position < current_level.level_limit:
if current_level_no < len(level_list)-1:
player.rect.x = 120
current_level_no += 1
current_level = level_list[current_level_no]
player.level = current_level
else:
done = True
current_level.draw(screen)
active_sprite_list.draw(screen)
clock.tick(60)
pygame.display.flip()
pygame.quit()
if __name__ == "__main__":
main()
The endgame of this code is to make a functional top down game with the goals of being a psychological horror. So far the mechanics in play are collision with walls, and, by extension, doors, levels, and character movements.
In total, all I can tell anyone is that this error has to do with everything in the code that isn't globals and imports(unless I'm wrong, which would make more sense to me.), and that it has something to do with
A) Code line 140
B) Throws the error under the specific line under 'sprite.py' that says 'self.add(*group) (which is line 142 in the 'sprite.py' file)
The stuff I can speculate about in this is that perhaps the code is throwing an infinite loop, as watching the console shows a code in the IDLE Shell, or the messages section of the pyscripter(what I'm using to program this), which iterates indefinitely before the program terminates. No visuals are created, and nothing appears to be happening, save the infinite loop. The code message is 'File "C:\Python33\lib\site-packages\pygame\sprite.py", line 142, in add self.add(*group) I can't say for sure, it's probably better that you run the code yourself to see what you can gather.

Pygame: Why Won't My Player Animation Play?

Hello I am currently working on a survival shooter game and I am currently getting frustrated at a few things. One being my player animation not working. I have the code for the player class right here:
import pygame
from zombie import *
# Player
class Player(pygame.sprite.Sprite):
def __init__(self, x, y, gravity):
# Player dimensions and position
# Player image and animation
self.images = []
self.images.append(pygame.image.load('images/Sprites/player.png'))
self.images.append(pygame.image.load('images/Sprites/player2.png'))
#~ self.images.append(pygame.image.load('ball1.png'))
#~ self.images.append(pygame.image.load('ball2.png'))
self.maxImage = len(self.images)
self.currentImage = 0
#~ self.rect = pygame.Rect(x, y, 80, 80)
self.rect = self.images[0].get_rect()
self.rect.x = x
self.rect.y = y
self.timeTarget = 10
self.timeNum = 1
self.velX = 0
self.velY = 0
self.health = 100
# Jump and gravity
self.jumping = False
self.on_ground = False
self.origJumpVel = 15
self.jumpVel = self.origJumpVel
self.gravity = 0.5
# Jump inputs
def do_jump(self):
if self.jumping and not self.on_ground:
self.velY = -self.jumpVel
self.jumpVel -= self.gravity
if self.on_ground:
self.jumping = False
self.jumpVel = self.origJumpVel
self.velY = 0
self.on_ground = True
def handle_events(self, event):
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
if not self.jumping:
self.jumping = True
self.on_ground = False
elif event.key == pygame.K_a:
self.velX = -5
elif event.key == pygame.K_d:
self.velX = +5
elif event.type == pygame.KEYUP:
if event.key in (pygame.K_a, pygame.K_d):
self.velX = 0
# PLayer updates
def update(self):
# Animations
if self.timeNum == self.timeTarget:
self.currentImage += 1
if self.currentImage >= self.maxImage:
self.currentImage = 0
self.timeNum = 1
# Health
#if self.rect.x == zombie.rect.x:
#self.health -= 10
# Screen wrap
if self.rect.right > 1280:
self.rect.left = 0
elif self.rect.left < 0:
self.rect.right = 1280
# Player rendering
def render(self, surface):
surface.blit(self.images[self.currentImage], self.rect)
If you want to know about any of my other problems/frustrations just say so. Any help will be greatly appreciated. Thank you.
You have
if self.timeNum == self.timeTarget:
# ...
self.timeNum += 1
but self.timeNum is 1 and self.timeTarget is 10 so it can't be run and it can't change self.timeNum
You probably need
if self.timeNum == self.timeTarget:
# ...
# inside of `if`
self.timeNum = 0
# outside of `if`
self.timeNum += 1

Pygame - Keep Sprites from overlapping

I'm making a space invaders type game using python and pygame. I currently have where I can move my user ship back and forth along the bottom with my arrow keys, and my enemies spawn and move back and forth across the top. My problem is with the enemies. I have it set so if they hit 100 pixels from the edge of the game screen, they start going back the other direction. This results in an overlap while the ones that have hit the limit are already heading back and the ones that haven't hit the limit are still going the original direction. I want it so that when the enemies on the edge hit the limit, all the enemies immediately go back in the other direction, just like in space invaders. My code is below. I have KeepFormation under enemies to try to do what I wanted, but it isn't working. Thank you!
from pygame import *
size_x = 900
size_y = 650
class Object:
def disp(self, screen):
screen.blit(self.sprite, self.rect)
class User_Ship(Object):
def __init__(self):
self.sprite = image.load("mouse.bmp")
self.rect = self.sprite.get_rect()
self.rect.centerx = size_x/2
self.rect.centery = size_y - 40
self.count = 0
self.move_x = 0
self.move_y = 0
def checkwith(self, otherrect):
if self.rect.colliderect(otherrect):
exit()
def cycle(self):
self.rect.centerx += self.move_x
if self.rect.centerx < 100:
self.rect.centerx = 100
if self.rect.centerx > size_x - 100:
self.rect.centerx = size_x - 100
self.rect.centery += self.move_y
if self.rect.centery < 0:
self.rect.centery = 800
def right(self):
self.move_x += 10
def left(self):
self.move_x -= 10
def stop_x(self):
self.move_x = 0
def stop_y(self):
self.move_y = 0
def shoot(self):
if keys[pygame.K_SPACE]:
self.Bullet.x = self.rect.centerx
self.Bullet.y = self.rect.centery
self.Bullet.speed = 10
class Enemys(Object):
def __init__(self):
self.sprite = image.load("ball.bmp")
self.rect = self.sprite.get_rect()
self.rect.centerx = size_x/3
self.rect.centery = 200
self.mval = -2
def KeepFormation(self, otherrect):
if self.rect.colliderect(otherrect):
self.rect.centerx += 5
def cycle(self):
self.rect.centerx += self.mval
if self.rect.centerx < 100:
self.mval = 2
elif self.rect.centerx > (size_x - 100):
self.mval = -2
class Bullet(Object):
def __init__(self):
self.sprite = image.load("missile.png")
self.rect = self.sprite.get_rect()
self.rect.centerx = -100
self.rect.centery = 100
self.speed = 0
EnemyList = []
for i in range(14):
EnemyList.append(Enemys())
EnemyList[i].rect.centerx = (i) * 50
# EnemyList[i].count = i * 20
init()
screen = display.set_mode((size_x, size_y))
m = User_Ship()
en = Enemys()
b = Bullet()
clock = time.Clock()
while True:
for e in event.get():
if e.type == QUIT:
quit()
if e.type == KEYDOWN:
if e.key == K_RIGHT:
m.right()
elif e.key == K_LEFT:
m.left()
if e.type == KEYUP:
if e.key == K_RIGHT or e.key == K_LEFT:
m.stop_x()
m.cycle()
screen.fill((255,255,255))
for enemy in EnemyList:
enemy.cycle()
enemy.disp(screen)
enemy.KeepFormation(enemy.rect)
m.disp(screen)
b.disp(screen)
display.flip()
clock.tick(60)
Add a flag in
def cycle(self):
self.rect.centerx += self.mval
if self.rect.centerx < 100:
self.mval = 2
return True # Direction change!
elif self.rect.centerx > (size_x - 100):
self.mval = -2
return True
return False # no change
But then you need to make this change happen only once. Thus...
done_once = False
for enemy in EnemyList:
if not done_once:
change = enemy.cycle()
if change and not done_once:
# call the new enemy function that changes every enemy's direction
done_once = True
enemy.disp(screen)
enemy.KeepFormation(enemy.rect)
Process this flag such that everyone should change direction now. You may need another function & direction_tracking variable in your Enemy class. Good luck & good job!

Categories

Resources