So i recently started trying to make a game. Im having trouble moving the player that is animated. I have it flip through a sprite sheet for the animation i just dont know how to have that animation move around the screen. So I just need to know how i can move an animating image. In the game I have a running animation and a idle animation i want it to switch to the running animation when i hold a arrow key and do the running animation while moving across the screen. Then go back to the idle animation while not moving.
import pygame
from sys import exit
import time
pygame.init()
pygame.display.set_caption('Rocket_Jump')
width = 1750
height = 1250
screen = pygame.display.set_mode((width,height))
#FPS
clock = pygame.time.Clock()
#Black Gunner
bg_idle_sheet = pygame.image.load(r'Rocket_Jump\TeamGunner_By_SecretHideout_060519\CHARACTER_SPRITES\Black\Gunner_ Black_Idle.png').convert_alpha(); bg_idle_frames = 5
bg_run_sheet = pygame.image.load(r'Rocket_Jump\TeamGunner_By_SecretHideout_060519\CHARACTER_SPRITES\Black\Gunner_Black_run.png').convert_alpha(); bg_run_frames = 6
bg_crouch_sheet = pygame.image.load(r'Rocket_Jump\TeamGunner_By_SecretHideout_060519\CHARACTER_SPRITES\Black\Gunner_Black_crouch.png').convert_alpha(); bg_crouch_frames = 3
bg_death_sheet = pygame.image.load(r'Rocket_Jump\TeamGunner_By_SecretHideout_060519\CHARACTER_SPRITES\Black\Gunner_Black_death.png').convert_alpha(); bg_death_frames = 8
bg_jump_sheet = pygame.image.load(r'Rocket_Jump\TeamGunner_By_SecretHideout_060519\CHARACTER_SPRITES\Black\Gunner_Black_jump.png').convert_alpha(); bg_jump_frames = 2
#Background
BG = (178, 190, 181)
#start position
start_x = 100
start_y = 100
#Gets images from a sprite sheet
def get_image(sheet, frame, width, height, scale, color):
image = pygame.Surface((width, height)).convert_alpha()
image.blit(sheet, (0, 0), (frame * width, 0, width, height))
image = pygame.transform.scale(image, (width * scale, width * scale))
image.set_colorkey(color)
return image
#Animation
class Gunner(pygame.sprite.Sprite):
def __init__(self, sheet, frames, pos_x, pos_y, type):
pygame.sprite.Sprite.__init__(self)
self.sprites = [get_image(sheet, i, 48, 48, 4, 'Black') for i in range(frames)]
self.current_sprite = 0
self.image = self.sprites[self.current_sprite]
self.rect = self.image.get_rect()
self.x = pos_x
self.y = pos_y
self.rect.center = [self.x, self.y]
self.type = type
def update(self):
self.current_sprite += 1
if self.current_sprite >= len(self.sprites):
self.current_sprite = 0
self.image = self.sprites[self.current_sprite]
def draw(self, screen):
screen.blit(self.image, self.rect)
moving_sprites = pygame.sprite.Group()
run = True
while run:
#What keys are pressed
keys = pygame.key.get_pressed()
player_idle = Gunner(bg_idle_sheet, bg_idle_frames, start_x, start_y, 1)
player_run = Gunner(bg_run_sheet, bg_run_frames, 100, 100, 2)
moving_sprites.add(player_idle)
moving_sprites.add(player_run)
#Screen color
screen.fill(BG)
#Quit Program
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
if keys[pygame.K_RIGHT]:
for sprite in moving_sprites:
if sprite.type == 1:
start_x += 1
sprite.draw(screen)
elif sprite.type == 2:
sprite.draw(screen)
moving_sprites.update()
pygame.display.flip()
pygame.display.update()
clock.tick(12)
To make your animated sprites move, I would recommend you use the built-in functions for pygame rectangles like the move function instead of updating the start_x on each iteration of the game loop:
https://www.pygame.org/docs/ref/rect.html#pygame.Rect.move_ip
Also you should make the Gunner object only once before the game loop and not re-create the same thing every iteration. Eventually your game will start to lag because of this once you add more to the game.
For transitioning between animations, I would highly recommend that you start with making only one instance of your Gunner object, and it contains all of the animations. Instead of two gunner objects where each gunner has only 1 set of images. For example you can have your Gunner.sprites be structured like
self.sprites = {
"running" : [get_image(bg_run_sheet, i, 48, 48, 4, 'Black') for i in range(bg_run_frames)],
"idle" : [get_image(bg_idle_sheet , i, 48, 48, 4, 'Black') for i in range(bg_idle_frames)]
}
Then you can keep track of the gunner's state in a variable, and key into this dict depending on your state. To manage the state, in the gunner's update function if there's a KEYDOWN event, you run, KEYUP, you go idle etc
Related
This question already has answers here:
Setting up an invisible boundary for my sprite
(1 answer)
Use vector2 in pygame. Collide with the window frame and restrict the ball to the rectangular area
(1 answer)
Create a border in PyGame
(1 answer)
Not letting the character move out of the window
(2 answers)
Closed 13 days ago.
In playing around with pygame capabilities I prepare to code a game of my own. While most of pygame's examples display surfaces like squares, I'd like to run with a rectangular shape resembling that of a cell phone screen. Initially, I'd expect that simply reshaping a GfG example picked up on the internet would do the job, yet I realize that objects do not stay inside the new rectangular shape when moving a sprite around with keyboard arrows.
I attempted to adjust width and height of surface (changed from (500, 500)):
# Global Variables
COLOR = (255, 100, 98)
SURFACE_COLOR = (167, 255, 100)
WIDTH = 580
HEIGHT = 250
But the squared object that I can control keeps continuing outside the new rect shape.
Any suggestions on how to proceed?
My playground code picked up on www.geeksforgeeks.org looks as follows:
import random
import pygame
# Global Variables
COLOR = (255, 100, 98)
SURFACE_COLOR = (167, 255, 100)
WIDTH = 580
HEIGHT = 250
# Object class
class Sprite(pygame.sprite.Sprite):
def __init__(self, color, height, width):
super().__init__()
self.image = pygame.Surface([width, height])
self.image.fill(SURFACE_COLOR)
self.image.set_colorkey(COLOR)
pygame.draw.rect(self.image,
color,
pygame.Rect(0, 0, width, height))
self.rect = self.image.get_rect()
def moveRight(self, pixels):
self.rect.x += pixels
def moveLeft(self, pixels):
self.rect.x -= pixels
def moveForward(self, speed):
self.rect.y += speed * speed/10
def moveBack(self, speed):
self.rect.y -= speed * speed/10
pygame.init()
RED = (255, 0, 0)
size = (WIDTH, HEIGHT)
screen = pygame.display.set_mode(size)
pygame.display.set_caption("Controlling Sprite")
all_sprites_list = pygame.sprite.Group()
playerCar = Sprite(RED, 20, 30)
playerCar.rect.x = 150
playerCar.rect.y = 150
all_sprites_list.add(playerCar)
exit = True
clock = pygame.time.Clock()
while exit:
for event in pygame.event.get():
if event.type == pygame.QUIT:
exit = False
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_x:
exit = False
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT]:
playerCar.moveLeft(5)
if keys[pygame.K_RIGHT]:
playerCar.moveRight(5)
if keys[pygame.K_DOWN]:
playerCar.moveForward(5)
if keys[pygame.K_UP]:
playerCar.moveBack(5)
all_sprites_list.update()
screen.fill(SURFACE_COLOR)
all_sprites_list.draw(screen)
pygame.display.flip()
clock.tick(60)
pygame.quit()
This question already has answers here:
Drag multiple sprites with different "update ()" methods from the same Sprite class in Pygame
(2 answers)
Closed 11 months ago.
I’m trying to make a 2D game where that background or screen can be dragged. When this happens I want all the sprites to move with it. How can I implement this?
You would need to detect the MOUSEMOTION event and then check if the left button is clikced using the event.buttons. From there, you can get the number of pixels the screen has been dragged (both horizontally and vertically) to find the new position that the screen should be set to, and hence, the new position for the sprites. Working example below:
import pygame
from pygame.locals import *
from random import randrange
# init global variables
left_btn = 0
cur_x = 0 # current X position
cur_y = 0 # current Y position
go = True
img_pos = pygame.Rect((0, 0), (0, 0))
# Sprite object
class Sprite(pygame.sprite.Sprite):
def __init__(self, color, width, height):
super().__init__()
self.width = width
self.height = height
self.image = pygame.Surface([width, height])
pygame.draw.rect(self.image, color, pygame.Rect(0, 0, width, height))
self.rect = self.image.get_rect()
def update(self, x, y):
self.rect = Rect(self.rect.x + x, self.rect.y + y, self.width, self.height)
# init display
pygame.display.init()
screen = pygame.display.set_mode((800, 600))
img = pygame.image.load('my_image.png')
# Create random Sprites
all_sprites_list = pygame.sprite.Group()
for _ in range(10):
c = (randrange(255), randrange(255), randrange(255))
s = Sprite(c, 20, 20)
s.rect.x = randrange(500)
s.rect.y = randrange(500)
all_sprites_list.add(s)
while go:
for e in pygame.event.get():
if e.type == pygame.QUIT: go = False
if e.type == MOUSEMOTION:
if e.buttons[left_btn]:
rel = e.rel
img_pos.x += rel[0]
img_pos.y += rel[1]
# calculate diff in X and Y positions
x = img_pos.x - cur_x
y = img_pos.y - cur_y
# update Sprites' position
all_sprites_list.update(x, y)
# update current X and Y positions
cur_x = img_pos.x
cur_y = img_pos.y
screen.fill(0)
screen.blit(img, img_pos) # update screen's position
all_sprites_list.draw(screen)
pygame.display.flip()
pygame.time.delay(30)
pygame.quit()
Cannot figure out why my code won't show sprites when I run it. The code is from a how-to book I found at my library, I have reread the code multiple times and haven't found anything different than what the book says to do. This is my first time coding on python and I haven't seen anything to help me solve my problem yet. This is all the code I've written for the game so far.
import pygame
from pygame import *
from random import randint
pygame.init()
WINDOW_WIDTH = 1100
WINDOW_HEIGHT = 600
WINDOW_RES = (WINDOW_WIDTH, WINDOW_HEIGHT)
WIDTH = 100
HEIGHT = 100
WHITE = (255, 255, 255)
SPAWN_RATE = 360
GAME_WINDOW = display.set_mode(WINDOW_RES)
display.set_caption('Attack of the vampire Pizzas!')
pizza_img = image.load('vampire.png')
pizza_surf = Surface.convert_alpha(pizza_img)
VAMPIRE_PIZZA = transform.scale(pizza_surf, (WIDTH, HEIGHT))
background_img = image.load('restaurant.jpg')
background_surf = Surface.convert_alpha(background_img)
BACKGROUND = transform.scale(background_surf, WINDOW_RES)
class VampireSprite(sprite.Sprite):
def __init__(self):
super().__init__()
self.speed = 2
self.lane = randint(0, 4)
all_vampires.add(self)
self.image = VAMPIRE_PIZZA.copy()
y = 50 + self.lane * 100
self.rect = self.image.get_rect(center = (1100, y))
def update(self, game_window):
game_window.blit(self.image, (self.rect.x, self.rect.y))
all_vampires = sprite.Group()
tile_color = WHITE
for row in range(6):
for column in range(11):
draw.rect(BACKGROUND, tile_color, (WIDTH * column, HEIGHT * row, WIDTH, HEIGHT), 1)
GAME_WINDOW.blit(BACKGROUND, (0,0))
----------------------------------------------
#Start Main Game Loop
game_running = True
#Game Loop
while game_running:
for event in pygame.event.get():
#Exit loop on quit
if event.type == QUIT:
game_running = False
if randint(1, SPAWN_RATE) == 1:
VampireSprite()
for vampire in all_vampires:
vampire.update(GAME_WINDOW)
display.update()
pygame.quit()
The Code seems to have all the correct components, except that it's a bit mixed up.
Generally when you make a sprite, it has the __init__() function - obviously for initialisation, and additionally an update() function. The update() function usually does not draw the object to the display/surface, but adjusts the position (i.e.: the sprite.rect) or changes the "look" (image) used for the sprite, for drawing later.
Sprites are usually grouped into an aptly-named Sprite Group. Once sprites are in a group, a single call to group.update() will call the update() function on every sprite contained. It's really convenient, and works well.
So tweaking your Vampire Pizza Sprite:
class VampireSprite(sprite.Sprite):
def __init__(self):
super().__init__()
self.speed = 2
self.lane = randint(0, 4)
self.image = VAMPIRE_PIZZA.copy()
y = 50 + self.lane * 100
self.rect = self.image.get_rect(center = (1100, y))
def update(self):
# TODO - do Vampire Pizzas Move?
# if so, update the self.rect
pass
And that's all that's needed. I removed the painting code, this will be handled by a sprite group.
So later on:
# Make a group of vampire sprites
all_vampires = sprite.Group()
all_vampires.add( VampireSprite() ) # Start with a single vampire
# Game Loop
game_running = True
while game_running:
# handle events
for event in pygame.event.get():
#Exit loop on quit
if event.type == QUIT:
game_running = False
# spawn some vampires, maybe
if randint(1, SPAWN_RATE) == 1:
all_vampires.add( VampireSprite() ) # add to the group
# Update/move all vampire sprites
all_vampires.update() # updates every sprite in group
# repaint the screen
GAME_WINDOW.blit(BACKGROUND, (0,0))
# draw some columns(?)
tile_color = WHITE
for row in range(6):
for column in range(11):
draw.rect(GAME_WINDOW, tile_color, (WIDTH * column, HEIGHT * row, WIDTH, HEIGHT), 1)
all_vampires.draw() # paints every sprite in group
display.update()
pygame.quit()
There's two calls from the all_vampires sprite group - all_vampires.update() and all_vampires.draw()? With just these two calls, all sprites in the group are moved (adjusted/whatever), and painted to the screen.
This code is mostly just the generic start up of a pygame window but I'm trying to make it so the object moves (the planet object I've made) in the orbit around the sun object I've made for the coordinates I've given it. I know the x and y values are updating but I don't understand why the object doesn't move.
#import the library
import pygame
import math
#classes
class button:
def _init_ (self,screen, colour, x, y, width,height, letter):
self.screen = screen
self.colour = colour
self.x = x
self.y = y
self.width = width
self.height = height
self.letter = letter
self.radius = radius
def draw(self):
pygame.draw.rect(self.screen, self.colour,(self.x,self.y, self.width, self.height))
if self.letter!= '+' and self.letter!= '-':
font = pygame.font.SysFont('agencyfb',15,True,False)
else:
font = pygame.font.SysFont('agencyfb',25,True,False)
text = font.render(self.letter, True, black)
text_rect = text.get_rect(center=(self.x+self.width/2,self.y+self.height/2))
screen.blit(text, text_rect)
class orbit:
def __init__(self,screen,colour,x,y,radius,width):
self.screen = screen
self.colour = colour
self.x = x
self.y = y
self.width = width
self.radius = radius
def draw_circle(self):
pygame.draw.circle(self.screen,self.colour,(self.x,self.y),self.radius,self.width)
#define colours
##Sun = pygame.draw.circle(screen,Sun,[1000,450],100,0)
Black = (0,0,0)
White = (255,255,255)
Green = (0,255,0)
Red = (255,0,0)
Blue = (0,0,255)
Sun = (255,69,0)
Sun = []
Planet = []
#initialise the engine
pygame.init()
#Opening a window
size = (1920,1080)
screen = pygame.display.set_mode(size)
#set window title
pygame.display.set_caption("Orbit Simulator")
#loop unti the user clicks the close button
done = False
#
x=1000
y=450
Sun.append(orbit(screen,Red,1000,450,100,0))
Planet.append(orbit(screen,White,x,y,50,0))
#
#used to manage how fast the screen updates
clock = pygame.time.Clock()
#------ Main program Loop ------
while not done:
#--- Main event loop
for event in pygame.event.get(): #user did something
if event.type == pygame.QUIT: #if user clicked close
done = True #flag that we are done and exit the loop
#------ Game logic should go here ------
#------ Drawing code should go here -------
#first, clear the screen to white. Don't put other drawing commands above this or they will be erased with this command.
screen.fill(Black)
for i in Sun:
i.draw_circle()
for i in Planet:
r=150
angle=0
count = 0
while angle <= 360:
angle_radians = math.radians(angle)
x = int(math.cos(angle_radians)*r)
y = int(math.sin(angle_radians)*r)
angle +=1
count +=1
print(count)
x+=1000
y+=450
pygame.draw.circle(screen,White,[x,y],10,0)
print("Position [",x,",",y,"]")
#update the screen
pygame.display.flip()
#------ Limit to 60 frames per second ------
clock.tick(60)
#------ When the loop ends, quit ------
pygame.quit()
You can make an object rotate around another by using trigonometry or vectors. With vectors you just have to rotate a vector which defines the offset from the rotation center each frame and add it to the position vector (self.pos which is the rotation center) to get the desired self.rect.center coordinates of the orbiting object.
import pygame as pg
from pygame.math import Vector2
class Planet(pg.sprite.Sprite):
def __init__(self, pos, *groups):
super().__init__(*groups)
self.image = pg.Surface((40, 40), pg.SRCALPHA)
pg.draw.circle(self.image, pg.Color('dodgerblue'), (20, 20), 20)
self.rect = self.image.get_rect(center=pos)
self.pos = Vector2(pos)
self.offset = Vector2(200, 0)
self.angle = 0
def update(self):
self.angle -= 2
# Add the rotated offset vector to the pos vector to get the rect.center.
self.rect.center = self.pos + self.offset.rotate(self.angle)
def main():
pg.init()
screen = pg.display.set_mode((640, 480))
screen_rect = screen.get_rect()
clock = pg.time.Clock()
all_sprites = pg.sprite.Group()
planet = Planet(screen_rect.center, all_sprites)
yellow = pg.Color('yellow')
while True:
for event in pg.event.get():
if event.type == pg.QUIT:
return
all_sprites.update()
screen.fill((30, 30, 30))
pg.draw.circle(screen, yellow, screen_rect.center, 60)
all_sprites.draw(screen)
pg.display.flip()
clock.tick(60)
if __name__ == '__main__':
main()
pg.quit()
When i try to run the game the code tries to run a method for the wrong sprite. I think the line "player.handle_keys()" is the problem as when i run it, it says that it can't find a "handle_keys()" method for the "meteor" class. I haven't got a line to run a "meteor.handle_keys()" as this class should not have this method.
Here is the code:
import pygame
import random
# Define some colors
BLACK = ( 0, 0, 0)
WHITE = (255, 255, 255)
RED = (255, 0, 0)
bg = pygame.image.load("bg1.png")
class space_ship(pygame.sprite.Sprite):
def __init__(self, color, width, height):
super().__init__()
# Create an image of the space_ship1, and fill it with a color.
# This could also be an image loaded from the disk.
self.image = pygame.Surface([width, height])
self.image.fill(WHITE)
self.image.set_colorkey(WHITE)
self.rect = self.image.get_rect()
#draw image
self.image = pygame.image.load("player1.gif").convert()
# Draw the ellipse
#pygame.draw.ellipse(self.image, color, [0, 0, width, height])
# x and y coordinates
self.x = 500
self.y = 450
def handle_keys(self):
""" Handles Keys """
key = pygame.key.get_pressed()
dist = 5 # distance moved in 1 frame
if key[pygame.K_RIGHT]: # right key
self.x += dist # move right
elif key[pygame.K_LEFT]: # left key
self.x -= dist # move left
def draw(self, surface):
""" Draw on surface """
# blit yourself at your current position
surface.blit(self.image, (self.x, self.y))
class asteroid(pygame.sprite.Sprite):
def __init__(self, color, width, height):
super().__init__()
# Create an image of the space_ship1, and fill it with a color.
# This could also be an image loaded from the disk.
self.image = pygame.Surface([width, height])
self.image.fill(WHITE)
self.image.set_colorkey(WHITE)
self.rect = self.image.get_rect()
# Draw the ellipse
#pygame.draw.ellipse(self.image, color, [0, 0, width, height])
self.image = pygame.image.load("ast1.gif").convert()
# x and y coordinates
self.x = random.randint(50,950)
self.y = 10
def draw(self, surface):
""" Draw on surface """
# blit yourself at your current position
surface.blit(self.image, (self.x, self.y))
def fall(self):
dist = 5
self.y +=dist
if self.y > 600:
self.x = random.randint(50,950)
self.y = random.randint(-2000, -10)
def respawn(self):
self.y = -10
# Initialize Pygame
pygame.init()
# Set the height and width of the screen
screen_width = 1000
screen_height = 600
screen = pygame.display.set_mode([screen_width, screen_height])
# This is a list of 'sprites.' Each sprite in the program is
# added to this list.
# The list is managed by a class called 'Group.'
asteroid_list = pygame.sprite.Group()
# This is a list of every sprite.
# All asteroids and the player as well.
all_sprites_list = pygame.sprite.Group()
player = space_ship(RED, 20, 15)
all_sprites_list.add(player)
asteroid_1 = asteroid(BLACK, 40, 40)
asteroid_list.add(asteroid_1)
all_sprites_list.add(asteroid_1)
asteroid_2 = asteroid(BLACK, 40, 40)
asteroid_list.add(asteroid_2)
all_sprites_list.add(asteroid_2)
asteroid_3 = asteroid(BLACK,40, 40)
asteroid_list.add(asteroid_3)
all_sprites_list.add(asteroid_3)
asteroid_4 = asteroid(BLACK,40, 40)
asteroid_list.add(asteroid_4)
all_sprites_list.add(asteroid_4)
asteroid_5 = asteroid(BLACK,40, 40)
asteroid_list.add(asteroid_5)
all_sprites_list.add(asteroid_5)
asteroid_6 = asteroid(BLACK,40, 40)
asteroid_list.add(asteroid_6)
all_sprites_list.add(asteroid_6)
asteroid_7 = asteroid(BLACK,40, 40)
asteroid_list.add(asteroid_7)
all_sprites_list.add(asteroid_7)
asteroid_8 = asteroid(BLACK,40, 40)
asteroid_list.add(asteroid_8)
all_sprites_list.add(asteroid_list)
# Loop until the user clicks the close button.
done = False
# Used to manage how fast the screen updates
clock = pygame.time.Clock()
score = 0
# ----------------- Main Program Loop --------------------
while not done:
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
#Call upon function
player.handle_keys()
# Clear the screen
screen.fill(WHITE)
#INSIDE OF THE GAME LOOP
screen.blit(bg, (0, 0))
# See if the player space_ship1 has collided with anything.
blocks_hit_list = pygame.sprite.spritecollide(player, asteroid_list, True)
# Check the list of collisions.
for player in blocks_hit_list:
score +=1
print(score)
# Draw all the spites
player.draw(screen)
asteroid_1.draw(screen)
asteroid_1.fall()
asteroid_2.draw(screen)
asteroid_2.fall()
asteroid_3.draw(screen)
asteroid_3.fall()
asteroid_4.draw(screen)
asteroid_4.fall()
asteroid_5.draw(screen)
asteroid_5.fall()
asteroid_6.draw(screen)
asteroid_6.fall()
asteroid_7.draw(screen)
asteroid_7.fall()
asteroid_8.draw(screen)
asteroid_8.fall()
#all_sprites_list.draw(screen)
# Limit to 60 frames per second
clock.tick(60)
# Go ahead and update the screen with what we've drawn.
pygame.display.flip()
pygame.quit()
You are overriding player in your for loop
# Check the list of collisions.
for player in blocks_hit_list:
score +=1
print(score)
change it to something else and all will be good
# Check the list of collisions.
for something_else in blocks_hit_list:
score +=1
print(score)
Enjoy