Reputation: 267
I've created a dragon that moves towards the player, and while doing so it has an animation where it flies. However, if the player stands at certain angles to the dragon, the flying animation stops until it is either directly above/to the side of the player, or immediately diagonal.
For example, standing below the dragon will trigger the animation, but standing below and over to the right will cause the dragons animation to pause until it is immediately diagonal. Here is a fully runnable example;
from Rooms import *
from Player import *
import pygame
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
pygame.init()
screen_width = 1080
screen_height = 607
screen = pygame.display.set_mode([screen_width, screen_height])
pygame.display.set_caption('Labyrinth')
block_list = pygame.sprite.Group()
all_sprites_list = pygame.sprite.Group()
rooms = []
room = Room0()
rooms.append(room)
current_room_no = 0
current_room = rooms[current_room_no]
player = Player("Isaac.png", 420, 150, current_room)
all_sprites_list.add(player)
clock = pygame.time.Clock()
done = False
# -- MAIN PROGRAM LOOP -- #
# -- Event processing --
while not done:
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
# Player controls
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
player.changespeed(-7, 0)
elif event.key == pygame.K_RIGHT:
player.changespeed(7, 0)
elif event.key == pygame.K_UP:
player.changespeed(0, -7)
elif event.key == pygame.K_DOWN:
player.changespeed(0, 7)
elif event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT:
player.changespeed(7, 0)
elif event.key == pygame.K_RIGHT:
player.changespeed(-7, 0)
elif event.key == pygame.K_UP:
player.changespeed(0, 7)
elif event.key == pygame.K_DOWN:
player.changespeed(0, -7)
# -- Game Logic --
all_sprites_list.update()
current_room.enemy_sprites.update(player)
# Hit detection
screen.blit(current_room.background_image, current_room.background_position)
all_sprites_list.draw(screen)
current_room.enemy_sprites.draw(screen)
pygame.display.flip()
clock.tick(60)
pygame.quit()
import pygame
import math
from Player import Player
import time
BLACK = (0, 0, 0)
class SpriteSheet(object):
def __init__(self, file_name):
self.sprite_sheet = pygame.image.load(file_name).convert()
def get_image(self, x, y, width, height):
image = pygame.Surface([width, height]).convert()
image.blit(self.sprite_sheet, (0, 0), (x, y, width, height))
image.set_colorkey(BLACK)
return image
class Dragon(pygame.sprite.Sprite):
def __init__(self, x, y):
super().__init__()
self.flying_frames_l = []
self.flying_frames_r = []
sprite_sheet = SpriteSheet("Dragon.png")
# Flying left
image = sprite_sheet.get_image(12, 22, 95, 85)
self.flying_frames_l.append(image)
image = sprite_sheet.get_image(140, 35, 95, 67)
self.flying_frames_l.append(image)
image = sprite_sheet.get_image(18, 138, 96, 55)
self.flying_frames_l.append(image)
image = sprite_sheet.get_image(128, 131, 96, 63)
self.flying_frames_l.append(image)
image = sprite_sheet.get_image(140, 35, 95, 67)
self.flying_frames_l.append(image)
image = sprite_sheet.get_image(12, 22, 95, 85)
self.flying_frames_l.append(image)
# Flying right
image = sprite_sheet.get_image(12, 22, 95, 85)
image = pygame.transform.flip(image, True, False)
self.flying_frames_r.append(image)
image = sprite_sheet.get_image(140, 35, 95, 67)
image = pygame.transform.flip(image, True, False)
self.flying_frames_r.append(image)
image = sprite_sheet.get_image(18, 138, 96, 55)
image = pygame.transform.flip(image, True, False)
self.flying_frames_r.append(image)
image = sprite_sheet.get_image(128, 131, 96, 63)
image = pygame.transform.flip(image, True, False)
self.flying_frames_r.append(image)
image = sprite_sheet.get_image(140, 35, 95, 67)
image = pygame.transform.flip(image, True, False)
self.flying_frames_r.append(image)
image = sprite_sheet.get_image(12, 22, 95, 85)
image = pygame.transform.flip(image, True, False)
self.flying_frames_r.append(image)
self.image = self.flying_frames_r[0]
self.rect = self.image.get_rect()
self.rect.y = y
self.rect.x = x
self.speedx = 0
self.speedy = 0
self.health = 100
def update(self, player):
posx = self.rect.x
posy = self.rect.y
dx = self.rect.x - player.rect.x
dy = self.rect.y - player.rect.y
dist = math.hypot(dx, dy)
dx = dx / dist
dy = dy / dist
if dx > 0:
self.speedx = -1.5
if dx <= 0:
self.speedx = -1.5
if dy >= 0:
self.speedy = -1.5
if dy <= 0:
self.speedy = -1.5
self.rect.x += dx * self.speedx
self.rect.y += dy * self.speedy
if self.rect.x < player.rect.x:
frame = (posx // 10) % len(self.flying_frames_l)
self.image = self.flying_frames_l[frame]
else:
frame = (posx // 10) % len(self.flying_frames_r)
self.image = self.flying_frames_r[frame]
if self.rect.y < player.rect.y:
frame = (posy // 10) % len(self.flying_frames_l)
self.image = self.flying_frames_l[frame]
else:
frame = (posy // 10) % len(self.flying_frames_r)
self.image = self.flying_frames_r[frame]
import pygame
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
class Player(pygame.sprite.Sprite):
def __init__(self, filename, x, y, current_room):
super().__init__()
self.image = pygame.image.load(filename).convert()
self.image.set_colorkey(BLACK)
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
self.change_x = 0
self.change_y = 0
def changespeed(self, x, y):
self.change_x += x
self.change_y += y
def update(self):
self.rect.x += self.change_x
self.rect.y += self.change_y
import Player
import pygame
from Enemies import Dragon
class Room(object):
enemy_sprites = None
def __init__(self):
self.enemy_sprites = pygame.sprite.Group()
class Room0(Room):
def __init__(self):
super().__init__()
enemy = Dragon(380, 280)
self.enemy_sprites.add(enemy)
self.background_position = [0, 0]
self.background_image = pygame.image.load("Floor.png").convert()
This is the spritesheet im using to make it easier to run the code
Upvotes: 3
Views: 1107
Reputation: 101052
Besides the ZeroDivisionError
Azhy already pointed out, your problem is that you calculate the current image of the animation by diving posx
/posy
by a constant.
So if posy
does not change, the image will not change.
You can print out frame
at the end of update
to see it yourself.
You could extract handling the animation into its own class or something, here's a simple example:
class Animation(object):
def __init__(self, sprite, speed, images):
self.sprite = sprite
self.images = images
self.speed = speed
self.step = 0
self.frame = 0
def update(self):
self.step += 1
if self.step >= self.speed:
self.frame = (self.frame + 1) % len(self.images)
self.sprite.image = self.images[self.frame]
self.step = 0
and then the Dragon
class could look like this:
class Dragon(pygame.sprite.Sprite):
def __init__(self, x, y):
super().__init__()
flying_frames_l = []
flying_frames_r = []
sprite_sheet = SpriteSheet("Dragon.png")
# Flying left
image = sprite_sheet.get_image(12, 22, 95, 85)
flying_frames_l.append(image)
image = sprite_sheet.get_image(140, 35, 95, 67)
flying_frames_l.append(image)
image = sprite_sheet.get_image(18, 138, 96, 55)
flying_frames_l.append(image)
image = sprite_sheet.get_image(128, 131, 96, 63)
flying_frames_l.append(image)
image = sprite_sheet.get_image(140, 35, 95, 67)
flying_frames_l.append(image)
image = sprite_sheet.get_image(12, 22, 95, 85)
flying_frames_l.append(image)
self.flying_left = Animation(self, 6, flying_frames_l)
# Flying right
image = sprite_sheet.get_image(12, 22, 95, 85)
image = pygame.transform.flip(image, True, False)
flying_frames_r.append(image)
image = sprite_sheet.get_image(140, 35, 95, 67)
image = pygame.transform.flip(image, True, False)
flying_frames_r.append(image)
image = sprite_sheet.get_image(18, 138, 96, 55)
image = pygame.transform.flip(image, True, False)
flying_frames_r.append(image)
image = sprite_sheet.get_image(128, 131, 96, 63)
image = pygame.transform.flip(image, True, False)
flying_frames_r.append(image)
image = sprite_sheet.get_image(140, 35, 95, 67)
image = pygame.transform.flip(image, True, False)
flying_frames_r.append(image)
image = sprite_sheet.get_image(12, 22, 95, 85)
image = pygame.transform.flip(image, True, False)
flying_frames_r.append(image)
self.flying_right = Animation(self, 6, flying_frames_r)
self.image = flying_frames_r[0]
self.rect = self.image.get_rect()
self.rect.y = y
self.rect.x = x
self.speedx = 0
self.speedy = 0
self.health = 100
self.animation = self.flying_right
def update(self, player):
posx = self.rect.x
posy = self.rect.y
dx = self.rect.x - player.rect.x
dy = self.rect.y - player.rect.y
dist = math.hypot(dx, dy)
if dist > 0:
dx = dx / dist
dy = dy / dist
if dx > 0:
self.speedx = -1.5
self.animation = self.flying_left
if dx <= 0:
self.speedx = -1.5
self.animation = self.flying_right
if dy >= 0:
self.speedy = -1.5
if dy <= 0:
self.speedy = -1.5
self.rect.x += dx * self.speedx
self.rect.y += dy * self.speedy
self.animation.update()
Note how we simply increase a counter to see if we should change the image instead on relying on the current position.
Upvotes: 2