Pygame shooting fix for school

Question:

When i cast a spell the spell moves with me and i don’t want it to. I’m circling simple fixes and i feel the answer is in my face but i been staring at it too long. The spell travels but when i move the character the spell follows the direction of the player even as its left the player position. The full code is below

import pygame as py
import sys
from os import path
from settings import *
from sprites import *
from tilemap import *

#HUD
def draw_player_health(surf,x,y,pct):
    if pct < 0:
        pct = 0

    BAR_LENGTH = 100
    BAR_HEIGHT = 20
    fill = pct * BAR_LENGTH
    outline_rect = py.Rect(x,y,BAR_LENGTH,BAR_HEIGHT)
    fill_rect = py.Rect(x, y, fill, BAR_HEIGHT)
    if pct > 0.6:
        color = GREEN
    elif pct > 0.3:
        color = YELLOW
    else:
        color = RED

    py.draw.rect(surf,color,fill_rect)
    py.draw.rect(surf, BLACK, outline_rect, 2)            


class Game:
    def __init__(self):
        py.init()
        self.screen = py.display.set_mode((WIDTH, HEIGHT))
        py.display.set_caption(TITLE)
        self.clock = py.time.Clock()
        self.load_data()

    def load_data(self):
        game_folder = path.dirname(__file__)
        self.map = Map(path.join(game_folder, 'imgmap.txt'))
        self.player_spritesheet = SpriteSheet('img/player_sheet1.png')
        self.wall_spritesheet = SpriteSheet('img/woodwall.png')
        self.terrain_spritesheet = SpriteSheet('img/grasstexture.jpg')
        self.mob_spritesheet = SpriteSheet('imgmobsheet.png')
        self.spell_spritesheet = SpriteSheet('imgspellsheethm.png')

    def new(self):
        # initialize all variables and do all the setup for a new game
        self.all_sprites = py.sprite.LayeredUpdates()
        self.walls = py.sprite.LayeredUpdates()
        self.mobs = py.sprite.LayeredUpdates()
        self.spell = py.sprite.LayeredUpdates()
        #self.player = py.sprite.LayeredUpdates()
        for row, tiles in enumerate(self.map.data):
            for col, tile in enumerate(tiles):
                Groundtile(self,col,row)
                if tile == '1':
                    Wall(self, col, row)
                if tile == 'P':
                    self.player = Player(self, col, row)
                    
                if tile == 'M':
                    Mobs(self, col, row)    
        self.camera = Camera(self.map.width, self.map.height)

    def run(self):
        # game loop - set self.playing = False to end the game
        self.playing = True
        while self.playing:
            self.dt = self.clock.tick(FPS) / 1000
            self.events()
            self.update()
            self.draw()

    def quit(self):
        py.quit()
        sys.exit()

    def update(self):
        # update portion of the game loop
        self.all_sprites.update()
        self.camera.update(self.player)

    def draw_grid(self):
        for x in range(0, WIDTH, TILESIZE):
            py.draw.line(self.screen, LIGHTGREY, (x, 0), (x, HEIGHT))
        for y in range(0, HEIGHT, TILESIZE):
            py.draw.line(self.screen, LIGHTGREY, (0, y), (WIDTH, y))

    def draw(self):
        self.screen.fill(BGCOLOR)
       # self.draw_grid()
        for sprite in self.all_sprites:
            if isinstance(sprite, Mobs):
                sprite.draw_health()
            self.screen.blit(sprite.image, self.camera.apply(sprite))

        #HUD
        draw_player_health(self.screen,850, 10, self.player.health / PLAYER_HEALTH)    

        py.display.flip()
  
    def events(self):
        # catch all events here
        for event in py.event.get():
            if event.type == py.QUIT:
                self.quit()
            if event.type == py.KEYDOWN:
                if event.key == py.K_ESCAPE:
                    self.quit()
                
                if event.key == py.K_SPACE:
                    if self.player.facing == 'up':
                     Spells(self, self.player.rect.x, self.player.rect.y)
                    if self.player.facing == 'down':
                     Spells(self, self.player.rect.x, self.player.rect.y)
                    if self.player.facing == 'left':
                     Spells(self, self.player.rect.x, self.player.rect.y)
                    if self.player.facing == 'right':
                     Spells(self, self.player.rect.x, self.player.rect.y)   
             
    def show_start_screen(self):
        pass

    def show_go_screen(self):
        pass

# create the game object
g = Game()
g.show_start_screen()
while True:
    g.new()
    g.run()
    g.show_go_screen()


             if self.y_change == 0:
                self.image = self.game.player_spritesheet.get_sprite(2, 71, self.width,self.height)
             else:
                self.image = up_animations[math.floor(self.animate_loop)]
                self.animate_loop += 0.1
                if self.animate_loop >= 4:
                    self.animate_loop = 1
        
        if self.facing == "right":
             if self.x_change == 0:
                self.image = self.game.player_spritesheet.get_sprite(6, 37, self.width,self.height)
             else:
                self.image = right_animations[math.floor(self.animate_loop)]
                self.animate_loop += 0.1
                if self.animate_loop >= 4:
                    self.animate_loop = 1   
        
        if self.facing == "left":
             if self.x_change == 0:
                self.image = self.game.player_spritesheet.get_sprite(7, 180, self.width,self.height)
             else:
                self.image = left_animations[math.floor(self.animate_loop)]
                self.animate_loop += 0.1
                if self.animate_loop >= 4:
                    self.animate_loop = 1     

    def mob_collide(self):
        hits = py.sprite.spritecollide(self.game.player,self.game.mobs, False) 
        for hit in hits:
            self.health -= MOB_DMG
        

               
    def update(self):
        self.get_keys()
        self.animation()
        self.mob_collide()
        
        self.rect.x += self.x_change
        self.collide_with_walls('x')
        self.rect.y += self.y_change
        self.collide_with_walls('y')
        self.x_change = 0
        self.y_change = 0
        if self.health <= 0:
            self.kill() 
class Mobs(py.sprite.Sprite):
    def __init__(self, game, x, y):
        self.game = game
        self._layer = MOB_LAYER
        self.groups = self.game.all_sprites, self.game.mobs
        py.sprite.Sprite.__init__(self, self.groups)

        self.x = x * TILESIZE
        self.y = y * TILESIZE
        
        self.width = TILESIZE
        self.height = TILESIZE
        
        self.facing = random.choice(['up','down','left','right'])
        self.animate_loop = 1
        self.movement_loop = 0
        self.max_travel = random.randint(0,200) 

        self.x_change = 0
        self.y_change = 0

        self.image = self.game.mob_spritesheet.get_sprite(0,11,self.width,self.height)
        self.image.set_colorkey(WHITE)
      
        self.rect = self.image.get_rect()
        self.rect.x = self.x
        self.rect.y = self.y

        self.health = MOB_HEALTH

    def update(self):
        self.movement()
        self.animation()
        self.rect.x += self.x_change
        self.collide_with_walls('x')
        self.rect.y += self.y_change
        self.collide_with_walls('y')
        self.x_change = 0
        self.y_change = 0
        if self.health <= 0:
            self.kill()
        #self.player_collide()

    def draw_health(self):
        if self.health > 60:
            color = GREEN
        elif self.health > 30:
            color = YELLOW
        else:
            color = RED 

        width = int(self.rect.width * self.health / MOB_HEALTH)
        self.health_bar = py.Rect(0,0, width, 7)
        if self.health < MOB_HEALTH:
            py.draw.rect(self.image, color, self.health_bar)           

    def collide_with_walls(self, dir):
        if dir == 'x':
            hits = py.sprite.spritecollide(self, self.game.walls, False)
            if hits:
                if self.x_change > 0:
                    self.x = hits[0].rect.left - self.rect.width
                if self.x_change < 0:
                    self.x = hits[0].rect.right
                self.x_change = 0
                self.rect.x = self.x
        if dir == 'y':
            hits = py.sprite.spritecollide(self, self.game.walls, False)
            if hits:
                if self.y_change > 0:
                    self.y = hits[0].rect.top - self.rect.height
                if self.y_change < 0:
                    self.y = hits[0].rect.bottom
                self.y_change = 0
                self.rect.y = self.y

    def movement(self):
        if  self.facing == 'left':
            self.x_change -= MOB_SPEED
            self.movement_loop -= 1
            if self.movement_loop <= -self.max_travel:
                self.facing = 'right' 
        if self.facing == 'right':
            self.x_change += MOB_SPEED
            self.movement_loop += 1
            if self.movement_loop >= self.max_travel:
                self.facing = 'left'
        if  self.facing == 'up':
            self.y_change -= MOB_SPEED
            self.movement_loop -= 1
            if self.movement_loop <= -self.max_travel:
                self.facing = 'down' 
        if self.facing == 'down':
            self.y_change += MOB_SPEED
            self.movement_loop += 1
            if self.movement_loop >= self.max_travel:
                self.facing = 'up'        

    def animation(self):
        
        down_animations = [self.game.mob_spritesheet.get_sprite(0, 11, self.width, self.height),
                           self.game.mob_spritesheet.get_sprite(33, 11, self.width, self.height),
                           self.game.mob_spritesheet.get_sprite(65, 11, self.width, self.height)]

        up_animations = [self.game.mob_spritesheet.get_sprite(2, 218, self.width, self.height),
                         self.game.mob_spritesheet.get_sprite(33, 218, self.width, self.height),
                         self.game.mob_spritesheet.get_sprite(65, 218, self.width, self.height)]

        left_animations = [self.game.mob_spritesheet.get_sprite(3, 70, self.width, self.height),
                           self.game.mob_spritesheet.get_sprite(35, 70, self.width, self.height),
                           self.game.mob_spritesheet.get_sprite(67, 70, self.width, self.height)]

        right_animations = [self.game.mob_spritesheet.get_sprite(3, 130, self.width, self.height),
                            self.game.mob_spritesheet.get_sprite(35, 130, self.width, self.height),
                            self.game.mob_spritesheet.get_sprite(67, 130, self.width, self.height)]
         
        if self.facing == "down":
            if self.y_change == 0:
                self.image = self.game.mob_spritesheet.get_sprite(2, 1, self.width,self.height)
            else:
                self.image = down_animations[math.floor(self.animate_loop)]
                self.animate_loop += 0.1
                if self.animate_loop >= 3:
                    self.animate_loop = 1   

        if self.facing == "up":
             if self.y_change == 0:
                self.image = self.game.mob_spritesheet.get_sprite(2, 71, self.width,self.height)
             else:
                self.image = up_animations[math.floor(self.animate_loop)]
                self.animate_loop += 0.1
                if self.animate_loop >= 3:
                    self.animate_loop = 1
        
        if self.facing == "right":
             if self.x_change == 0:
                self.image = self.game.mob_spritesheet.get_sprite(6, 37, self.width,self.height)
             else:
                self.image = right_animations[math.floor(self.animate_loop)]
                self.animate_loop += 0.1
                if self.animate_loop >= 3:
                    self.animate_loop = 1   
        
        if self.facing == "left":
             if self.x_change == 0:
                self.image = self.game.mob_spritesheet.get_sprite(7, 180, self.width,self.height)
             else:
                self.image = left_animations[math.floor(self.animate_loop)]
                self.animate_loop += 0.1
                if self.animate_loop >= 3:
                    self.animate_loop = 1     

     
class Spells(py.sprite.Sprite):
    def __init__(self, game,x,y):
        self.game = game
        self._layer = SPELL_LAYER
        self.groups = self.game.all_sprites, self.game.spell
        py.sprite.Sprite.__init__(self, self.groups)

        self.x = x
        self.y = y
        self.width = TILESIZE
        self.height = TILESIZE
        
        self.movement_loop = 0

        self.shoodir = 'down' 
        
        self.animate_loop = 0 
       # self.spawn_time = py.time.get_ticks()
        
        self.image = self.game.spell_spritesheet.get_sprite(4,14,self.width,self.height) 
        self.image.set_colorkey(WHITE)
        
        self.x_change = 0
        self.y_change = 0

        self.rect = self.image.get_rect()
        self.rect.x = self.x
        self.rect.y = self.y

        

    def update(self):
        self.animate()
        self.collide()
        self.rect.x += self.x_change
        self.collide_with_walls('x')
        self.rect.y += self.y_change
        self.collide_with_walls('y')
        self.x_change = 0
        self.y_change = 0
        self.movement()
        
        #if py.time.get_ticks() - self.spawn_time > SPELL_LIFETIME:
        #    self.kill()
    def collide(self):
        hits = py.sprite.groupcollide(self.game.mobs,self.game.spell, False, True) 
        for hit in hits:
            hit.health -= SPELL_DMG

    def collide_with_walls(self, dir):
        if dir == 'x':
            hits = py.sprite.spritecollide(self, self.game.walls, False)
            if hits:
                if self.x_change > 0:
                    self.x = hits[0].rect.left - self.rect.width
                    self.kill()
                if self.x_change < 0:
                    self.x = hits[0].rect.right
                    self.kill()
                self.x_change = 0
                self.rect.x = self.x
        if dir == 'y':
            hits = py.sprite.spritecollide(self, self.game.walls, False)
            if hits:
                if self.y_change > 0:
                    self.y = hits[0].rect.top - self.rect.height
                    self.kill()
                if self.y_change < 0:
                    self.y = hits[0].rect.bottom
                    self.kill()
                self.y_change = 0
                self.rect.y = self.y        

    def animate(self):
        direction = self.game.player.facing

        down_animations = [self.game.spell_spritesheet.get_sprite(0, 0, self.width, self.height),
                           self.game.spell_spritesheet.get_sprite(35, 0, self.width, self.height),
                           self.game.spell_spritesheet.get_sprite(67, 0, self.width, self.height),
                           self.game.spell_spritesheet.get_sprite(98, 0, self.width, self.height),
                           self.game.spell_spritesheet.get_sprite(128, 0, self.width, self.height),
                           self.game.spell_spritesheet.get_sprite(158, 0, self.width, self.height),
                           self.game.spell_spritesheet.get_sprite(190, 0, self.width, self.height)]

        up_animations = [self.game.spell_spritesheet.get_sprite(0, 0, self.width, self.height),
                           self.game.spell_spritesheet.get_sprite(35, 0, self.width, self.height),
                           self.game.spell_spritesheet.get_sprite(67, 0, self.width, self.height),
                           self.game.spell_spritesheet.get_sprite(98, 0, self.width, self.height),
                           self.game.spell_spritesheet.get_sprite(128, 0, self.width, self.height),
                           self.game.spell_spritesheet.get_sprite(158, 0, self.width, self.height),
                           self.game.spell_spritesheet.get_sprite(190, 0, self.width, self.height)]

        left_animations = [self.game.spell_spritesheet.get_sprite(0, 0, self.width, self.height),
                           self.game.spell_spritesheet.get_sprite(35, 0, self.width, self.height),
                           self.game.spell_spritesheet.get_sprite(67, 0, self.width, self.height),
                           self.game.spell_spritesheet.get_sprite(98, 0, self.width, self.height),
                           self.game.spell_spritesheet.get_sprite(128, 0, self.width, self.height),
                           self.game.spell_spritesheet.get_sprite(158, 0, self.width, self.height),
                           self.game.spell_spritesheet.get_sprite(190, 0, self.width, self.height)]

        right_animations = [self.game.spell_spritesheet.get_sprite(0, 0, self.width, self.height),
                           self.game.spell_spritesheet.get_sprite(35, 0, self.width, self.height),
                           self.game.spell_spritesheet.get_sprite(67, 0, self.width, self.height),
                           self.game.spell_spritesheet.get_sprite(98, 0, self.width, self.height),
                           self.game.spell_spritesheet.get_sprite(128, 0, self.width, self.height),
                           self.game.spell_spritesheet.get_sprite(158, 0, self.width, self.height),
                           self.game.spell_spritesheet.get_sprite(190, 0, self.width, self.height)]
        if direction == 'up':
            
            self.image = up_animations[math.floor(self.animate_loop)]
            self.animate_loop += 0.5
            if self.animate_loop >= 7:
                self.animate_loop = 1
                
        if direction == 'down':
            
            self.image = down_animations[math.floor(self.animate_loop)]
            self.animate_loop += 0.5
            if self.animate_loop >= 7:
                #self.kill()
                self.animate_loop = 1
        if direction == 'left':
           
            self.image = left_animations[math.floor(self.animate_loop)]
            self.animate_loop += 0.5
            if self.animate_loop >= 7:
                #self.kill()
                self.animate_loop = 1
        if direction == 'right':
            
            self.image = right_animations[math.floor(self.animate_loop)]
            self.animate_loop += 0.5
            if self.animate_loop >= 7:
                #self.kill()
                self.animate_loop = 1
        

    def movement(self):
         
        direction = self.game.player.facing
         
        if  direction == 'left':
            self.shoodir = 'left'
            self.x_change -= SPELL_SPEED
            self.movement_loop -= 1
            if self.movement_loop == -SPELL_LIFETIME:
                self.kill() 
        if  direction == 'right':
            self.shoodir = 'right'
            self.x_change += SPELL_SPEED
            self.movement_loop += 1
            if self.movement_loop == SPELL_LIFETIME:
                self.kill() 
        if  direction == 'up':
            self.shoodir = 'up'
            self.y_change -= SPELL_SPEED
            self.movement_loop -= 1
            if self.movement_loop == -SPELL_LIFETIME:
                self.kill() 
        if  direction == 'down':
            self.shoodir = 'down'
            self.y_change += SPELL_SPEED
            self.movement_loop += 1
            if self.movement_loop == SPELL_LIFETIME:
                self.kill()  
            

class Wall(py.sprite.Sprite):
    def __init__(self, game, x, y):
        self.game = game
        self._layer = BLOCK_LAYER
        self.groups = self.game.all_sprites, self.game.walls
        py.sprite.Sprite.__init__(self, self.groups)

        self.x = x * TILESIZE
        self.y = y * TILESIZE

        self.width = TILESIZE
        self.height = TILESIZE

        self.image = self.game.wall_spritesheet.get_sprite(0,0,self.width,self.height)

        self.rect = self.image.get_rect()
        self.rect.x = self.x
        self.rect.y = self.y

    
def update(self):
    self.rect.x += self.x_change
    self.rect.y += self.y_change

    self.x_change = 0
    self.y_change = 0    

class Groundtile(py.sprite.Sprite):
    def __init__(self, game, x , y):
     self.game = game
     self._layer = GROUND_LAYER
     self.groups = self.game.all_sprites
     py.sprite.Sprite.__init__(self, self.groups)
     
     self.x = x * TILESIZE
     self.y = y * TILESIZE
     self.width = TILESIZE
     self.height = TILESIZE
     
     self.image = self.game.terrain_spritesheet.get_sprite(0,0,self.width,self.height)
     
     self.rect = self.image.get_rect()
     self.rect.x = self.x
     self.rect.y = self.y

import pygame as py
from settings import *



def collide_hit_rect(one, two):
    return one.hit_rect.colliderect(two.rect)

    
class Map:
    def __init__(self, filename):
        self.data = []
        with open(filename, 'rt') as f:
            for line in f:
                self.data.append(line.strip())

        self.tilewidth = len(self.data[0])
        self.tileheight = len(self.data)
        self.width = self.tilewidth * TILESIZE
        self.height = self.tileheight * TILESIZE

class Camera:
    def __init__(self, width, height):
        self.camera = py.Rect(0, 0, width, height)
        self.width = width
        self.height = height

    def apply(self, entity):
        return entity.rect.move(self.camera.topleft)

    def update(self, target):
        x = -target.rect.x + int(WIDTH / 2)
        y = -target.rect.y + int(HEIGHT / 2)

        # limit scrolling to map size
        x = min(0, x)  # left
        y = min(0, y)  # top
        x = max(-(self.width - WIDTH), x)  # right
        y = max(-(self.height - HEIGHT), y)  # bottom
        self.camera = py.Rect(x, y, self.width, self.height)

///////SETTINGS FILE//////////

WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
DARKGREY = (40, 40, 40)
LIGHTGREY = (100, 100, 100)
GREEN = (0, 255, 0)
RED = (255, 0, 0)
YELLOW = (255, 255, 0)

# game settings
WIDTH = 1024   # 16 * 64 or 32 * 32 or 64 * 16
HEIGHT = 768  # 16 * 48 or 32 * 24 or 64 * 12
FPS = 60
TITLE = "ZomBlaster"
BGCOLOR = DARKGREY

TILESIZE = 32
GRIDWIDTH = WIDTH / TILESIZE
GRIDHEIGHT = HEIGHT / TILESIZE

# Player settings
PLAYER_SPEED = 3
PLAYER_HEALTH = 10000
#Loading Layers
PLAYER_LAYER = 4
MOB_LAYER = 3
BLOCK_LAYER = 2
GROUND_LAYER = 1
SPELL_LAYER = 4
#Mob settings
MOB_HEALTH = 100
MOB_SPEED = 1
MOB_DMG = 10
MOB_KNOCKBACK = 2
#Spell settings
SPELL_IMG1 = ''


SPELL_SPEED = 5
SPELL_LIFETIME = 2000

SPELL_RATE = 10

SPELL_DMG = 10




Asked By: Bigfootyeti

||

Answers:

You should add settings files, sprites, tilemaps to make it easier for people to debug, otherwise you have to shrink your current code file.

Answered By: Lucsky_Infosec
def animate(self):
        direction = self.game.player.facing

def movement(self):         
        direction = self.game.player.facing

These lines of code seem to modify the direction of the spell depending on direction of character every time the "animate" or "movement" methods are called.

I quickly glanced through the code looking for definition of "game.player" but I guess I may be missing it, however, I making an assumption that this is the player of the game your question is referring to.

Since your direction is modified by the player’s direction, you’ve modified the "shootdir" if your spell, as well as the animations, extra logic etc.

I might suggest using an extra variable in your class constructor with a cardinal direction that is otherwise not modifiable through your methods.
Such as:

class Spells(py.sprite.Sprite):
    def __init__(self, game,x,y, direction):
        self.game = game
        self._layer = SPELL_LAYER
        self.groups = self.game.all_sprites, self.game.spell
        self.direction = direction
        py.sprite.Sprite.__init__(self, self.groups)

and call it like so:

def events(self):
        # catch all events here
        for event in py.event.get():
            if event.type == py.QUIT:
                self.quit()
            if event.type == py.KEYDOWN:
                if event.key == py.K_ESCAPE:
                    self.quit()
                
                if event.key == py.K_SPACE:
                    if self.player.facing == 'up':
                     Spells(self, self.player.rect.x, self.player.rect.y, 
                     self.player.facing)
                    if self.player.facing == 'down':
                     Spells(self, self.player.rect.x, self.player.rect.y, 
                     self.player.facing)
                    if self.player.facing == 'left':
                     Spells(self, self.player.rect.x, self.player.rect.y, 
                     self.player.facing)
                    if self.player.facing == 'right':
                     Spells(self, self.player.rect.x, self.player.rect.y, 
                     self.player.facing)
Answered By: iroxusux
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.