I am making snake in pygame and python is giving me an error that one of my objects is actually a string, but its not meant to be - python

The error that shows up in python right now is
Traceback (most recent call last):
File "C:\Users\Eduardo.Graglia\AppData\Local\Programs\Python\Python37\Start.py", line 66, in <module>
snake = snake(self) # create an instance
File "C:\Users\Eduardo.Graglia\AppData\Local\Programs\Python\Python37\Start.py", line 17, in __init__
food.image = pygame.image.load("food.png")
AttributeError: 'str' object has no attribute 'image'
I am very new to python and pygame, so most of the code I've been using is stuff I've taken and adapted from stack overflow
What I was trying to do with the food object was make it so that it was all in one player class because I am confused on how to call methods from other classes and use objects from other classes in one class. If anyone has any alternatives to what I've done please tell me.
import pygame
import os
import time
import math
import random
length = 650
width = 400
headx = 0
heady = 0
class snake(object):
def __init__(self, food):
self.image = pygame.image.load("head.png")
self.x = 0
self.y = 0
food.image = pygame.image.load("food.png")
food.x = 0
food.y = 0
def handle_keys(self):
""" Handles Keys """
key = pygame.key.get_pressed()
dist = 25 # distance moved in 1 frame, try changing it to 5
if key[pygame.K_DOWN]: # down key
self.y += dist # move down
heady = heady - dist
elif key[pygame.K_UP]: # up key
self.y -= dist # move up
heady = heady - dist
if key[pygame.K_RIGHT]: # right key
self.x += dist # move right
headx = headx - dist
elif key[pygame.K_LEFT]: # left key
self.x -= dist # move left
headx = headx - dist
def fooddrop(food, surface):
newfoodx = 1
newfoody = 1
while newfoodx % 25 != 0 or newfoodx !=0:
newfoodx = random.randint(0,650)
while newfoody % 25 != 0 or newfoody !=0:
newfoody = random.randint(0,400)
food.x = newfoodx
food.y = newfoody
surface.blit(food.image,(food.x,food.y))
def draw(self, surface):
""" Draw on surface """
# blit yourself at your current position
surface.blit(self.image, (self.x, self.y))
self = 'null'
food = 'null'
pygame.init()
screen = pygame.display.set_mode((length, width))
snake = snake(self) # create an instance
food = snake(food)
running = True
while running:
# handle every event since the last frame.
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit() # quit the screen
running = False
if snake.y > width or snake.y < 0 or snake.x > length or snake.x < 0: #Border Created
pygame.quit() # quit the screen
running = False
time.sleep(0.125)
snake.handle_keys() # handle the keys
screen.fill((0,0,0)) # fill the screen with white
snake.draw(screen) # draw the snake to the screen
snake.fooddrop(screen)
pygame.display.update() # update the screen
clock.tick(40)
Feel free to completely destroy my code because I am new and need to learn.
Thanks in advance!

You have to distinguish between Classes and instances of classes (objects).
Create a class Snake (or whatever name). Please use a leading capital letter for the name of the class to avoid confusions (see Style Guide for Python Code - Class Names).
The constructor of the class has 1 parameter (beside self), the name of the image:
class Snake(object):
def __init__(self, imagename):
self.image = pygame.image.load(imagename)
self.x = 0
self.y = 0
Create 2 instances of the class:
snake = Snake("head.png")
food = Snake("food.png")

Related

How to not initialize the def init every time

this code is by tech with tim but i am trying to tweak it, i am trying to make the rotation velocity vary everytime.
import pygame
import time
import math
from utility import scale_image, blit_rotate_center
rotation_speed=2
Joystickx=0
GRASS = scale_image(pygame.image.load("Sprites/grass.png"),2.5)
TRACK = scale_image(pygame.image.load("Sprites/track.png"),0.7)
TRACK_BORDER = scale_image(pygame.image.load("Sprites/track-border.png"),0.7)
Car = scale_image(pygame.image.load("Sprites/F1.xcf"),0.1)
FINISH=pygame.image.load("Sprites/finish.png")
WIDTH, HEIGHT= TRACK.get_width(), TRACK.get_height()
WIN = pygame.display.set_mode((WIDTH,HEIGHT))
pygame.display.set_caption("F1")
FPS = 60
class AbstractCar:
def __init__(self,max_vel,rotation_vel):
self.img=self.IMG
self.max_vel=max_vel
self.vel = 0
self.rotation_vel = rotation_vel
self.angle = 90
self.x, self.y = self.START_POS
def rotate(self, left=False, right=False):
if left:
self.angle += self.rotation_vel
print(self.angle)
elif right:
self.angle -= self.rotation_vel
print(self.angle)
def draw(self):
blit_rotate_center(WIN, self.img,(self.x, self.y), self.angle)
class PlayerCar(AbstractCar):
IMG = Car
START_POS = (180,200)
def draw(win,images, player_car):
for img, pos in images:
win.blit(img,pos)
player_car.draw()
pygame.display.update()
run=True
clock = pygame.time.Clock()
images = [(GRASS, (0,0)),(TRACK,(0,0))]
def rotate():
global rotation_speed
global Joystickx
rotation_speed+=2*Joystickx
rotation_speed*=0.9
while run:
clock.tick(FPS)
rotate()
player_car = PlayerCar(4, rotation_speed)
draw(WIN, images, player_car)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
break
keys = pygame.key.get_pressed()
if keys[pygame.K_a]:
player_car.rotate(left=True)
Joystickx=-1
elif keys[pygame.K_d]:
player_car.rotate(right=True)
Joystickx=1
else:
Joystickx=0
pygame.quit()
however, every time the class is ran, the code will set self.angle to 90, i do not want that to happen, what can i do to not let the def init run as that will set the self.angle to 94 instead remembering the last self.angle
This is OOP (Object Oriented Programming) thing. I really suggest you to look it up, it's not an easy topic at first, but it's also not that hard to understand everything in it, it's just the first time is hard.
So, the __init__ is the constructor of your AbstractCar class. This will always run when you make a new object from this class.
The simple way to fix this is to place the line where you define your car a bit above, outside the while loop and to keep the rotation_vel updated, we make a new method in the AbstractCar class and call it instead:
class AbstractCar:
def set_rotation_vel(self, new_rotation_vel):
self.rotation_vel = new_rotation_vel
[...]
player_car = PlayerCar(4, rotation_speed)
while run:
clock.tick(FPS)
rotate()
player_car.set_rotation_vel(rotation_speed)
draw(WIN, images, player_car)

I am trying to make enemies spawn over time in my python arcade game, but i get a simple error that makes no sense

im working on a game in python arcade, where the player runs around, shoots zombies, etc. very basic game. just recently, i started implementing the spawn over time part, but i get an error that just makes no sense:
AttributeError: 'MyGame' object has no attribute 'total_time'
it makes no sense because i have stated self.total_time in MyGame.
how do i fix this?
import arcade
import random
import math
import arcade.gui
import time
import timeit
SPRITE_SCALING = 0.35
SPRITE_SCALING_LASER = 0.8
SCREEN_WIDTH = 1280
SCREEN_HEIGHT = 720
SCREEN_TITLE = "zombier shooter"
ENEMY_COUNT = 20
BULLET_SPEED = 30
MOVEMENT_SPEED = 5
SPRITE_SPEED = 1
INDICATOR_BAR_OFFSET = 32
ENEMY_ATTACK_COOLDOWN = 1
PLAYER_HEALTH = 5
SCENE_MENU = 'SCENE_MENU'
SCENE_GAME = 'SCENE_GAME'
class QuitButton(arcade.gui.UIFlatButton):
def on_click(self, event: arcade.gui.UIOnClickEvent):
arcade.exit()
class Player(arcade.Sprite):
def update(self):
""" moves the player """
# move player.
self.center_x += self.change_x
self.center_y += self.change_y
# check for out of bounds
if self.left < 0:
self.left = 0
elif self.right > SCREEN_WIDTH - 1:
self.right = SCREEN_WIDTH - 1
if self.bottom < 0:
self.bottom = 0
elif self.top > SCREEN_HEIGHT - 1:
self.top = SCREEN_HEIGHT - 1
class Enemy(arcade.Sprite):
"""
This class represents the enemies on our screen.
"""
def follow_sprite(self, player_sprite):
"""
This function will move the current sprite towards whatever
other sprite is specified as a parameter.
"""
if self.center_y < player_sprite.center_y:
self.center_y += min(SPRITE_SPEED, player_sprite.center_y - self.center_y)
elif self.center_y > player_sprite.center_y:
self.center_y -= min(SPRITE_SPEED, self.center_y - player_sprite.center_y)
if self.center_x < player_sprite.center_x:
self.center_x += min(SPRITE_SPEED, player_sprite.center_x - self.center_x)
elif self.center_x > player_sprite.center_x:
self.center_x -= min(SPRITE_SPEED, self.center_x - player_sprite.center_x)
class MyGame(arcade.Window):
"""
main game class
"""
def __init__(self, width, height, title):
"""
initialises stuff
"""
# call the parent class initializer
super().__init__(width, height, title)
self.scene = SCENE_MENU
# variables that will hold sprite lists
self.player_list = None
# set up the player info
self.player_sprite = None
# track the current state of what key is pressed
self.left_pressed = False
self.right_pressed = False
self.up_pressed = False
self.down_pressed = False
# --- Required for all code that uses UI element,
# a UIManager to handle the UI.
self.manager = arcade.gui.UIManager()
self.manager.enable()
# Set background color
arcade.set_background_color(arcade.color.DARK_BLUE_GRAY)
# Create a vertical BoxGroup to align buttons
self.v_box = arcade.gui.UIBoxLayout()
# Create the buttons
start_button = arcade.gui.UIFlatButton(text="Start Game", width=200)
self.v_box.add(start_button.with_space_around(bottom=20))
settings_button = arcade.gui.UIFlatButton(text="Settings", width=200)
self.v_box.add(settings_button.with_space_around(bottom=20))
# Again, method 1. Use a child class to handle events.
quit_button = QuitButton(text="Quit", width=200)
self.v_box.add(quit_button)
# --- Method 2 for handling click events,
# assign self.on_click_start as callback
start_button.on_click = self.on_click_start
# --- Method 3 for handling click events,
# use a decorator to handle on_click events
#settings_button.event("on_click")
def on_click_settings(event):
print("Settings:", event)
# Create a widget to hold the v_box widget, that will center the buttons
self.manager.add(
arcade.gui.UIAnchorWidget(
anchor_x="center_x",
anchor_y="center_y",
child=self.v_box)
)
def setup(self):
""" Set up the game and initialize the variables. """
# sprite lists
self.player_list = arcade.SpriteList()
self.enemy_list = arcade.SpriteList()
self.bullet_list = arcade.SpriteList()
#setup timer
self.total_time = 0.0
# setup score
self.score = 0
self.score_text = None
# setup health info
self.health = 5
self.health_text = None
self.dead = None
# set up the player
self.player_sprite = Player(":resources:images/animated_characters/female_person/femalePerson_idle.png",
SPRITE_SCALING)
self.player_sprite.center_x = 50
self.player_sprite.center_y = 50
self.player_list.append(self.player_sprite)
def on_draw(self):
""" render the screen. """
# clear the screen
self.clear()
if self.scene == SCENE_MENU:
self.manager.draw()
elif self.scene == SCENE_GAME:
# draw all the sprites.
self.player_list.draw()
self.enemy_list.draw()
self.bullet_list.draw()
# put score text on the screen
output = f"Score: {self.score}"
arcade.draw_text(output, 10, 20, arcade.color.WHITE, 14)
# put helth text on the screen
output = f"Health: {self.health}"
arcade.draw_text(output, 10, 40, arcade.color.WHITE, 14)
if self.health <= 0:
self.player_sprite.remove_from_sprite_lists()
# put u died text on the screen
output = f"YOU DIED"
arcade.draw_text(output, 500, 400, arcade.color.RED, 50)
output = f"Click to Exit"
arcade.draw_text(output, 550, 300, arcade.color.BLACK, 30)
def on_click_start(self, event):
self.setup()
self.scene = SCENE_GAME
self.manager.disable()
print("Start:", event)
def on_mouse_press(self, x, y, button, modifiers):
""" Called whenever the mouse button is clicked. """
if self.health <= 0:
exit()
# create a bullet
bullet = arcade.Sprite(":resources:images/space_shooter/laserBlue01.png", SPRITE_SCALING_LASER)
# Position the bullet at the player's current location
start_x = self.player_sprite.center_x
start_y = self.player_sprite.center_y
bullet.center_x = start_x
bullet.center_y = start_y
# Get from the mouse the destination location for the bullet
# IMPORTANT! If you have a scrolling screen, you will also need
# to add in self.view_bottom and self.view_left.
dest_x = x
dest_y = y
# Do math to calculate how to get the bullet to the destination.
# Calculation the angle in radians between the start points
# and end points. This is the angle the bullet will travel.
x_diff = dest_x - start_x
y_diff = dest_y - start_y
angle = math.atan2(y_diff, x_diff)
# Angle the bullet sprite so it doesn't look like it is flying
# sideways.
bullet.angle = math.degrees(angle)
print(f"Bullet angle: {bullet.angle:.2f}")
# Taking into account the angle, calculate our change_x
# and change_y. Velocity is how fast the bullet travels.
bullet.change_x = math.cos(angle) * BULLET_SPEED
bullet.change_y = math.sin(angle) * BULLET_SPEED
# Add the bullet to the appropriate lists
self.bullet_list.append(bullet)
def update_player_speed(self):
# calculate speed based on the keys pressed
self.player_sprite.change_x = 0
self.player_sprite.change_y = 0
if self.up_pressed and not self.down_pressed:
self.player_sprite.change_y = MOVEMENT_SPEED
elif self.down_pressed and not self.up_pressed:
self.player_sprite.change_y = -MOVEMENT_SPEED
if self.left_pressed and not self.right_pressed:
self.player_sprite.change_x = -MOVEMENT_SPEED
elif self.right_pressed and not self.left_pressed:
self.player_sprite.change_x = MOVEMENT_SPEED
def on_update(self, delta_time):
""" updates values n stuff """
if self.scene == SCENE_GAME:
# call update to move the sprite
self.player_list.update()
# Call update on all sprites
self.bullet_list.update()
# go through each bullet
for bullet in self.bullet_list:
# check each bullet to see if it hit a zombie
hit_list = arcade.check_for_collision_with_list(bullet, self.enemy_list)
# if it did, remove the bullet
if len(hit_list) > 0:
bullet.remove_from_sprite_lists()
# for each enemy we hit with a bullet, remove enemy and add to the score
for enemy in hit_list:
enemy.remove_from_sprite_lists()
self.score += 1
# if bullet goes off screen, then remove it
if bullet.bottom > self.width or bullet.top < 0 or bullet.right < 0 or bullet.left > self.width:
bullet.remove_from_sprite_lists()
for enemy in self.enemy_list:
Enemy.follow_sprite(enemy, self.player_sprite)
# create a list of all sprites that had a collision with the player.
hit_list = arcade.check_for_collision_with_list(self.player_sprite, self.enemy_list)
# go through each sprite, if it got hit, then remove the sprite and lower score and health
for enemy in hit_list:
enemy.remove_from_sprite_lists()
self.score -= 1
self.health -= 1
# Accumulate the total time
self.total_time += delta_time
# Calculate minutes
minutes = int(self.total_time) // 60
# Calculate seconds by using a modulus (remainder)
seconds = int(self.total_time) % 60
# Calculate 100s of a second
seconds_100s = int((self.total_time - seconds) * 100)
if self.total_time > 5:
for i in range(5):
# enemy texture
enemy = arcade.Sprite(":resources:images/animated_characters/zombie/zombie_idle.png", SPRITE_SCALING)
enemy.center_x = random.randrange(SCREEN_WIDTH)
enemy.center_y = random.randrange(SCREEN_HEIGHT)
self.enemy_list.append(enemy)
self.total_time = 0.0
def on_key_press(self, key, modifiers):
"""called when user presses a key. """
if key == arcade.key.UP:
self.up_pressed = True
self.update_player_speed()
elif key == arcade.key.DOWN:
self.down_pressed = True
self.update_player_speed()
elif key == arcade.key.LEFT:
self.left_pressed = True
self.update_player_speed()
elif key == arcade.key.RIGHT:
self.right_pressed = True
self.update_player_speed()
def on_key_release(self, key, modifiers):
"""called when user releases a key. """
if key == arcade.key.UP:
self.up_pressed = False
self.update_player_speed()
elif key == arcade.key.DOWN:
self.down_pressed = False
self.update_player_speed()
elif key == arcade.key.LEFT:
self.left_pressed = False
self.update_player_speed()
elif key == arcade.key.RIGHT:
self.right_pressed = False
self.update_player_speed()
def main():
""" Main function """
MyGame(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_TITLE)
arcade.run()
if __name__ == "__main__":
main()
You defined self.total_time in setup() and not in __init__(), which should be a red-flag, because it could happen that self.total_time is actually accessed before setup() is called. And exactly this happened.
The error appears in on_update() when you try to run self.total_time += delta_time - in order for this line to work, self.total_time has to be initialised before - but setup() wasn't executed before, so self.total_time 'does not exist' yet.
So you can fix your code by moving the line self.total_time = 0.0 from setup() to __init__() - this way you make sure that you create this variable once the class gets initialised and before anything else gets executed.
If you plan on using variables in a class across different methods it's better to define them in __init__() to avoid such problems.

How to call a particular object's method and have affect only on that object which is a value of a key of a dictionary in pygame?

I am a new learner of programming. I am practiceing python and writing a litle game using pygame. I have ten circle on the pygame window and each have a counter. I want to increase the counter by 1 when it's circle is clicked. I first created group using .sprite.Group(), but I could not get the desired result. Because then the counter does not even get update. So I create two list, one for the circle and one for the counter. And for each circle in the circle list I created a dictionary taking the circle as the key and each counter in the circle list is the value of the circle. Now when the circle got clicked then the all counter gets updated, not the counter that the circle holds. But goal is to get the specific counter updated for it's circle.
(hole == circle)
dig_hole.py(This is the main file.)
import pygame
import sys
from pygame.sprite import Group
from counter import Counter
from hole import Hole
from settings import Settings
class DigHole:
def __init__(self):
pygame.init()
self.settings = Settings()
self.screen = pygame.display.set_mode((self.settings.screen_width, self.settings.screen_height))
pygame.display.set_caption("Dig Hole")
pygame.display.set_icon(Hole(self).image)
self.count = Counter(self)
self.counter_group = list()
self.holes = list()
self.dict = dict()
self._create_holes()
self.hole = Hole(self)
self.mouse_pos = (0, 0)
def run_dig_hole(self):
while True:
self._check_events()
self._update_screen()
def _check_events(self):
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_q:
sys.exit()
elif event.type == pygame.MOUSEBUTTONDOWN:
self.mouse_pos = pygame.mouse.get_pos()
self._check_hole_clicked_events(self.mouse_pos)
def _check_hole_clicked_events(self, mouse_pos):
for key in self.dict:
if key.rect.collidepoint(mouse_pos):
self.dict[key].count_clock += 1
self.dict[key].prep_counter()
self.count.prep_counter()
def _create_holes(self):
for row_number in range(2):
for hole_number in range(5):
self._create_hole(row_number, hole_number)
for hole in self.holes:
counter = Counter(self)
counter.counter_rect.midbottom = hole.rect.midtop
self.counter_group.append(counter)
for hole in self.holes:
for counter in self.counter_group:
self.dict[hole] = counter
def _create_hole(self, row_number, hole_number):
hole = Hole(self)
hole_width, hole_height = hole.rect.size
available_space_x = self.settings.screen_width - (2 * hole_width)
available_space_y = self.settings.screen_height - (2 * hole_height)
hole.x =(((available_space_x // 5) - hole_width) // 2) + (available_space_x // 5) * hole_number
hole.rect.x = hole.x
hole.rect.y = 2 * hole.rect.height + (available_space_y - (4 * hole_height)) * row_number
self.holes.append(hole)
def _update_screen(self):
self.screen.fill(self.settings.bg_color)
for key in self.dict:
key.draw()
for key in self.dict:
self.dict[key].counter_rect.midbottom = key.rect.midtop
self.dict[key].show_counter()
self.count.show_counter()
pygame.display.flip()
if __name__ == '__main__':
dh = DigHole()
dh.run_dig_hole()
hole.py
import pygame
from pygame.sprite import Sprite
class Hole():
def __init__(self, dh):
# super().__init__()
self.screen = dh.screen
self.image = pygame.image.load("images/circle.bmp")
self.rect = self.image.get_rect()
self.rect.x = self.rect.width
self.rect.y = self.rect.height
self.x = float(self.rect.x)
def draw(self):
self.screen.blit(self.image, self.rect)
counter.py
import pygame.font
from pygame.sprite import Sprite
class Counter():
def __init__(self, dh):
# super().__init__()
self.screen = dh.screen
self.screen_rect = self.screen.get_rect()
self.settings = dh.settings
self.count_clock = 0
self.text_color = (30, 30, 30)
self.font = pygame.font.SysFont(None, 48)
self.prep_counter()
def prep_counter(self):
counter_str = str(self.count_clock)
self.counter_image = self.font.render(counter_str, True, self.text_color, self.settings.bg_color)
self.counter_rect = self.counter_image.get_rect()
self.counter_rect.right = self.screen_rect.right - 20
self.counter_rect.top = 20
def show_counter(self):
self.screen.blit(self.counter_image, self.counter_rect)
Thank you.This is the window of the progeam. Here all circles are gets update but one is clicked.
The issue is that, in _create_holes, you set the counters of each circle to be the same Counter object.
for hole in self.holes:
for counter in self.counter_group:
self.dict[hole] = counter
Unrolling the inner loop, this is the same as
for hole in self.holes:
self.dict[hole] = self.counter_group[0]
self.dict[hole] = self.counter_group[1]
self.dict[hole] = self.counter_group[2]
...
self.dict[hole] = self.counter_group[-1]
The first assignments are all immediately overwritten, so this code is setting every self.dict value to self.counter_group[-1]. What you want to do instead is
for hole, counter in zip(self.holes, self.counter_group):
self.dict[hole] = counter
which iterates over both self.holes and self.counter_group simultaneously. In your case, you can actually rewrite this as
self.dict = dict(zip(self.holes, self.counter_group))
which is nicer.
I’m not sure, but I think you intend self.count to be a total. If this is the case, it won’t quite work: you’re missing a line from _check_hole_clicked_events. It should look like this:
def _check_hole_clicked_events(self, mouse_pos):
for key in self.dict:
if key.rect.collidepoint(mouse_pos):
self.dict[key].count_clock += 1
self.dict[key].prep_counter()
self.count.count_clock += 1
self.count.prep_counter()
As a side note, I noticed you also wrote list() and dict() to create empty lists and dicts. It’s more efficient and idiomatic just to write literals ([] and {}).

Is there a way to change my_sprite or my_group to change the animation displayed?

I'm making animated sprites in pygame, and would like help finding a way to flip from one to the other? The current code looks something like this:
class normal(pygame.sprite.Sprite):
def __init__(self):
#etc, list of images to create the animation
class tall(pygame.sprite.Sprite):
def __init__(self):
#rinse and repeat with a different set of images
I already have an idea for how to trigger the change via keystroke. But I'm not sure which variable to change, and to what. When I try to change with the following code, nothing happens
fps = 25
pygame.init()
my_sprite = normal()
my_group = pygame.sprite.Group(my_sprite)
#etc until we get to the part where it changes
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_RETURN:
if my_sprite == normal():
my_sprite = tall()
fps = 30
else:
my_sprite = normal()
fps = 25
I'm not sure exactly what isn't working in my code as it doesn't come back with an error. Can someone point me in the right direction?
It's not working because when the code calls normal() it's creating a new instance of an object. So the call:
if my_sprite == normal():
Is saying "is my existing sprite object == this new sprite object", which is never true. You can use the python function to type() of the object to do the same thing, or add your own type-function as I have presented in the code below.
I would track the state of the sprite inside the class, and use some functions grow() and shrink() to change the size automatically.
class GrowingSprite( pygame.sprite.Sprite, x, y ):
def __init__( self ):
#etc, list of images to create the animation
self.image_short = ... # load "short" image
self.image_tall = ... # load "tall" image
# Set the initial state
self.image = self.image_short # start short
self.rect = self.image.get_rect()
self.rect.centerx = x
self.rect.centery = y
self.state = 'short'
def getState( self ):
return self.state
def grow( self ):
self.state = 'tall'
self.image = self.image_tall
current_x = self.rect.centerx # preserve existing location
current_y = self.rect.centery
self.rect = self.image.get_rect()
self.rect.center = ( current_x, current_y )
def shrink( self ):
self.state = 'short'
self.image = self.image_short
current_x = self.rect.centerx # preserve existing location
current_y = self.rect.centery
self.rect = self.image.get_rect()
self.rect.center = ( current_x, current_y )
I found a workaround that is a bit redundant, but it makes it possible to expand it in case there are more groups
It requires making two groups that can be pulled back and fourth, and changing the foo.draw(screen) to the new group. This is how it looks
nml_sprite = normal()
tal_sprite = tall()
tg = 1 #this is nothing more than a switch to trigger the change
tal_group = pygame.sprite.Group(tal_sprite)
nml_group = pygame.sprite.Group(nml_sprite)
cursprite = nml_group #this variable determines which sprite set is loaded
...
...
if event.key == pygame.K_RETURN:
if tg == 1:
curspt = tal_group
tg = 2
else:
curspt = nml_group
tg = 2
...
...
nml_group.update()
tal_group.update()
curspt.draw(screen)
...

I cant figure out this space key and attack animation

I decided to add the attack images into the walking ones to see what happened and I got them to load up.
I have been attempting to break it down and piece it back together to try and find what I have been doing wrong and it may be an issue of my experience.
I have butchered my code trying to figure this out after someone gave me an explanation about my classes. I thought maybe I should try and set it up as global, and then I realize there's something I'm not doing right. I don't want someone to just write the code for me I should mention. But an explanation for why I am screwing up would be nice.
Some tutorials are helping me but not as much as when someone tells me where specifically where I went wrong. I think I made more progress there.
##a simple punch without the whole animation atm
class attacks(object):
attack = pygame.image.load("atk3.png")
def __init__(self, x, y, width, height, attack):
self.x = x
self.y = y
self.width = width
self.height = height
self.attackCount = 0
def draw(self, win):
## is it my redraw method?
if (self.attack):
if self.attackCount + 1 >= 9:
win.blit(attack, self.attackCount//3(self.x, self.y))
self.attackCount += 1
So with the class set up here im sure that something is wrong, ive been diving through forums and I know something is not right. I dont know what though.
def redrawGameWindow():
global walkCount
global attackCount
win.blit(bg, (0, 0))
if walkCount +1 >= 27:
walkCount = 0
bob.draw(win)
jerk.draw(win)
for attack in attacks:
attack.draw(win)
pygame.display.update()
#While true
#This calls the classes created
bob = player(100, 200, 128, 128)
jerk = enemy(500, 200, 164, 100, 600)
attacks = []
run = True
while run:
clock.tick(30)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
keys = pygame.key.get_pressed()
#attempting to make this into a bool that changes the value
if not(bob.attacking):
if keys[pygame.K_SPACE]:
bob.attacking = True
bob.standing = False
bob.left = False
bob.right = False
if keys[pygame.K_LEFT] and bob.x > bob.vel:
bob.x -= bob.vel
bob.left = True
bob.right = False
bob.standing = False
elif keys[pygame.K_RIGHT] and bob.x < 800 - bob.width - bob.vel:
bob.x += bob.vel
bob.right = True
bob.left = False
bob.standing = False
else:
bob.standing = True
bob.walkCount = 0
if not(bob.isJump):
if keys[pygame.K_UP]:
bob.isJump = True
bob.right = False
bob.left = False
bob.walkCount = 0
else:
if bob.jumpCount >= -10:
neg = 1
if bob.jumpCount < 0:
neg = -1
bob.y -= (bob.jumpCount ** 2) * 0.5 * neg
bob.jumpCount -= 1
else:
bob.isJump = False
bob.jumpCount = 10
redrawGameWindow()
pygame.quit()
Im almost sure my True loop has nothing to do with it now since im able to run walk and jump. And when I press space it loads a frame thats not an attack one so i know for sure something is happening when I hit space
one of the errors I have found is that you are telling pygame to load multiple images however, you have only loaded one
class attacks(object):
attack = pygame.image.load("atk3.png")#< ----- you are only loading one
def __init__(self, x, y, width, height, attack):
#[...]
and you are telling it to go in a cycle to blit different images in a group
def draw(self, win):
## is it my redraw method?
if (self.attack):
if self.attackCount + 1 >= 9:
win.blit(attack, self.attackCount//3(self.x, self.y))# you only have one image yet you are trying to blit multiple
self.attackCount += 1
another error is your attack varible. to know when you luanch an attack you do it like this
class attacks(object):
attack = pygame.image.load("atk3.png")
def __init__(self, x, y, width, height,#attack <----- this attack shoudnt be here):
self.x = x
self.y = y
self.width = width
self.height = height
self.attackCount = 0
self.punchisluacnhed = false
def draw(self, win):
if (self.punchisluacnhed):
if self.attackCount + 1 >= 9:
win.blit(self.attack, self.attackCount//3(self.x, self.y))
self.attackCount += 1
#B.T.W the attack image in the draw function should have self before it since you called it in a class not in the initilization i.e import pygame etc
If you want the character to punch when a button is pressed you would put it in a function like this
if keys[pygame.K_SPACE]:
bob.punchisluacnhed = True
bob.standing = False
bob.left = False
bob.right = False
to tell it to stop you put an else stateent an set every thing to false except from the standing value

Categories