Projectiles only move if i hold the fire key down - python

Previously in my projectiles module, I had a class that handled each direction of fire seperately (a class for firing up, down, left and right) and this did it's job. However, now that I'm trying to incorporate shot speed and other things into the class, having 4 seperate classes is just too messy and so I tried to trim it down so that I only have one class for all projectiles fired.
However, now that I have done this, when I fire a projectile, it will only move so long as I am holding the fire button ('a' key if firing left) down. Also, if I fire left, then fire right, the projectile that was previously travelling left will begin to travel right instead.
My question is; How do I handle the projectiles so that when I fire one, it no longer accepts updates and travels in a straight line?
This is my working code;
Main game module
import pygame
from constants import *
from player import Player
from Projectile import Projectiles
pygame.init()
screen = pygame.display.set_mode([500, 500])
pygame.display.set_caption('Labyrinth')
# Spawn player
player = Player(50, 50)
all_sprites_list = pygame.sprite.Group()
all_sprites_list.add(player)
projectile_list = pygame.sprite.Group()
clock = pygame.time.Clock()
done = False
# ----- Event Loop
while not done:
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
elif event.type == pygame.KEYDOWN:
if event.key == ord('a'):
player.changespeed(-3, 0)
elif event.key == ord('d'):
player.changespeed(3, 0)
elif event.key == ord('w'):
player.changespeed(0, -3)
elif event.key == ord('s'):
player.changespeed(0, 3)
elif event.key == pygame.K_LEFT:
projectile = Projectiles(0, 0)
projectile.rect.x = player.rect.x
projectile.rect.y = player.rect.y
elif event.key == pygame.K_RIGHT:
projectile = Projectiles(0, 0)
projectile.rect.x = player.rect.x
projectile.rect.y = player.rect.y
elif event.key == pygame.K_UP:
projectile = Projectiles(0, 0)
projectile.rect.x = player.rect.x
projectile.rect.y = player.rect.y
elif event.key == pygame.K_DOWN:
projectile = Projectiles(0, 0)
projectile.rect.x = player.rect.x
projectile.rect.y = player.rect.y
try:
if projectile:
projectile_list.add(projectile)
except:
pass
elif event.type == pygame.KEYUP:
if event.key == ord('a'):
player.changespeed(3, 0)
elif event.key == ord('d'):
player.changespeed(-3, 0)
elif event.key == ord('w'):
player.changespeed(0, 3)
elif event.key == ord('s'):
player.changespeed(0, -3)
# ----- Game Logic
all_sprites_list.update()
projectile_list.update()
screen.fill(GREEN)
all_sprites_list.draw(screen)
projectile_list.draw(screen)
pygame.display.flip()
clock.tick(60)
pygame.quit()
Player module
from constants import *
import pygame
import time
from datetime import datetime, timedelta
class Player(pygame.sprite.Sprite):
def __init__(self, x, y):
super().__init__()
self.image = pygame.Surface([15, 15])
self.image.fill(BLACK)
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
self.change_x = 0
self.change_y = 0
def changespeed(self, x, y):
self.change_x += x
self.change_y += y
def update(self):
self.rect.x += self.change_x
self.rect.y += self.change_y
Projectile module
import pygame
from constants import *
class Projectiles(object):
def __init__(self, x, y):
super().__init__()
self.image = pygame.Surface([4, 4])
self.image.fill(RED)
self.rect = self.image.get_rect()
def update(self):
key = pygame.key.get_pressed()
if key[pygame.K_UP]:
self.rect.y -= 5
if key[pygame.K_DOWN]:
self.rect.y += 5
if key[pygame.K_LEFT]:
self.rect.x -= 5
if key[pygame.K_RIGHT]:
self.rect.x += 5
As always any help would be much appreciated!

The first problem is that you only create ONE projectile. Your class is called Projectiles which is misleading because it's only one object not multiple. This causes the projectile to be controlled even after firing.
Also, the reason why the projectile only moves while you press a key is that in the update() method, you only add to the projectiles x or y coordinate when e.g. key[pygame.K_UP]: is true.
So, to fix this issues you will have to change the way your game handles projectiles.
If I understand your question right, you want to have multiple projectiles at once.
The way to implement this is to use a collection of projectiles.
Game
//nothing changed till here
elif event.key == pygame.K_LEFT:
p = Projectile(player.rect.x, player.rect.y, -5, 0)
projectile_list.add(p)
elif event.key == pygame.K_RIGHT:
p = Projectile(player.rect.x, player.rect.y, 5, 0)
projectile_list.add(p)
elif event.key == pygame.K_UP:
p = Projectile(player.rect.x, player.rect.y, 0, -5)
projectile_list.add(p))
elif event.key == pygame.K_DOWN:
p = Projectile(player.rect.x, player.rect.y, 0, 5)
projectile_list.add(p)
// moved the part where you append the projectile to in the if statement
# ----- Game Logic
all_sprites_list.update()
projectile_list.update()
screen.fill(GREEN)
all_sprites_list.draw(screen)
projectile_list.draw(screen)
pygame.display.flip()
clock.tick(60)
pygame.quit()
Projectile:
import pygame
from constants import *
// projectile needs to extend Sprite
class Projectile(pygame.sprite.Sprite):
def __init__(self, x, y, x_speed, y_speed):
super().__init__()
self.image = pygame.Surface([4, 4])
self.image.fill(RED)
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
self.x_speed = x_speed
self.y_speed = y_speed
def update(self):
self.rect.x += self.x_speed
self.rect.y += self.y_speed
Im not so familiar with Pygame but I hope this will help you at least somehow.

I have never used PyGame but one can see that your update() method in the Projectiles class depends on key press while it should depend on elapsed time instead.
Your projectile moves 5 units per key press, not 5 units per game tick once launched.

Related

Pygame: How to "lose" game when sprite runs into its trail

I created a snake-like game in which the user moves the sprite, and the sprite leaves a trail. If the user runs into the trail he's created, I'd like the game to end, and the player to lose.
One idea I had was to somehow track past positions of the sprite (maybe in a list), and then create an 'if' statement that would lead to a game loss (However, I'm was a little unclear on how to do that).
I received an answer to this question that coded for this list:
"I think you could declare a two dimensional list like this:
pastPositions = [[400, 300]]
Then every time the player's position moves, check the list:
for row in pastPositions:
If (player.rect.x == pastPositions[row][0] and player.rect.y == >pastPositions[row][1]):
done = true # game over
If the player hasn't been there yet, then add that position to the list.
pastPositions.append([player.rect.x, player.rect.y])"
This looks like it should work, but when I try to run the code (in Python Interactive), I get an error message that reads: "line 86, in if player.rect.x == astPositions[row][0] and player.rect.y == pastPositions[row][1]: IndexError: list index out of range" – Gal 2 days ago
What would you suggest I change the range to so that this doesn't happen? I tried setting it to the width and height of the pygame window.
import pygame
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
class Player(pygame.sprite.Sprite):
def __init__(self, x, y):
super().__init__()
self.image = pygame.Surface([15, 15])
self.image.fill(WHITE)
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
self.change_x = 0
self.change_y = 0
def changespeed(self, x, y):
self.change_x += x
self.change_y += y
def update(self):
self.rect.x += self.change_x
self.rect.y += self.change_y
pygame.init()
screen = pygame.display.set_mode([800, 600])
pygame.display.set_caption('The Etch-a-Sketch Game')
myfont = pygame.font.SysFont('Times', 20)
textsurface = myfont.render('This is the Etch-a-Sketch Game', False, (255, 255, 255))
screen.blit(textsurface,(0,0))
myfont = pygame.font.SysFont('Times', 15)
textsurface = myfont.render('Feel free to draw, but if you cross your own path, you will die.', False, (255, 255, 255))
screen.blit(textsurface,(0,20))
player = Player(400, 300)
all_sprites_list = pygame.sprite.Group()
all_sprites_list.add(player)
clock = pygame.time.Clock()
done = False
while not done:
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
player.changespeed(-3, 0)
elif event.key == pygame.K_RIGHT:
player.changespeed(3, 0)
elif event.key == pygame.K_UP:
player.changespeed(0, -3)
elif event.key == pygame.K_DOWN:
player.changespeed(0, 3)
elif event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT:
player.changespeed(3, 0)
elif event.key == pygame.K_RIGHT:
player.changespeed(-3, 0)
elif event.key == pygame.K_UP:
player.changespeed(0, 3)
elif event.key == pygame.K_DOWN:
player.changespeed(0, -3)
player.update()
all_sprites_list.draw(screen)
pygame.display.flip()
clock.tick(75)
pygame.quit ()
I think you could declare a two dimensional list like this:
pastPositions = [[400, 300]]
Then every time the player's position moves, check the list:
for row in pastPositions:
if (player.rect.x == row[0] and player.rect.y == row[1]):
done = true # game over
If the player hasn't been there yet, then add that position to the list.
pastPositions.append([player.rect.x, player.rect.y])
Are you looking for something like that?

Improve performance while executing pygame?

My pygame is running way too slow. Without using class oop it was running perfectly but now using oop its very slow.
I have tested putting that separate class file in main file also but the result was same.
import pygame
from snake import Snake
pygame.init()
surf_width = 800
surf_height = 600
clock = pygame.time.Clock()
dis_surf = pygame.display.set_mode((surf_width, surf_height))
pygame.display.set_caption("snake game")
run = True
def game_loop():
x = 255
y = 255
x_change = 0
y_change = 0
while run:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
dis_surf.fill((255, 255, 255))
game = Snake(dis_surf, x, y, x_change, y_change)
x = game.x
y = game.y
another file:
import pygame
class Snake():
def __init__(self, dis_surf, x, y, x_change, y_change):
self.dis_surf = dis_surf
self.x = x
self.y = y
self.width = 20
self.height = 20
self.x_change = x_change
self.y_change = y_change
self.vel = 5
self.draw()
def draw(self):
pygame.draw.rect(self.dis_surf, (0, 255, 0), (self.x, self.y, self.width, self.height))
self.run()
pygame.display.update()
def run(self):
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_RIGHT:
self.x_change = self.vel
self.y_change = 0
elif event.key == pygame.K_LEFT:
self.x_change = -self.vel
self.y_change = 0
elif event.key == pygame.K_UP:
self.y_change = -self.vel
self.x_change = 0
elif event.key == pygame.K_DOWN:
self.y_change = self.vel
self.x_change = 0
print(event)
self.x += self.x_change
self.y += self.y_change
x_change = game.x_change
y_change = game.y_change
pygame.display.update()
clock.tick(60)
game_loop()
A few things are wrong.
1) You are instantiating a new Snake class every game loop when you do game = Snake() inside of the while loop. This in combination with number 2 is your main problem. I moved this line outside of the while loop for you.
2) You are calling run() inside of __init__. This is something you should never do in a constructor, constructors generally should only be used for setting initial data. This also contributed to problem number 1 significantly because this was happening every game loop. I removed the call self.run() inside __init__ for you.
3) pygame.display.update() was being called twice. Not the cause of your problem, but still unnecessary.
Made some small corrections for you.
import pygame
pygame.init()
surf_width = 800
surf_height = 600
clock = pygame.time.Clock()
dis_surf = pygame.display.set_mode((surf_width, surf_height))
pygame.display.set_caption("snake game")
run = True
def game_loop():
x = 255
y = 255
x_change = 0
y_change = 0
game = Snake(dis_surf, x, y, x_change, y_change)
while run:
dis_surf.fill((255, 255, 255))
game.draw()
class Snake():
def __init__(self, dis_surf, x, y, x_change, y_change):
self.dis_surf = dis_surf
self.x = x
self.y = y
self.width = 20
self.height = 20
self.x_change = x_change
self.y_change = y_change
self.vel = 5
def draw(self):
pygame.draw.rect(self.dis_surf, (0, 255, 0), (self.x, self.y, self.width, self.height))
self.run()
def run(self):
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_RIGHT:
self.x_change = self.vel
self.y_change = 0
elif event.key == pygame.K_LEFT:
self.x_change = -self.vel
self.y_change = 0
elif event.key == pygame.K_UP:
self.y_change = -self.vel
self.x_change = 0
elif event.key == pygame.K_DOWN:
self.y_change = self.vel
self.x_change = 0
self.x += self.x_change
self.y += self.y_change
pygame.display.update()
clock.tick(60)
game_loop()
If you want to use OOP in pygame, use pygame's Sprite class. It's made exactly for this purpose.
Your code should look like this (I tried to change not too much):
import pygame
pygame.init()
surf_width = 800
surf_height = 600
clock = pygame.time.Clock()
screen = pygame.display.set_mode((surf_width, surf_height))
pygame.display.set_caption("snake game")
class Snake(pygame.sprite.Sprite):
def __init__(self, pos):
super().__init__()
self.image = pygame.Surface((20, 20))
self.image.fill(pygame.Color('orange'))
self.rect = self.image.get_rect(topleft=pos)
self.x_change = 0
self.y_change = 0
self.vel = 5
def update(self, events):
for event in events:
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_RIGHT:
self.x_change = self.vel
self.y_change = 0
elif event.key == pygame.K_LEFT:
self.x_change = -self.vel
self.y_change = 0
elif event.key == pygame.K_UP:
self.y_change = -self.vel
self.x_change = 0
elif event.key == pygame.K_DOWN:
self.y_change = self.vel
self.x_change = 0
self.rect.move_ip(self.x_change, self.y_change)
def main():
snake = Snake((0, 0))
snakes = pygame.sprite.Group(snake)
while True:
events = pygame.event.get()
for event in events:
if event.type == pygame.QUIT:
return
snakes.update(events)
screen.fill((30, 30, 30))
snakes.draw(screen)
pygame.display.flip()
clock.tick(60)
if __name__ == '__main__':
main()
Ensure to only call pygame.display.flip() and pygame.event.get() once every frame.
If you want to handle events in other parts of your code, just store the current frame's events in a variable and pass them around. Using a Group makes this easy.
See how we cleanly seperated the logic of the game:
The main loop does only the three things it's supposed to do. Handling events, updating the game state, and drawing to the screen. It does so without "knowing what actually happens" in the game.
The Snake sprite only reacts when told so by the main loop (when its update method is called), and it does not care where the events come from and how and where it is actually displayed.

Bullets Not Appearing in Simple Space Invader Game

I'm a new programmer and am trying to figure out why my bullets aren't showing up. It seems that the Y coordinate changes, but for some reason the bullets are not showing up. This is my code in Python:
#Importing necessary modules
import random
import pygame
import sys
#Setting up pygame
pygame.init()
shooting = False
n = 0
keys = [False,False,False,False]
clock = pygame.time.Clock()
screen = pygame.display.set_mode([500,500])
font = pygame.font.Font(None,50)
#Creating class for player
class Player:
def __init__(self,x,y,width,height):
self.x = x
self.y = y
self.width = width
self.height = height
def draw(self):
pygame.draw.rect(screen,[0,255,0],
[int(self.x),int(self.y),int(self.width),int(self.height)],0)
def move(self):
if keys[1] == True:
self.x -= 1
elif keys[3] == True:
self.x += 1
if self.x < 0:
print(self.x)
self.x = 0
if self.x > 500 - self.width:
print(self.x)
self.x = 500 - self.width
def shoot(self):
return
class Bullet:
def __init__(self,x,y):
self.x = x
self.y = y
def update(self,y_amount = 5):
self.y += y_amount
return
def draw(self):
pygame.draw.rect(screen,[0,255,0],[int(self.x),int(self.y),10,30],0)
bullets = []
#Creating a player
player = Player(200,450,40,20)
#Main Loop
while True:
clock.tick(60)
#Background
screen.fill([0,0,0])
#Letting Player move
player.move()
#Drawing Player
player.draw()
#Updating screen
pygame.display.flip()
#Checking for events
for event in pygame.event.get():
#Checking for quit
if event.type == pygame.QUIT:
sys.exit()
if event.type == pygame.KEYDOWN:
#Checking for keys
if event.key == pygame.K_w:
keys[0] = True
elif event.key == pygame.K_a:
keys[1]=True
elif event.key == pygame.K_s:
keys[2]=True
elif event.key == pygame.K_d:
keys[3]=True
elif event.key == pygame.K_SPACE:
shooting = True
if event.type == pygame.KEYUP:
if event.key == pygame.K_w:
keys[0]=False
elif event.key == pygame.K_a:
keys[1]=False
elif event.key == pygame.K_s:
keys[2]=False
elif event.key == pygame.K_d:
keys[3]=False
elif event.key == pygame.K_SPACE:
shooting = False
if shooting == True:
bullets.append(Bullet(player.x, player.y))
for bullet in bullets:
bullet.update()
bullet.draw()
Rule 1: Check your coordinate system.
Pygame has (0,0) at the top left, your player is at (x, 450) - at the bottom. When you create a bullet, you do so at the player coordinate and then update the position to increase Y, i.e. move downwards rather than upwards.
I believe that you need to update your screen at the end of the while-loop, not at the beginning:
while True:
#fill screen
for event in pygame.event.get():
#get user input
pygame.display().flip()

Pygame player movement stops when too many keys are pressed at the same time

When I try to move my character and press any other key at the same time, the movement suddenly stops. For example, the space key in my code is used to shoot a tiny orb out of the spaceship. Every time I press space and I am moving left and right quickly, the orb will shoot out but the player movement will be frozen for a second or two.
I have tried to switch to different ways of handling the way keys are input, but all of them seem to lead to this same problem. pygame.key.get_pressed() also has this problem when in my code.
I am not quite sure if this is a problem with my laptop keyboard or something in the code, so the code for the entire file is below.
import pygame, sys, decimal
# Screen Size
SCREEN_X = 400
SCREEN_Y = 400
# Loading Images
backgroundImg = pygame.image.load('StarBackground.png')
menuBar = pygame.image.load('Menu_Bar.png')
shipImg = pygame.image.load('PowerShip.png')
orb = pygame.image.load('Orb00.png')
class Ship(pygame.sprite.Sprite):
# Movement rate of change
change_x = 0
# Methods
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = shipImg.convert_alpha()
self.rect = self.image.get_rect()
self.rect.x = SCREEN_X / 2 - 8
self.rect.y = SCREEN_Y - 40
def move(self, speed):
self.change_x = speed
def stop(self):
self.change_x = 0
def update(self, screen):
self.rect.x += self.change_x
if self.rect.x < 0:
self.rect.x = 0
elif self.rect.right > SCREEN_X:
self.rect.x -= 1
screen.blit(self.image, self.rect)
class MenuBar(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = menuBar.convert_alpha()
self.rect = self.image.get_rect()
self.rect.x = 10
self.rect.y = 0
def update(self, screen):
screen.blit(self.image,self.rect)
class Bullet1(pygame.sprite.Sprite):
def __init__(self,x,y):
pygame.sprite.Sprite.__init__(self)
self.image = orb.convert_alpha()
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
self.alive = True
def update(self):
if self.alive == True:
self.rect.y -= 1
if self.alive == False:
self.rect.y = -10000
class HealthBar(pygame.sprite.Sprite):
pass
class EnergyBar(pygame.sprite.Sprite):
pass
class PointsBar(pygame.sprite.Sprite):
pass
class Background(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = backgroundImg.convert_alpha()
self.rect = self.image.get_rect()
self.rect.x = 0
self.rect.y = 0
def update(self, screen):
if self.rect.top > 0:
self.rect.y = SCREEN_Y * -1
self.rect.y += 1
screen.blit(self.image, self.rect)
def main():
pygame.init()
size = [SCREEN_X, SCREEN_Y]
screen = pygame.display.set_mode(size, pygame.DOUBLEBUF) # Set the height and width of the screen
pygame.display.set_caption("Space Adventure") # Setting the game name in the title bar
background = Background() # Creating the game objects
menubar = MenuBar()
ship = Ship()
finished = False # Close button exit code
bullet1Enabled = True
bullet1Count = 1
spacePressed = False
clock = pygame.time.Clock() # Manages the frames per second
lastkey = None # Variable that stores the last key pressed
bulletlist = []
# Game loop
while not finished:
for event in pygame.event.get():
print(lastkey)
if event.type == pygame.QUIT:
finished = True
pygame.event.set_blocked(pygame.MOUSEMOTION)
if event.type == pygame.KEYDOWN:
if lastkey != pygame.K_SPACE:
lastkey = event.key
if event.key == pygame.K_SPACE:
spacePressed = True
if bullet1Enabled == True:
bullet1 = Bullet1(ship.rect.x, ship.rect.y)
bulletlist.append(bullet1)
bullet1Count = 1
else:
spacePressed = False
if event.type == pygame.KEYUP:
if event.key == pygame.K_RIGHT and lastkey != pygame.K_LEFT:
lastkey = None
ship.move(0)
if event.key == pygame.K_LEFT and lastkey != pygame.K_RIGHT:
lastkey = None
ship.move(0)
if event.key == pygame.K_RIGHT or lastkey == pygame.K_LEFT:
spacePressed = False
if event.key == pygame.K_LEFT or lastkey == pygame.K_RIGHT:
spacePressed = False
#Bullet Delay
if spacePressed == True:
bullet1Count = True
if spacePressed == False:
bullet1Count = False
if lastkey == pygame.K_RIGHT:
ship.move(1)
if lastkey == pygame.K_LEFT:
ship.move(-1)
clock.tick(240) # Frames per second
background.update(screen) # Background update
# Menu Bar update
ship.update(screen) # Ship update
for b in bulletlist:
if b.rect.bottom <= 0:
b.alive = False
b.update()
screen.blit(b.image, b.rect)
menubar.update(screen)
pygame.display.flip() # Updates the display for everything
pygame.quit() # Clean shutdown on IDLE
if __name__ == "__main__":
main()
The problem occurs because you don't reset lastkey to None after you release the space bar, so you have to press left or right twice.
if event.type == pygame.KEYUP:
if event.key == pygame.K_SPACE:
lastkey = None
I don't see why you need the lastkey variable at all. I'd remove these lines from the main loop,
if lastkey == pygame.K_RIGHT:
ship.move(1)
if lastkey == pygame.K_LEFT:
ship.move(-1)
insert them in the event loop and change lastkey to event.key:
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_RIGHT:
ship.move(1)
if event.key == pygame.K_LEFT:
ship.move(-1)
Now you should be able to remove the lastkey completely.

When running a script, two objects that are very far apart recognise as colliding

I've been having trouble with this code in Pygame recently, and I am not able to find my error. The script is at the moment just a controllable sprite, (which I understand is not showing as things are drawn over it) but when I run my code it thinks the small white square, (player) is colliding with the larger, (blocks.trees). The code is as such:
import pygame
from pygame.locals import*
#initialise pygame
pygame.init()
WHITE = (255,255,255)
#counts which sprite you should be on when running
#create screen
screen_width = 160
screen_height = 144
screen_multiplier = 4
screen = pygame.display.set_mode(((screen_width*screen_multiplier), (screen_height*screen_multiplier)))
pygame.display.set_caption('Pokemon Blood Red')
#Sprite stuff
sprite = pygame.image.load('player_east_still.png')
#Reform the sprite
sprite = pygame.transform.scale(sprite, (10*screen_multiplier, 14*screen_multiplier))
sprite.set_colorkey(WHITE)
#############################################################################
class Player(pygame.sprite.Sprite):
def __init__(self):
super(Player, self).__init__()
self.player_sprite = pygame.Surface((10*screen_multiplier, 14*screen_multiplier))
self.player_sprite.fill(WHITE)
self.rect = self.player_sprite.get_rect()
class Blocks(pygame.sprite.Sprite):
def __init__(self):
super(Blocks, self).__init__()
self.trees = pygame.Surface((20*screen_multiplier, 40*screen_multiplier))
self.trees.fill(WHITE)
self.rect = self.trees.get_rect()
player = Player()
blocks = Blocks()
#############################################################################
#Random variables for later use
amount_caught = 0
place = 1
catch1 = {'pokemon':'none',
'hp':0,
'attack':0,
'defence':0,
'sp_attack':0,
'sp_defence':0,}
background = 1
def area_load():
global background
if background == 1:
background = pygame.image.load('neuory_town.png').convert()
background = pygame.transform.scale(background, (160*screen_multiplier, 144*screen_multiplier))
area_load()
(x) = 160*0.45
(y) = 144*0.45
def caught():
if amount_caught == 0:
pass
#Mainloop
crashed = False
while not crashed:
pressed_keys = pygame.key.get_pressed()
player.update(pressed_keys)
x_change = 0
y_change = 0
#Different buttons
for event in pygame.event.get():
if event.type == pygame.QUIT:
crashed = True
pygame.quit()
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
x_change = 5*screen_multiplier
sprite = pygame.image.load('player_west_still.png')
elif event.key == pygame.K_RIGHT:
x_change = -5*screen_multiplier
sprite = pygame.image.load('player_east_still.png')
elif event.key == pygame.K_UP:
y_change = -5*screen_multiplier
sprite = pygame.image.load('player_north_still.png')
elif event.key == pygame.K_DOWN:
y_change = 5*screen_multiplier
sprite = pygame.image.load('player_south_still.png')
elif event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT:
x_change = 0
elif event.key == pygame.K_RIGHT:
x_change = 0
elif event.key == pygame.K_UP:
y_change = 0
elif event.key == pygame.K_DOWN:
y_change = 0
x += x_change
y += y_change
blockades = pygame.sprite.Group()
blockades.add(blocks)
#Check for collisions
hits = pygame.sprite.spritecollide(player, blockades, True)
if hits:
print ('Collision!')
#Draw everything
sprite = pygame.transform.scale(sprite, (10*screen_multiplier, 14*screen_multiplier))
sprite.set_colorkey(WHITE)
screen.blit(background,(0,0))
screen.blit(sprite,(x,y))
screen.blit(player.player_sprite, (x, y))
screen.blit(blocks.trees, (200, 200))
pygame.display.flip()
pygame.quit()
Thanks for the help!
pygame.sprite.spritecollide checks if the rects of the sprites overlap. You never move the rects to a new position after the instantiation, so both the player and the blocks are still positioned at (0, 0) (try to print(blocks.rect, player.rect)). To move them you can for example change the x and y coords, the topleft, center or the other attributes of the rect:
blocks.rect.center = (400, 500)
player.rect.topleft = (20, 40)
player.rect.x += 50
player.rect.y += 100
In your original example you're not moving the sprites, but only change the variables x and y which you use as the blit position for the image.
# This doesn't change the position of the rect, so there won't be collisions.
x += x_change
y += y_change
You should instead move the rect and then use the rect as the blit position:
player.rect.x += x_change
player.rect.y += y_change
screen.blit(player.player_sprite, player.rect) # Blits the image at rect's topleft coords.
Also, the image attribute of a pygame.sprite.Sprite should be called image not player_sprite. Then you can put all your sprites into one pygame.sprite.Group and to update and draw all sprites you only need two lines of code:
# Before the while loop define the sprite group.
all_sprites = pygame.sprite.Group()
# Add all sprites.
all_sprites.add(player) # And other sprites.
# In the while loop update the sprites.
all_sprites.update()
# And in the draw phase.
all_sprites.draw(screen)

Categories