pygame sprite not moving automatically with each sprite update - python

I'm trying to make a cut scene for a pygame that I'm building, and in this pygame I'm trying to get the main player sprite to spawn at the rightmost side of the screen, before slowly moving towards the center. For some reason, rather than moving, it just stays completely still, despite the fact that the same logics that I applied in the cutscene works completely fine in the main game when I'm using keypresses to move the player instead of an automatic update.
I basically just followed the same logic that I did in my main game except instead of moving as a result of a keypress, it moves as a result of a sprite update. This is my code for the sprite:
class Player(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.Surface((30, 60))
self.image = pygame.image.load("soldier.png").convert_alpha()
self.rect = self.image.get_rect()
self.rect.x = WIDTH - 30
self.rect.y = HEIGHT - 60
self.speedx = -5
self.speedy = 0
self.count = 0
tru = False
def update(self):
self.count += 1
if self.count > 10:
self.speedx -= 5
self.count = 0
else:
self.speedx = 0
if self.rect.x < WIDTH / 2:
self.speedx = 0
self.rect.x += self.speedx
And here is my main game loop
game_over = True
running = True
CurrentLevel = 1
while running:
all_sprites = pygame.sprite.Group()
curtime = pygame.time.get_ticks()
platforms = pygame.sprite.Group()
bullets = pygame.sprite.Group()
grounds = pygame.sprite.Group()
thentime = pygame.time.get_ticks()
for plat in PLATFORMS:
p = Platform(*plat)
all_sprites.add(p)
platforms.add(p)
for gro in GROUNDS:
g = Ground(*gro)
all_sprites.add(g)
grounds.add(g)
player = Player()
all_sprites.add(player)
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_d:
running = False
all_sprites.update()
screen.fill(WHITE)
screen.blit(bg, [0, 0])
all_sprites.draw(screen)
pygame.display.flip()
This is what the outcome becomes:
Output
That player sprite at the far right side of the screen just remains there and doesn't move like it should.
Does anyone know whats going on?

Inside your while running loop, you have the line player = Player() and all_sprites.add(player). That means that each frame, your game is creating a new player object and instantiating it on the right side of the screen, so it never has a chance to move.

Related

I'm wondering why my player and my balloon which are both sprites is stuttering when I move the player

My frames drop and the game basically stops whenever I use the WASD keys, which are my movement controls. Its supposed to make the water balloon move but when I stop moving so does the water balloon. They're both sprites.
I might have got them mixed up since there are two sprite families.
main.py:
import pygame
from player import Player
from projectile import WaterBaloon
# Start the game
pygame.init()
game_width = 1000
game_height = 650
screen = pygame.display.set_mode((game_width, game_height))
clock = pygame.time.Clock()
running = True
bg_image = pygame.image.load("../assets/BG_Sand.png")
#make all the sprite groups
playerGroup = pygame.sprite.Group()
projectilesGroup = pygame.sprite.Group()
#put every sprite class in a group
Player.containers = playerGroup
WaterBaloon.containers = projectilesGroup
#tell the sprites where they are gonna be drawn at
mr_player = Player(screen, game_width/2, game_height/2)
# ***************** Loop Land Below *****************
# Everything under 'while running' will be repeated over and over again
while running:
# Makes the game stop if the player clicks the X or presses esc
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE:
running = False
#player input that detects keys (to move)
keys = pygame.key.get_pressed()
if keys[pygame.K_d]:
mr_player.move(1, 0)
if keys[pygame.K_a]:
mr_player.move(-1, 0)
if keys[pygame.K_w]:
mr_player.move(0, -1)
if keys[pygame.K_s]:
mr_player.move(0, 1)
if pygame.mouse.get_pressed()[0]:
mr_player.shoot()
#blit the bg image
screen.blit((bg_image),(0, 0))
#update the player
mr_player.update()
#update all the projectiles
for projectile in projectilesGroup:
projectile.update()
# Tell pygame to update the screen
pygame.display.flip()
clock.tick(60)
pygame.display.set_caption("ATTACK OF THE ROBOTS fps: " + str(clock.get_fps()))
player.py:
import pygame
import toolbox
import projectile
#Players Brain
class Player(pygame.sprite.Sprite):
#player constructor function
def __init__(self, screen, x, y):
pygame.sprite.Sprite.__init__(self, self.containers)
self.screen = screen
self.x = x
self.y = y
self.image = pygame.image.load("../assets/player_03.png")
#rectangle for player sprite
self.rect = self.image.get_rect()
self.rect.center = (self.x, self.y)
#end of rectangle for player sprite
self.speed = 8
self.angle = 0
#player update function
def update(self):
self.rect.center = (self.x, self.y)
mouse_x, mouse_y = pygame.mouse.get_pos()
self.angle = toolbox.angleBetweenPoints(self.x, self.y, mouse_x, mouse_y)
#get the rotated version of player
image_to_draw, image_rect = toolbox.getRotatedImage(self.image, self.rect, self.angle)
self.screen.blit(image_to_draw, image_rect)
#tells the computer how to make the player move
def move(self, x_movement, y_movement):
self.x += self.speed * x_movement
self.y += self.speed * y_movement
#shoot function to make a WaterBaloon
def shoot(self):
projectile.WaterBaloon(self.screen, self.x, self.y, self.angle)
You're only processing one event per frame. That's because you've put everything you do inside the frame in the event handling loop. That is likely to break down when you start getting events (such as key press and release events) at a higher rate. If events are not all being processed, your program may not update the screen properly.
You probably want your main loop to only do event processing stuff in the for event in pygame.event.get(): loop. Everything else should be unindented by one level, so that it runs within the outer, while running: loop, after all pending events have been handled.
Try something like this:
while running:
# Makes the game stop if the player clicks the X or presses esc
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE:
running = False
#player input that detects keys (to move) # unindent here (and all the lines below)
keys = pygame.key.get_pressed()
...

Pygame how to set a certain delay on automatic shooting

I'm trying to create a space shooting game the problem is I need to set a certain delay in the game loop so that the shooting can be controlled. If possible if the delay can be stored in a variable so that I can control it while in game thank you. Here's the code
When you use the spacebar to shoot, it already have the delay but I'm guessing that just is because of the keyboard delay because it's detected when it's pressed down
class Player(pygame.sprite.Sprite):
........
def shoot(self):
bullet = Bullet(self.rect.centerx, self.rect.top)
all_sprites.add(bullet)
bullets.add(bullet)
class Bullet(pygame.sprite.Sprite):
def __init__(self, x, y):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.Surface((10, 20))
self.image.fill(RED)
self.rect = self.image.get_rect()
self.rect.bottom = y
self.rect.centerx = x
self.speedy = -10
def update(self):
self.rect.y += self.speedy
# kill if it moves off the top of the screen
if self.rect.bottom < 0:
self.kill()
#Sprites
all_sprites = pygame.sprite.Group()
bullets = pygame.sprite.Group()
player = Player()
all_sprites.add(player)
running = True
while running:
player.shoot()
create a variable for example shootTime and iterate it (add one) every loop, then only call the shoot function when the variable reaches twenty. once you call the shoot variable then set the variable back to zero
all_sprites = pygame.sprite.Group()
bullets = pygame.sprite.Group()
player = Player()
all_sprites.add(player)
shootTime = 0
running = True
while running:
shootTime += 1
if shootTime == 20:
player.shoot()
shootTime = 0
you can change the number 20 in if shootTime == 20 to change the length between shots

FIRE. Checking if a list of rectangles collides with a player rectangle

I know i need a loop to check if a list of bullets hits a player.
I've tried researching online for 2 hours for reference code but all use sprites and classes.
#Bullet Collision with players
for i in range(len(bullets_2)):
#player is a rectangle style object
if bullets_2[i].colliderect(player):
player_health -= 10
Sadly enough my computer science teacher hasn't taught the class about sprites or classes, so let's avoid that.
I tried having the code above check if the list collides with the rectangle player.
The point of the above code is for the game to to take health away from the health bar if the enemy player's bullets hit the player.
EDIT:
I only have about 8 days to finish this game
TLDR:
How do I check to see if a list collides with a rectangle.
As in the comment, here's the code.
Here's the images I am using
import pygame, time, sys
from pygame.locals import *
pygame.init()
screen = pygame.display.set_mode((800,600))
clock = pygame.time.Clock()
class playerClass(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load("player.png").convert()
self.image.set_alpha(196)
self.rect = self.image.get_rect()
self.rect.y = 260
self.rect.x = 500
def update(self):
pass
class bulletClass(pygame.sprite.Sprite):
def __init__(self, speed, starty):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load("bullet.png").convert()
self.rect = self.image.get_rect()
self.rect.y = starty
self.rect.x = 0
self.speed = speed
def update(self):
self.rect.x += self.speed
gameExit = False
player = playerClass()
bullet1 = bulletClass(7,265)
bullet2 = bulletClass(10,295)
bullet3 = bulletClass(7,325)
bulletSprites = pygame.sprite.RenderPlain((bullet1, bullet2, bullet3))
playerSprites = pygame.sprite.RenderPlain((player))
bulletRectList = [bullet1.rect, bullet2.rect, bullet3.rect]
while not gameExit:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
screen.fill((255,255,255))
bulletSprites.update()
bulletSprites.draw(screen)
playerSprites.update()
playerSprites.draw(screen)
collidedBulletList = player.rect.collidelistall(bulletRectList)
if len(collidedBulletList) > 0:
for i in collidedBulletList:
print(i)
pygame.display.update()
clock.tick(10)
In this code, if you want to add a bullet just declare a new object
bullet4 = bulletClass(speed, yCoordinateToBeginWith)
and append it to bulletSprites and the bulletRectList and you are done. Using sprites simplifies this. Making your code sprite friendly would be difficult at the beginning but appending it is definitely easy afterwards.

Trying to move a sprite in pygame

I'm trying to make a bullet move in Pygame. Apologies if it has a simple fix, I just can't think at the moment.
This is what I run when I detect that the "1" button is pressed.
if pygame.event.get().type == KEYDOWN and e.key == K_1:
bullet = Bullet()
bullet.rect.x = player.rect.x
bullet.rect.y = player.rect.y
entities.add(bullet)
bullet_list.add(bullet)
bullet.update()
...and this is the actual bullet class. The spacing is a bit off.
class Bullet(pygame.sprite.Sprite):
def __init__(self):
super(Bullet, self).__init__()
self.image = pygame.Surface([4, 10])
self.image.fill(pygame.Color(255, 255, 255))
self.isMoving = False
self.rect = self.image.get_rect()
def update(self):
for i in range(20):
self.rect.x += 3
I understand that the update method is happening instantly rather than the slower movement I want. How am I supposed to make the bullet move slower?
All the answers that I've seen involve completely stopping the program instead of just stopping the one object. Is there a way around it?
You need to update all bullets on every game tick, not just when a player presses a button.
So, you'll want something like this as your event loop:
clock = pygame.time.Clock()
while True:
clock.tick(60)
for event in pygame.event.get():
if event == KEYDOWN and event.key == K_1:
bullet = Bullet()
bullet.rect.x = player.rect.x
bullet.rect.y = player.rect.y
entities.add(bullet)
bullet_list.add(bullet)
for bullet in bullet_list:
bullet.update()
And, modify the Bullet class to do incremental moves, like so:
class Bullet(pygame.sprite.Sprite):
def __init__(self):
super(Bullet, self).__init__()
self.image = pygame.Surface([4, 10])
self.image.fill(pygame.Color(255, 255, 255))
self.isMoving = False
self.rect = self.image.get_rect()
def update(self):
self.rect.x += 3

Python, having trouble controlling enemy sprite

Complete novice, new to programming in general. I am trying to write a side scroller game in python, using pygame. I have created three different libraries for my sprite classes for: the player, the enemy, and the land. I made the land a sprite so that the player can interact (collide) with different objects in the land class and not be able to pass through them. The issue I am having is that I want the enemy sprite to interact with the land sprite as well. Ideally, I want the enemy sprites to start at point "x" and be set in motion (-2) until it comes into contact with the land sprite, at which point I want it to reverse direction. I have been trying everything I can think of, and searching online for a solution to make this work with no success. It seems like it should be really simple, but I can't make it work.
Thank you for your time.
here's my code:
land sprite :
import pygame
class Object(pygame.sprite.Sprite):
def __init__(self,image_file):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load(image_file)
self.rect = self.image.get_rect()
player sprite :
import pygame
class Player(pygame.sprite.Sprite):
change_x = 0
change_y = 0
jump_ready = False
frame_since_collision = 0
frame_since_jump = 0
frame = 0
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.images = []
for i in range(1,9):
img = pygame.image.load("pit"+str(i)+".png").convert()
img.set_colorkey((0,0,0))
self.images.append(img)
self.image = self.images[0]
self.rect = self.image.get_rect()
def changespeed_x(self,x):
self.change_x = x
def changespeed_y(self,y):
self.change_y = y
def update(self,ground,brick,enemy):
if self.change_x < 0:
self.frame += 1
if self.frame > 3*4:
self.frame = 0
self.image = self.images[self.frame//4]
if self.change_x > 0:
self.frame += 1
if self.frame > 3*4:
self.frame = 0
self.image = self.images[self.frame//4+4]
old_x = self.rect.x
new_x = old_x + self.change_x
self.rect.x = new_x
player_health = 5
hurt = pygame.sprite.spritecollide(self,enemy,False)
if hurt:
player_health -= 1
print(player_health)
brick_break = pygame.sprite.spritecollide(self,brick,True)
collide = pygame.sprite.spritecollide(self,ground,False)
if collide:
self.rect.x = old_x
old_y = self.rect.y
new_y = old_y + self.change_y
self.rect.y = new_y
touch_list = pygame.sprite.spritecollide(self,ground,False)
for ground in touch_list:
self.rect.y = old_y
self.rect.x = old_x
self.change_y = 0
self.frame_since_collision = 0
if self.frame_since_collision < 6 and self.frame_since_jump < 6:
self.frame_since_jump = 100
self.change_y -= 8
self.frame_since_collision += 1
self.frame_since_jump += 1
def calc_grav(self):
self.change_y += .35
if self.rect.y >= 450 and self.change_y >= 0:
self.change_y = 0
self.rect.y = 450
self.frame_since_collision = 0
def jump(self,blocks):
self.jump_ready = True
self.frame_since_jump = 0
this is the enemy sprite that works, it only moves left, every time I tried a variation of the collision code like I have in the player class the sprite would just stop when it collided with the land sprite
enemy sprite :
import pygame
class Enemy(pygame.sprite.Sprite):
def __init__(self,image_file):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load(image_file)
self.image = self.image.convert()
self.image.set_colorkey((0,0,0))
self.rect = self.image.get_rect()
def update(self,ground):
change_x = -2
self.rect.x += change_x
and my main program code :
# first must import
import pygame
import random
import thing
import enemy
import player
# initialize the game engine
pygame.init()
# define some colors
# more color combos at www.colorpicker.com
black = ( 0, 0, 0)
white = ( 255, 255, 255)
green = (0, 255, 0)
red = (255, 0, 0)
blue = (131,226,252)
# open and set window size.
screen_width = 700
screen_height = 350
screen = pygame.display.set_mode([screen_width,screen_height])
break_list = pygame.sprite.Group()
land_list = pygame.sprite.Group()
enemy_list = pygame.sprite.Group()
all_sprites_list = pygame.sprite.Group()
cloud = pygame.image.load("cumulus-huge.png").convert()
for x in range(300,500,60):
brick = thing.Object("birck.png")
brick.rect.x = x
brick.rect.y = 180
break_list.add(brick)
all_sprites_list.add(brick)
for x in range(0,200,50):
wall = thing.Object("Sky3.png")
wall.rect.x = -180
wall.rect.y = x
land_list.add(wall)
all_sprites_list.add(wall)
for x in range (-50,1400,70):
ground = thing.Object("Ground2.png")
ground.rect.x = x
ground.rect.y = 305
land_list.add(ground)
all_sprites_list.add(ground)
monster = enemy.Enemy("monster1.png")
monster.rect.x = 650
monster.rect.y = 250
enemy_list.add(monster)
all_sprites_list.add(monster)
for x in range(760,1070,300):
pipe = thing.Object("pipe-top.png")
pipe.rect.x = x
pipe.rect.y = 225
land_list.add(pipe)
all_sprites_list.add(pipe)
player = player.Player()
player.rect.x = 10
player.rect.y = 230
all_sprites_list.add(player)
# set the window title
pygame.display.set_caption("Scroller")
# the following code sets up the main program loop
# Boolean Variable to loop until the user clicks the close button.
done = False # loop control
# used to manage how fast the screen updates
clock = pygame.time.Clock() # controls how fast game runs
# Main Program Loop
while done == False:
# ALL EVENT PROCESSING (input) SHOULD GO BELOW THIS COMMENT
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 so we exit this loop
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
player.changespeed_x(-6)
if event.key == pygame.K_RIGHT:
player.changespeed_x(6)
if event.key == pygame.K_UP:
player.jump(land_list)
if event.key == pygame.K_DOWN:
player.changespeed_y(6)
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT:
player.changespeed_x(-0)
if event.key == pygame.K_RIGHT:
player.changespeed_x(0)
monster.update()
player.update(land_list,break_list,enemy_list)
player.calc_grav()
# ALL EVENT PROCESSING (input) SHOULD GO ABOVE THIS COMMENT
# ALL GAME LOGIC (process) SHOULD GO BELOW THIS COMMENT
if player.rect.x >= 500:
diff = player.rect.x - 500
player.rect.x=500
for ground in land_list:
ground.rect.x -= diff
for brick in break_list:
brick.rect.x -= diff
for monster in enemy_list:
monster.rect.x -= diff
if player.rect.x <= 15:
diff = 15 - player.rect.x
player.rect.x = 15
for ground in land_list:
ground.rect.x += diff
for brick in break_list:
brick.rect.x += diff
for monster in enemy_list:
monster.rect.x += diff
# ALL GAME LOGIC (process) SHOULD GO ABOVE THIS COMMENT
# ALL CODE TO DRAW (output) SHOULD GO BELOW THIS COMMENT
# First, clear the screen. Don't put other drawing commands
# above this, or they will be erased with this command.
screen.fill(blue)
screen.blit(cloud,[200,0])
cloud.set_colorkey(black)
all_sprites_list.draw(screen)
# ALL CODE TO DRAW (output) SHOULD GO ABOVE THIS COMMENT
# This will update the screen with what's been drawn.
pygame.display.flip()
# limit to 30frames per second
clock.tick(30)
pygame.quit()
Your enemy class should be like this:
class Enemy(pygame.sprite.Sprite):
def __init__(self,image_file):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load(image_file)
self.image = self.image.convert()
self.image.set_colorkey((0,0,0))
self.rect = self.image.get_rect()
self.vel = -2
def update(self,ground):
self.rect.x += self.vel
Then in your update loop, implement this pseudocode:
...
if monster collides with ground:
monster.vel *= -1
...

Categories

Resources