Pygame Animation Trouble - python

I am trying to animate a wizard walking to the left when holding down the left arrow key and walking to the right when holding down the right arrow key. The problem: I don't know how to assign a variable to the whole class.
Here is the error:
Traceback (most recent call last):
File "C:\Python27\Wizard Game\wizard game", line 18, in <module>
class player_standing_right(object):
File "C:\Python27\Wizard Game\wizard game", line 61, in player_standing_right
screen.blit(player_spr, player_rect)
NameError: name 'player_spr' is not defined
Here is my code:
import sys, pygame
pygame.init()
size = (640, 480)
screen = pygame.display.set_mode(size)
gamerunning = True
def load_image(name):
image = pygame.image.load(name)
return image
clock = pygame.time.Clock()
while gamerunning == True:
white = (255, 255, 255)
clock.tick(30)
screen.fill(white)
class player_standing_right(object):
def __init__(self):
self.player_spr = player_spr
player_spr = load_image("wizard right 0.bmp")
x = 0
player_right = [load_image("wizard right 0.bmp"), load_image("wizard right 1.bmp"), load_image("wizard right 0.bmp")]
player_left = [load_image("wizard left 0.bmp"), load_image("wizard left 1.bmp"), load_image("wizard left 0.bmp")]
def key_press(keypressed):
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == keypressed:
return True
def key_release(keyreleased):
for event in pygame.event.get():
if event.type == pygame.KEYUP:
if event.key == keyreleased:
return True
if key_press(pygame.K_LEFT):
player_spr = player_left[x]
while key_press(pygame.K_LEFT):
player_rect = player_rect.move(-1, 0)
x += 1
if x == len(player_left):
x = 0
player_spr = player_left[x]
if key_press(pygame.K_RIGHT):
player_spr = player_right[x]
while key_press(pygame.K_RIGHT):
player_rect = player_rect.move(1, 0)
x += 1
if x == len(player_right):
x = 0
player_spr = player_right[x]
screen.blit(player_spr, player_rect)
pygame.display.flip()

You assigned player_spr when key is left and right, but you didn't assign it on "idle" state. When you're starting game you're not pressing any key, thus sprite is not assigned. You did it before class definition. You can try to put it inside. Also I'm not an expert but I would define class outside the actual main loop.

#TRY USING THIS METHOD
class AnimationClass():
def __init__(self):
self.x = 0
self.y = 0
self.frame_count = 0
self.image_list = []
def update(self):
self.frame_count += 1
for num in range(1,5): # SET THE NUM OF FRAMES
image = pygame.image.load(f"YOURE IMAGE FILE{num}.png") # loading youre image file
self.image_list.append(image) # appending youre image file
window.blit(self.image_list[int(self.frame_count)],(self.x , self.y)) # rendering youre image
animation = AnimationClass()
Loop = True
while Loop == True:
for event in pygame.event.get():
if event.type == pg.QUIT:
Loop = False
animation.update() # CALLING THE UPDATE IN LOOP
pygame.display.update()

Related

Pygame drawing a certain number of objects on the screen at a time

I wanted to make a simple dance game using pygame.
class Sword():
def __init__(self, image, speed, center):
self.image = pygame.image.load(image)
self.rect = self.image.get_rect()
self.rect.center = center
self.speed = speed # object speed
self.alive = True # draw object if not hit the enemey
def live(self, enemy): # check if hit the enemy
if self.rect.colliderect(enemy):
self.alive = False
mixer.music.play()
def update(self): # move object
self.rect.x += self.speed
def draw(self, surface): # draw object
if self.alive:
surface.blit(self.image, (self.rect))
I can draw and move my object on the screen.
sword = [Sword('sword.png',1,(100,420))],
[Sword('sword.png',5,(200,420))],
[Sword('sword.png',3,(300,420))]]
while (True):#Mainloop
kare = pygame.draw.rect(display,((255,0,0)), pygame.Rect(700,420,100,100))
for i, tile in sorted(enumerate(sword), reverse=True):
tile.update()
tile.live(kare)
tile.draw()
if not tile.live:
sword.pop(i)#delete object
my code works flawlessly so far;=)
but when I want to draw 4 objects on the screen every time, things don't go as I want.
def main():
extend = []
running = True
while running:
if len(extend) >= 3:
running = False
else:
for i in range(4):
extend.append(Sword('sword.png',1,(100,420)))
return extend
i have a simple function to draw 4 objects at a time to the screen but when i use this in my main loop my objects don't move
while True:
sword = main()#call function
kare = pygame.draw.rect(display,((255,0,0)), pygame.Rect(700,420,100,100))
for i, tile in sorted(enumerate(sword), reverse=True):
tile.update()
tile.live(kare)
tile.draw(display)
if not tile.alive:
sword.pop(i)
First of all, I apologize for this long post, but I wanted the topic to be clear, how do I edit my code so that there are 4 on the screen each time?
Thank you for your interest...
Here is the full code of the solution:
import pygame, sys, math, random
from pygame import mixer
from pygame.locals import *
mainClock = pygame.time.Clock()
pygame.init()
pygame.display.set_caption('game base')
WINDOW_SIZE = (980,570)
screen = pygame.display.set_mode((WINDOW_SIZE), 0, 32)
display = pygame.Surface((WINDOW_SIZE))
RIGHT_KEY,UP_KEY,LEFT_KEY,DOWN_KEY = False,False,False,False
class Sword():
def __init__(self, image, speed, center):
self.image = pygame.image.load(image)
self.rect = self.image.get_rect()
self.rect.center = center
self.speed = speed
self.alive = True
def live(self, enemy):
if self.rect.colliderect(enemy):
self.alive = False
#mixer.music.play()
def update(self):
self.rect.x += self.speed
def draw(self, surface):
if self.alive:
surface.blit(self.image, (self.rect))
def main():
extend = []
running = True
if len(extend) >= 3:
running = False
while running:
if len(extend) >= 4:
running = False
else:
for i in range(5):
extend.append(Sword('sword.png',i,(100,420)))
return extend
sword = main()
while True:
display.fill((250,198,14))
kare = pygame.draw.rect(display,((255,0,0)), pygame.Rect(700,420,100,100))
all_not_alive = True
for tile in sword:
tile.update()
tile.live(kare)
tile.draw(display)
if not tile.alive:
tile.rect.x = 100
tile.alive = True
# Buttons ------------------------------------------------ #
RIGHT_KEY,UP_KEY,LEFT_KEY,DOWN_KEY = False,False,False,False
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
pygame.quit()
sys.exit()
if event.key == pygame.K_UP:
UP_KEY = True
if event.key == pygame.K_DOWN:
DOWN_KEY = True
if event.key == pygame.K_LEFT:
LEFT_KEY = True
if event.key == pygame.K_RIGHT:
RIGHT_KEY = True
# Update -------------------------------------------------
screen.blit(display,(0,0))
pygame.display.update()
mainClock.tick(60)
The problem was that you have recreated all swords every time when the game updated. You should recreate the sword only if it is not alive.
EDIT
I have moved the code which generates the Swords out of the loop:
sword = main()
and I am moving all swords to the start after they collide:
if not tile.alive:
tile.rect.x = 100
tile.alive = True

How to stop images from looping through a list

I am making a match-3 style game. I am a beginner with pygame and have managed to randomly generate a board so that each playthrough is different. My only issue at the moment is my tiles seem to be continuously cycling through the list I created for each image. I tried adding a for loop to delete each element as it is being generated but nothing I seem to change is working. Could anybody help? You can find the images I used in a google drive! I appreciate anything!
GoogleDrive
import pygame
from pygame.locals import *
import math
import time
import sys
import random
pygame.init()
# game variables
display_h = 900
display_w = 750
game_row = 12
game_column = 10
background_img = pygame.image.load('pink_background_resized.png')
clock = pygame.time.Clock()
running = True
# build screen and window name
screen = pygame.display.set_mode((display_w, display_h))
pygame.display.set_caption("Jelliez")
screen.fill((255,255,255))
class Tile():
# initialize tiles
def __init__(self, x, y, image, clicked):
self.image = image
self.rect = self.image.get_rect()
self.rect.topleft = (x,y)
self.clicked = clicked
def draw(self):
action = False
# get mouse position
pos = pygame.mouse.get_pos()
# check mouse over and clicked psotion
if self.rect.collidepoint(pos):
if (pygame.mouse.get_pressed()[0] == 1) and (self.clicked == False):
self.clicked = True
action = True
if pygame.mouse.get_pressed()[0] == 0:
self.clicked = False
screen.blit(self.image, (self.rect.x, self.rect.y))
return action
def generateBoard():
screen.blit(background_img, (0,0))
return [[image_list[random.randrange(0, len(image_list))] for i in range (game_column)] for x in range(game_row)]
def showBoard(board):
screen.blit(background_img, (0,0))
rowNum = 0
for row in board:
columnNum = 0
for shape in row:
screen.blit(shape, (70 * columnNum, 64 * rowNum ))
columnNum += 1
rowNum += 1
# add game images
blue_jelly_img = pygame.image.load('blue_jelly.png').convert_alpha()
gray_jelly_img = pygame.image.load('gray_jelly.png').convert_alpha()
green_jelly_img = pygame.image.load('green_jelly.png').convert_alpha()
pink_jelly_img = pygame.image.load('pink_jelly.png').convert_alpha()
red_jelly_img = pygame.image.load('red_jelly.png').convert_alpha()
yellow_jelly_img = pygame.image.load('yellow_jelly.png').convert_alpha()
# create tile istances
blue_jelly = Tile(100, 231, blue_jelly_img, False)
gray_jelly = Tile(100, 231, gray_jelly_img, False)
green_jelly = Tile(100, 231, green_jelly_img, False)
pink_jelly = Tile(100, 231, pink_jelly_img, False)
red_jelly = Tile(100, 231, red_jelly_img, False)
yellow_jelly = Tile(100, 231, yellow_jelly_img, False)
image_list = [blue_jelly_img, gray_jelly_img, green_jelly_img, pink_jelly_img, red_jelly_img, yellow_jelly_img]
for x in range(len(image_list) - 6):
del(image_list[0])
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
gameBoard = generateBoard()
showBoard(gameBoard)
pygame.display.update()
pygame.quit()
The problem is that the board is recreated every frame.
Generate the board once before the application loop. Clear the display and show the board in the application loop:
gameBoard = generateBoard()
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
screen.blit(background_img, (0,0))
showBoard(gameBoard)
pygame.display.update()
pygame.quit()

Pygame Output : Black Background

I want to view my blit() however once i add the line self.screen_dim.fill([255, 255, 255])
pygame.display.update() it overlaps
def __init__(self):
self.width = 500
self.height = 500
self.screen_dim = pygame.display.set_mode((self.width, self.height))
self.mole = pygame.image.load("mole.png")
self.mole_hit = pygame.image.load("mole-hit.png")
I am confused on how to get my pygame screen the images within that function is working however it overlaps if i added a new background color
def start(self):
stat = True
num_display = 1
x_array = []
y_array = []
for i in self.mole_pos:
x_array.append(i[0])
y_array.append(i[1])
while stat:
Rand_Pos = random.randint(0, 8)
if num_display == 1:
self.screen_dim.blit(self.mole, (x_array[Rand_Pos], y_array[Rand_Pos]))
for Event in pygame.event.get():
if Event.type == pygame.QUIT:
stat = False
if self.mouse_clicked(mouse.get_pos(), self.mole_pos[Rand_Pos]):
num_display = 0
self.screen_dim.blit(self.mole_hit, (x_array[Rand_Pos], y_array[Rand_Pos]))
continue
pygame.display.flip()
This ahs nothing to to with class. It is just a matter of Indentation. You have to draw self.mole_hit in the application loop rather than the event loop:
def start(self):
# [...]
while stat:
# [...]
for Event in pygame.event.get():
if Event.type == pygame.QUIT:
stat = False
#<--| INDENTATION
if self.mouse_clicked(mouse.get_pos(), self.mole_pos[Rand_Pos]):
num_display = 0
self.screen_dim.blit(self.mole_hit, (x_array[Rand_Pos], y_array[Rand_Pos]))
pygame.display.flip()

Using pygame, how can I update an object's position that is defined by a class

I'm trying to build the Google Dinosaur game in Python. I have
class Dino():
def __init__(self, posy):
self.score = 0
self.isDead = False
self.isJumping = False
self.isDucking = False
self.pos = (100, posy)
def draw(self):
dinoImport = pygame.image.load("assets\dino1.png")
dino = pygame.transform.scale(dinoImport, (50,50))
screen.blit(dino, self.pos)
Then I have the main function where the game actually runs.
def gameplay():
global flag
flag = True
color = (255,255,255)
y = 300
playerDino = Dino(y)
gamespeed = 4
ground = Ground(-1*gamespeed)
while flag:
screen.fill(color)
ground.draw()
playerDino.draw()
pygame.display.flip()
events = pygame.event.get()
for event in pygame.event.get():
if event.type==pygame.QUIT:
pygame.quit()
exit(0)
keys = pygame.key.get_pressed()
if keys[pygame.K_s]:
pass
if keys[pygame.K_w]:
y += 3
playerDino.draw()
pygame.display.update()
Everything is placed correctly, but when I press the w key, the y position of the dino doesn't move up by 3, it doesn't move. What exactly am I missing here?
The coordinates of the dino are stored in a tuple on the attribute pos. You have to change the tuple attribute rather than y:
y += 3
playerDino.pos = (playerDino.pos[0], playerDino.pos[1] + 3)
Anyway, I recommend to use a pygame.Rect object for the position of the dino. You can get the rectangle form the pygame.Surface object, by get_rect. Load the Surface in the constructor of Dino, rather than in every frame:
class Dino():
def __init__(self, posy):
self.score = 0
self.isDead = False
self.isJumping = False
self.isDucking = False
dinoImport = pygame.image.load("assets\dino1.png").convert_alpha()
self.image = pygame.transform.scale(dinoImport, (50,50))
self.rect = self.image.get_rect(topleft = (100, posy))
def draw(self):
screen.blit(self.image, self.rect)
The position of playerDino can be changed by changing the rect attribute. Your event loop wont work, because of the multiple calls pygame.event.get(). Since pygame.event.get() removes the events from the queue, the 2nd call won't return any event. Remove the first call of pygame.event.get():
def gameplay():
global flag
color = (255,255,255)
playerDino = Dino(300)
gamespeed = 4
ground = Ground(-1*gamespeed)
clock = pygame.time.Clock()
flag = True
while flag:
clock.tick(60)
for event in pygame.event.get():
if event.type==pygame.QUIT:
flag = False
keys = pygame.key.get_pressed()
if keys[pygame.K_s]:
pass
if keys[pygame.K_w]:
playerDino.rect.y += 3
screen.fill(color)
ground.draw()
playerDino.draw()
pygame.display.flip()
pygame.quit()
exit(0)

How do you add collision and make my foes to go slower in Pygame?

I made a game where the player has to dodge things called foes. I have tried doing the collision but have had no luck with it and I am not sure how to get the foes to go slower. The following is what I have so far:
import pygame,random, sys
from pygame.locals import *
from Player import *
from Person import *
from Badies import *
def terminate():
pygame.quit()
sys.exit()
def writeText(window, written, cenX, cenY):
font = pygame.font.Font(None, 48)
text = font.render(written, 1, TEXTCOLOR)
textpos = text.get_rect()
textpos.centerx = cenX
textpos.centery = cenY
window.blit(text, textpos)
return (textpos)
def waitForPlayerToPressKey():
while True:
for event in pygame.event.get():
if event.type == QUIT:
terminate()
if event.type == KEYDOWN:
if event.key == K_ESCAPE: # pressing escape quits
terminate()
return
def playerHitFoes(playerRect, foes):
for f in foes:
if guy.getRect(f['rect']):
return True
return False
pygame.init()
screen = pygame.display.set_mode((800,600))
pygame.key.set_repeat(1, 1)
font = pygame.font.SysFont(None, 48)
WINDOWWIDTH = 800
WINDOWHEIGHT = 600
TEXTCOLOR = (255, 255, 255)
FPS = 40
BADDIEMAXSIZE = 35
BADDIEMINSIZE = 35
BADDIEMAXSPEED = 10
BADDIEMINSPEED = 10
ADDNEWFOESRATE = 6
PLAYERMOVERATE = 5
changedRecs=[]
BACKGROUNDCOLOR = (255, 255, 255)
gameWin = False
win=False
score = 0
windowSurface = pygame.display.set_mode((WINDOWWIDTH, WINDOWHEIGHT))
guy = Player(400, 525)
foes = Badies()
playerRect = getRec(guy)
foess = pygame.image.load('Bad.png')
writeText(screen,"How to Play?" , 400,100)
writeText(screen,"*Help Mario dodge the squares", 400,150)
writeText(screen,"*Controls: Up, Down, Left, Right.", 400,200)
writeText(screen,"(Press Any Key to Start.)", 400,250)
pygame.display.update()
waitForPlayerToPressKey()
gameEnd = foes.drawAndCollision(screen, guy)
pygame.display.update()
gameEnd = foes.drawAndCollision(screen, guy)
WHITE = (255,255,255)
screen.fill(WHITE)
pygame.display.update()
while True:
# set up the start of the game
foes= []
score = 0
moveLeft = moveRight = moveUp = moveDown = False
r = s = False
foesAddCounter = 0
while True: # the game loop runs while the game part is playing
score += 1 # increase score
for event in pygame.event.get():
if event.type == QUIT:
terminate()
if event.type == KEYDOWN:
if event.key == K_LEFT:
guy.moveLeft()
if event.key == K_RIGHT:
guy.moveRight()
if event.key == K_UP:
guy.moveUp()
if event.key == K_DOWN:
guy.moveDown()
if not r and not s:
foesAddCounter += 1
if foesAddCounter == ADDNEWFOESRATE:
foesAddCounter = 0
baddieSize = BADDIEMAXSIZE
newFoes = {'rect': pygame.Rect(random.randint(0, WINDOWWIDTH-baddieSize), 0 - baddieSize, baddieSize, baddieSize),
'speed': BADDIEMAXSPEED,
'surface':pygame.transform.scale(foess, (baddieSize, baddieSize)),
}
foes.append(newFoes)
for f in foes:
if not r and not s:
f['rect'].move_ip(0, f['speed'])
elif reverseCheat:
f['rect'].move_ip(0, -5)
elif slowCheat:
f['rect'].move_ip(0, 1)
for f in foes[:]:
if f['rect'].top > WINDOWHEIGHT:
foes.remove(f)
screen.fill(BACKGROUNDCOLOR)
writeText(screen,"Score: %s" % (score), 10, 0)
guy.draw(screen)
for f in foes:
windowSurface.blit(f['surface'], f['rect'])
pygame.display.update()
if playerHasHitBaddie(playerRect, baddies):
writeText(screen, "Game Over!", 400,300)
break
pygame.display.update()
This next part is the Player File:
import pygame
from pygame.locals import *
class Player:
# set all class variables in the constructor
def __init__(self, newX, newY):
self.x = newX
self.y = newY
# Add images to the list of images
self.images = [ "Player.gif", "PlayerR.gif","PlayerR.gif", "Player.gif"]
# Use this to keep track of which image to use
self.cos = 0
# draw your person with the correct image
def draw(self, window):
window.blit( pygame.image.load( self.images[ self.cos ] ),
(self.x,self.y))
# move person left and set the costume facing left.
def moveLeft(self):
self.x -= 1
self.cos = 3
# move person right and set the costume facing right
def moveRight(self):
self.x += 1
self.cos = 2
# move person up and set the costume facing up
def moveUp(self):
self.y -= 1
self.cos = 1
# move person down and set the costume facing down
def moveDown(self):
self.y += 1
self.cos = 0
def playerHitFoes(playerRect, foes):
for f in foes:
if playerRect.colliderect(f['rect']):
return True
def playerHasHitHeart(playerRect, foes):
for h in heart:
if playerRect.colliderect(h['rect']):
return True
def collide(self, other):
myRec = self.getRec
otherRec = other.getRec()
oRight = otherRec[0] + otherRec[2]
oBottom = otherRec[1] + otherRec[3]
right = myRec[0] + myRec[2]
bottom = myRec[1] + myRec[3]
if (otherRec[0] <= right) and (oRight >= self.x) and (otherRec[1] <= bottom) and (oBottom >= self.y):
return True
return False
def getRec(self):
myRec = pygame.image.load( self.images[ self.cos ] ).get_rect()
return (self.x, self.y, myRec[2], myRec[3])
Without having access to the gif's and being able to run this code, I'm going to assume your problem lies within how you check for collisions.
Namely, the colliderect() function takes one parameter, and it should be a pygame.Rect() object.
Meaning when you do your playerHitFoes you should pass the .rect object of your f['rect'] objects like so:
def playerHitFoes(playerRect, foes):
for f in foes:
if playerRect.colliderect(f['rect'].rect):
return True
def playerHasHitHeart(playerRect, foes):
for h in heart:
if playerRect.colliderect(h['rect'].rect):
return True
This might or might not solve your issue.
But I'll touch on some other things I found that is most likely not crucial to this problem, but might give you problems down the line.
def playerHitFoes(playerRect, foes):
for f in foes:
if guy.getRect(f['rect']):
return True
return False
In the code above, playerRect is never used, guy is not defined (all tho it will most likely pull the guy = Player() just fine, but this might cause issues for you.
playerHitFoes() is also defined twice, once out in the wild and once in the player function. But it's never used in your code examples.
playerHitFoes, playerHasHitHeart and collide? is never called upon anywhere in your code.
playerHasHitBaddie is used to check if game is over, but playerHasHitBaddie is never defined.
This code would give a lot of exceptions even if i had the gifs.
So I'll assume this is just a minor part of your code and you left out a lot of things.. So either the above solves the problem - or you need to give at least me more detail.. For instance what code do you use to do the actual collision detection?
List of things not defined or not used
Badies() - We don't know what it looks like
foes.drawAndCollision
playerHasHitBaddie
playerHitFoes
playerHasHitHeart
collide
gameWin
changedRecs
PLAYERMOVERATE
BADDIEMINSPEED
BADDIEMINSIZE
FPS
win
guy, TEXTCOLOR (Local variables in functions assuming global presence)
This was just to name a few.
One important one is what Badies() look like and how check/call for the collision detection.

Categories

Resources