Rectangle drawing issue in Pygame Python [duplicate] - python

This question already has answers here:
Why is my PyGame application not running at all?
(2 answers)
Closed 1 year ago.
So I'm kinda new at Pygame, and just trying to create easy projects to learn.
I've created a basic rectangle first as player, and I want to implement a system where user clicks to somewhere in screen and game spawns a rectangle at that point. Here's my code:
import pygame
import sys
from pygame import *
from pygame.mouse import get_pos
pygame.init()
SCREEN_WIDTH = 800
SCREEN_HEIGHT = 600
screen = pygame.display.set_mode((SCREEN_WIDTH,SCREEN_HEIGHT))
pygame.display.set_caption("Touch To Create Blocks!")
class Player(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
self.surf = pygame.Surface((50,50))
self.surf.fill((220,120,37))
self.rect = self.surf.get_rect()
def update(self,pressed_keys):
if pressed_keys[pygame.K_UP]:
self.rect.move_ip(0,-5)
elif pressed_keys[pygame.K_DOWN]:
self.rect.move_ip(0,5)
elif pressed_keys[pygame.K_LEFT]:
self.rect.move_ip(-5,0)
elif pressed_keys[pygame.K_RIGHT]:
self.rect.move_ip(5,0)
if self.rect.left < 0:
self.rect.left = 0
elif self.rect.right > SCREEN_WIDTH:
self.rect.right = SCREEN_WIDTH
elif self.rect.top <= 0:
self.rect.top = 0
elif self.rect.top >= SCREEN_HEIGHT - 50:
self.rect.bottom = SCREEN_HEIGHT
player = Player()
run = True
while run:
for event in pygame.event.get():
if event.type == QUIT:
run = False
sys.exit()
elif event.type == KEYDOWN:
if event.key == K_ESCAPE:
run = False
sys.exit()
elif event.type == MOUSEBUTTONDOWN:
mouse_x, mouse_y = pygame.mouse.get_pos()
rectangle = pygame.Rect(mouse_x, mouse_y, 40, 40)
pygame.draw.rect(screen, (255,255,255) , rectangle)
pygame.display.update()
screen.fill((0,0,0))
pressed_keys = pygame.key.get_pressed()
player.update(pressed_keys)
screen.blit(player.surf,player.rect)
pygame.display.update()
With that code, when I click, a block spawns and disappears immediately. How do I fix this? Thanks for your help.
(Sorry for my bad English)

The problem is that when the user clicks you draw the rectangle
(pygame.draw.rect), update the display (pygame.display.update) and
then, after the for loop, you empty the display
(screen.fill((0,0,0))). This explains why the rectangle disappears
immediately.
Instead of calling pygame.draw.rect each time the user clicks on the
screen, you can instead memorise the rectangle and save it into a
list. Then you have can draw all rectangles you memorised at each
iteration of your main loop.
Here is an implementation of this solution (I have added comments in
the code):
import pygame
import sys
from pygame import *
from pygame.mouse import get_pos
pygame.init()
SCREEN_WIDTH = 800
SCREEN_HEIGHT = 600
screen = pygame.display.set_mode((SCREEN_WIDTH,SCREEN_HEIGHT))
pygame.display.set_caption("Touch To Create Blocks!")
class Player(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
self.surf = pygame.Surface((50,50))
self.surf.fill((220,120,37))
self.rect = self.surf.get_rect()
def update(self,pressed_keys):
if pressed_keys[pygame.K_UP]:
self.rect.move_ip(0,-5)
elif pressed_keys[pygame.K_DOWN]:
self.rect.move_ip(0,5)
elif pressed_keys[pygame.K_LEFT]:
self.rect.move_ip(-5,0)
elif pressed_keys[pygame.K_RIGHT]:
self.rect.move_ip(5,0)
if self.rect.left < 0:
self.rect.left = 0
elif self.rect.right > SCREEN_WIDTH:
self.rect.right = SCREEN_WIDTH
elif self.rect.top <= 0:
self.rect.top = 0
elif self.rect.top >= SCREEN_HEIGHT - 50:
self.rect.bottom = SCREEN_HEIGHT
player = Player()
run = True
rectangles = list() # list of the rectangles we have to draw
while run:
for event in pygame.event.get():
if event.type == QUIT:
run = False
sys.exit()
elif event.type == KEYDOWN:
if event.key == K_ESCAPE:
run = False
sys.exit()
elif event.type == MOUSEBUTTONDOWN:
# add a new rectangle to our list of rectangles
mouse_x, mouse_y = pygame.mouse.get_pos()
rectangles.append(pygame.Rect(mouse_x, mouse_y, 40, 40))
screen.fill((0,0,0))
pressed_keys = pygame.key.get_pressed()
player.update(pressed_keys)
screen.blit(player.surf,player.rect)
# draw all the rectangles we memorised
for rectangle in rectangles:
pygame.draw.rect(screen, (255,255,255) , rectangle)
pygame.display.update()

Related

Pygame colliderect is not working properly

I'm writing this code to build a simple square which moves left and right and can jump on a stage using the colliderect function in pygame but the problem is when the player(square) jumps on the stage its y coordinate changes to the y coordinate of the stage permanently and never falls down. Another big issue is that when the player is below the stage it should not be able to jump over the top but it does. My code contains four pages, first contains the main loop, second contains the player class, third contains stage class and forth part contains the basic game functions
Main--Pg 01
import pygame
from player import Player
import game_functions as gf
import sys
from stage import Stage
from pygame.sprite import Group
def run_game():
# Intialise the game and start the screen
pygame.init()
screen = pygame.display.set_mode((800, 600))
pygame.display.set_caption("AmarCreep")
player = Player(screen)
stage = Stage(screen)
clock = pygame.time.Clock()
# Main loop
while True:
clock.tick(60)
# Navy screen
screen.fill((173,216,249))
for event in pygame.event.get():
# Check if user wants to quit
if event.type == pygame.QUIT:
sys.exit()
gf.responses(screen, player, event)
# Update player's x-y coordinate
player.p_movements(stage)
stage.draw_stage()
# Make the player appear
player.draw_player()
# Make the newly made screen visible
pygame.display.flip()
run_game()
Player--Pg 02
import pygame
from pygame.sprite import Sprite
class Player(Sprite):
# Initialise the main player
def __init__(self, screen):
super(Player, self).__init__()
self.screen = screen
self.screen_rect = screen.get_rect()
# Specifying the position of the player at start
self.rect = pygame.Rect(0, 0, 30, 30)
self.rect.centerx = self.screen_rect.centerx
self.rect.bottom = 590
self.moving_left = False
self.moving_right = False
self.moving_up = False
self.vel_y = 18
def p_movements(self, stage):
dx = 0
dy = 0
# Predict the player movements beforehand
if self.moving_left and self.rect.x > 10:
dx -= 7
if self.moving_right and self.rect.x < 760:
dx += 7
if self.moving_up:
dy -= self.vel_y
self.vel_y -= 2
if self.vel_y < -18:
self.moving_up = False
self.vel_y = 18
# Check collisions in x direction
if stage.s_rect.colliderect(self.rect.x + dx, self.rect.y, 30, 30):
dx = 0
# Check collisions in y direction
if stage.s_rect.colliderect(self.rect.x, self.rect.y + dy, 30, 30):
if self.vel_y < 0:
dy = stage.s_rect.bottom - self.rect.top
self.vel_y = 0
elif self.vel_y > 0:
dy = stage.s_rect.top - self.rect.bottom
# Update the positionse
self.rect.x += dx
self.rect.y += dy
if self.rect.bottom > 590:
self.rect.bottom = 590
dy = 0
pygame.time.Clock().tick(60)
def draw_player(self):
''' Draw the player on the screen'''
pygame.draw.rect(self.screen, (245,245,245), self.rect)
Stage--Pg 03
import pygame
from pygame.sprite import Sprite
from random import randint
class Stage(Sprite):
"""Initialize the platform for player to jump on"""
def __init__(self, screen):
super(Stage, self).__init__()
self.screen = screen
self.screen_rect = screen.get_rect()
self.s_rect = pygame.Rect(0, 540, 80, 10)
self.s_rect.x = randint(10, 590)
def draw_stage(self):
''' Draw the platform for the player'''
pygame.draw.rect(self.screen, (0,0,0), self.s_rect)
Game functions--Pg 04
import pygame
def responses(screen, player, event):
''' Check for responses'''
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_UP:
player.moving_up = True
if event.key == pygame.K_LEFT:
player.moving_left = True
if event.key == pygame.K_RIGHT:
player.moving_right = True
elif event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT:
player.moving_left = False
if event.key == pygame.K_RIGHT:
player.moving_right = False
From what I can see about your code, you use colliderect with a collision box of 30x30: colliderect(self.rect.x + dx, self.rect.y, 30, 30)
Your level, or stage is 80x10: pygame.Rect(0, 540, 80, 10)
This means that the collision detection will only happen in a certain part of your stage. Here is a visual to help you better understand:
I believe this may be the source of your problems. After colliding with the red box, you have them teleport to around halfway, a time when they are still colliding with the box. This makes them constantly teleport back to where they were, as they are always getting put back into the red box, as they are colliding with it. This may cause some of your other errors.

Pygame Sprite unresponsive, mac

First time building a game in python, let alone pygame. When I launch the code the window with the desired BG comes up, and my Sprite loads where I want. However, the Sprite doesn't move despite all efforts. I've scoured this site and other for resolutions but to no avail.
Note: I am using an upgraded mid-2009 mac book with OS X 10.11.6 and I am launching the code via terminal (python boss_fight.py). Also, I downloaded[tag: pygame] via homebrew.
Other things I've tried:
elif then if vs. if then if statements
Adding print functions after if statements regarding key input to see if the input is registered, does not print.
List item adding print functions after if statements regarding key input to see if input is registered, does not print.
Updating pygame
Updating python
Launching with command pythonw boss_fight.py (this yields: ImportError: No module named pygame) which is weird because running the prompt python boss_fight.py runs the game.
I've tried a few other things but can't remember them all
Here's the code:
import pygame # load pygame keywords
import sys # let python use your file system
import os # help python identify your OS
class Player(pygame.sprite.Sprite):
# Spawn a player
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.movex = 0
self.movey = 0
self.frame = 0
self.images = []
img = pygame.image.load(os.path.join('images','hero.png'))
self.images.append(img)
self.image = self.images[0]
self.rect = self.image.get_rect()
def control(self,x,y):
# control player movement
self.movex += x
self.movey += y
def update(self):
# Update sprite position
self.rect.x = self.rect.x + self.movex
self.rect.y = self.rect.y + self.movey
# moving left
if self.movex < 0:
self.frame += 1
if self.frame > 3 * ani:
self.frame = 0
self.image = self.images[self.frame//ani]
# moving right
if self.movex > 0:
self.frame += 1
if self.frame > 3 * ani:
self.frame = 0
self.image = self.images[(self.frame//ani)+4]
# Setup
worldx = 960
worldy = 720
fps = 40 # frame rate
ani = 4 # animation cycles
clock = pygame.time.Clock()
pygame.init()
main = True
BLUE = (25,25,200)
BLACK = (23,23,23 )
WHITE = (254,254,254)
ALPHA = (0,255,0)
world = pygame.display.set_mode([worldx,worldy])
backdrop = pygame.image.load(os.path.join('images','stage.jpeg')).convert()
backdropbox = world.get_rect()
player = Player() # spawn player
player.rect.x = 0
player.rect.y = 0
player_list = pygame.sprite.Group()
player_list.add(player)
steps = 10 # how fast to move
# Main loop
while main:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit(); sys.exit()
main = False
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
player.control(-steps,0)
print('left')
elif event.key == pygame.K_RIGHT:
player.control(steps,0)
print('right')
elif event.key == pygame.K_UP:
print('up')
elif event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT:
player.control(steps,0)
elif event.key == pygame.K_RIGHT:
player.control(-steps,0)
elif event.key == pygame.K_q:
pygame.quit()
sys.exit()
main = False
world.blit(backdrop, backdropbox)
player.update()
player_list.draw(world)
pygame.display.update()
clock.tick(fps)
The place where I think you've mistaken is where you're writing code for update
The way I do it is
def update(self):
# Update sprite position
self.rect.x = self.rect.x + self.movex
self.rect.y = self.rect.y + self.movey
# moving left
if self.movex < 0:
self.frame += 1
if self.frame > 3 * ani:
self.frame = 0
self.image = self.images[self.frame//ani]
# moving right
elif self.movex > 0:
self.frame += 1
if self.frame > 3 * ani:
self.frame = 0
self.image = self.images[(self.frame//ani)+4]
self.rect.topleft = self.rect.x, self.rect.y

pygame my player makes everything disappear when moving

project game
import pygame
import os
import random from pygame.locals import * # Constants
import math
import sys
import random
pygame.init()
screen=pygame.display.set_mode((1280,720)) #(length,height)
screen_rect=screen.get_rect()
background = pygame.Surface(screen.get_size())
background.fill((255,255,255)) # fill the background white
White = (255,255,255)
---------------------------------------------------------------------
background = pygame.image.load('stage.png').convert()
screen.blit(background, (0, 0))
class Player(pygame.sprite.Sprite):
def __init__(self):
self.rect = pygame.draw.rect(screen, (0,0,128), (50,560,50,25)) #(colour)(x-position,y-position,width,height)
self.dist = 100
def draw_rect(self,x,y): # This is my code which should make the player move
screen.blit(background, (0, 0)) #If this isn't included then when the rectangle moves it's old positon will still be on the screen
self.rect = self.rect.move(x*self.dist, y*self.dist); pygame.draw.rect(screen, (0, 0, 128), self.rect)
pygame.display.update()
def handle_keys(self): # code to make the character move when the arrow keys are pressed
for e in pygame.event.get():
if e.type == KEYDOWN:
key = e.key
if key == K_LEFT:
self.draw_rect(-0.5,0)
elif key == K_RIGHT:
self.draw_rect(0.5,0)
elif key == K_UP:
self.draw_rect(0,-0.5)
elif key == K_DOWN:
self.draw_rect(0,0.5)
elif key == K_SPACE:
self.draw_rect(2,-3)
if self.rect.right > 1400:
self.rect.right = 1400
if self.rect.left < 0:
self.rect.left = 0
if self.rect.bottom > 500:
self.rect.bottom = 500
if self.rect.top < 0:
self.rect.top = 0
player = Player()
------------------------------------------------------------------------
class Enemy(pygame.sprite.Sprite): # the enemy class which works fine
def __init__(self):
x = random.randint(50,450)
self.rect = pygame.draw.rect(screen, (128,0,0), (300,x,50,25))
enemy = Enemy()
pygame.display.flip() #updates the whole screen
def main(): #my main loop
while True:
player.handle_keys()
for event in pygame.event.get
if event.type == pygame.QUIT:
running = False
if __name__ == '__main__': main()
The player does move but when the keys are pressed and the player moves the enemy disappears so i need help to fix it
Ext the player doesn't move when the arrow keys are held only when pressed
You were checking for keydown events in your player's handle_keys method. Any keydown events only register once until the next keyup. You want to use pygame.key.get_pressed() which returns a dict of all the pressed keys at any given moment. I've fixed it for you as well as cleaned the code up a little bit. You may want to consider using a delay or pygame's built-in Clock class for controlling framerates. If you notice, I had to change your movements to very tiny numbers (0.05 from 0.5) because of how quickly you update your frames. Adding in time.sleep() or the pygame clock would fix this.
import pygame
import os
import random
from pygame.locals import * # Constants
import math
import sys
import random
pygame.init()
screen=pygame.display.set_mode((1280,720)) #(length,height)
screen_rect=screen.get_rect()
background = pygame.Surface(screen.get_size())
background.fill((255,255,255)) # fill the background white
White = (255,255,255)
class Player(pygame.sprite.Sprite):
def __init__(self):
self.rect = pygame.draw.rect(screen, (0,0,128), (50,560,50,25)) #(colour)(x-position,y-position,width,height)
self.dist = 100
def draw_rect(self,x,y): # This is my code which should make the player move
screen.blit(background, (0, 0)) #If this isn't included then when the rectangle moves it's old positon will still be on the screen
self.rect = self.rect.move(x*self.dist, y*self.dist); pygame.draw.rect(screen, (0, 0, 128), self.rect)
pygame.display.update()
def handle_keys(self): # code to make the character move when the arrow keys are pressed
keys = pygame.key.get_pressed()
if keys[K_LEFT]:
self.draw_rect(-0.05,0)
elif keys[K_RIGHT]:
self.draw_rect(0.05,0)
elif keys[K_UP]:
self.draw_rect(0,-0.05)
elif keys[K_DOWN]:
self.draw_rect(0,0.05)
elif keys[K_SPACE]:
self.draw_rect(2,-3)
if self.rect.right > 1400:
self.rect.right = 1400
if self.rect.left < 0:
self.rect.left = 0
if self.rect.bottom > 500:
self.rect.bottom = 500
if self.rect.top < 0:
self.rect.top = 0
class Enemy(pygame.sprite.Sprite): # the enemy class which works fine
def __init__(self):
x = random.randint(50,450)
self.rect = pygame.draw.rect(screen, (128,0,0), (300,x,50,25))
player = Player()
enemy = Enemy()
def main(): #my main loop
running = True
while running:
player.handle_keys()
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
pygame.display.flip() #updates the whole screen
if __name__ == '__main__': main()

How to keep shooting as long as the shoot button is being held down

I recently worked a fire rate into my coding, however, I have to continuously press the fire button in order to shoot.
Is there a way to handle KEYDOWN events so that instead of firing one bullet when I press the fire button, bullets fire periodically so long as I'm holding down the fire button?
Working code is as follows;
Main game module
import pygame
from constants import *
from player import Player
from Projectile import Projectile
from pygame.math import Vector2
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)
projectiles = pygame.sprite.Group()
clock = pygame.time.Clock()
previous_time = pygame.time.get_ticks()
speed = 12
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 == pygame.K_LEFT:
vel = Vector2(-speed, 0)
elif event.key == pygame.K_RIGHT:
vel = Vector2(speed, 0)
elif event.key == pygame.K_UP:
vel = Vector2(0, -speed)
elif event.key == pygame.K_DOWN:
vel = Vector2(0, speed)
if event.key in (pygame.K_LEFT, pygame.K_RIGHT, pygame.K_UP, pygame.K_DOWN):
current_time = pygame.time.get_ticks()
if current_time - previous_time > 500:
previous_time = current_time
projectiles.add(Projectile(player.rect.x, player.rect.y, vel))
# ----- Game Logic
all_sprites_list.update()
projectiles.update()
screen.fill(GREEN)
all_sprites_list.draw(screen)
projectiles.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.fire_rate = 1
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 *
from pygame.math import Vector2
BULLET_IMG = pygame.Surface((4, 4))
BULLET_IMG.fill(RED)
class Projectile(pygame.sprite.Sprite):
def __init__(self, x, y, vel):
super().__init__()
self.image = BULLET_IMG
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
self.vel = Vector2(vel)
def update(self):
self.rect.move_ip(self.vel)
Any help would be greatly appreciated!
If you're not interested in the fact that a key is pressed, but rather that a key is held down, use pygame.key.get_pressed to get the keyboard state.
One way to solve your issue is to create a dict that maps each arrow key to a vector, and then simply iterate that dict and check if the specific key is pressed, something like this:
keymap = {
pygame.K_LEFT: Vector2(-speed, 0),
pygame.K_RIGHT: Vector2(speed, 0),
pygame.K_UP: Vector2(0, -speed),
pygame.K_DOWN: Vector2(0, speed)
}
while not done:
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
current_time = pygame.time.get_ticks()
pressed = pygame.key.get_pressed()
for key in keymap:
if pressed[key]:
if current_time - previous_time > 500:
previous_time = current_time
projectiles.add(Projectile(player.rect.x, player.rect.y, keymap[key]))
Some further notes:
You can add sprites to multiple groups, and it usually makes sense to add all sprites to a groups that holds all sprites to keep the main loop simple.
You already have a group called all_sprites_list, so use it like this. Just add all new projectiles to that groups, also, and call update/draw only on that very group:
...
if current_time - previous_time > 500:
previous_time = current_time
Projectile(player.rect.x, player.rect.y, keymap[key], all_sprites_list, projectiles)
# ----- Game Logic
all_sprites_list.update()
screen.fill(GREEN)
all_sprites_list.draw(screen)
pygame.display.flip()
...
and in Projectile.py:
...
class Projectile(pygame.sprite.Sprite):
def __init__(self, x, y, vel, *groups):
super().__init__(groups)
...

How can I make Pygame check if two images are colliding?

I've tried everything and cannot get how I check if my two blocks have collided.
Here's my code:
import pygame
import random
pygame.init()
display_width = 600
display_height = 300
class player:#Just info for player
width = 30
height = 30
x = display_width // 2
y = display_height - height - 5
a = x + 30
pic = 'SnakePart.png'
thing = pygame.image.load(pic)
def place(x,y):#function for placing player object
gameDisplay.blit(player.thing, (player.x,player.y))
class enemy:#enemy info class
width = 30
height = 30
x = random.randint(0,display_width - width)
y = 1
a = x + 30
pic = 'Apple.png'
thing = pygame.image.load(pic)
speed = 10#sets speed
def change_x():
enemy.x = random.randint(0,display_width - enemy.width)
def change_y():
enemy.y += enemy.speed
def make(x,y):#set up funtion
gameDisplay.blit(enemy.thing, (x,y))
def respawn():#reseting enemy entity
enemy.y = 1
gameDisplay.blit(enemy.thing, (enemy.x,enemy.y))
player.thing#uses the variables in the classes to set up the images for use
enemy.thing
black = (0,0,0)
white = (255,255,255)
player_height = 30
player_width = 30
clock = pygame.time.Clock()
x_change = 0#This is to make movment
gameDisplay = pygame.display.set_mode((display_width,display_height))
pygame.display.set_caption('Bullet Hell.')
dodged = 0#counter will be used in the more polished vesion.
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
if event.type == pygame.KEYDOWN:#Checks for keypress, to make player entity move
if event.key == pygame.K_RIGHT:
x_change = 5
if event.key == pygame.K_LEFT:
x_change = -5
if event.type == pygame.KEYUP:
if event.key == pygame.K_RIGHT or pygame.K_LEFT:
x_change = 0
player.x += x_change
gameDisplay.fill(black)
enemy.make(enemy.x,enemy.y)
player.place(player.x,player.y)
enemy.change_y()
if enemy.y > display_height:#Brings enemy back to top once it has gotten to th bottom
enemy.change_x()
dodged += 1
enemy.respawn()
pygame.display.update()
clock.tick(60)
It's all really the collision and I think I'll be good. Oh yeah, if you guys could also tell me how to display text that would be great!
Take a look at the pygame.Rect class and its collision detection methods. Give your objects rects as attributes which you get by calling the .get_rect() method of the images/surfaces. Update the coordinates of these rects each frame and in your main loop call player.rect.colliderect(enemy.rect) to check if the two rects collide.
import pygame
import random
pygame.init()
BLACK = pygame.Color('black')
display = pygame.display.set_mode((600, 300))
# Create a rect with the dimensions of the screen at coords (0, 0).
display_rect = display.get_rect()
clock = pygame.time.Clock()
# SNAKE_IMAGE = pygame.image.load('SnakePart.png').convert_alpha()
# APPLE_IMAGE = pygame.image.load('Apple.png').convert_alpha()
# Replacement images.
SNAKE_IMAGE = pygame.Surface((30, 30))
SNAKE_IMAGE.fill((30, 150, 0))
APPLE_IMAGE = pygame.Surface((30, 30))
APPLE_IMAGE.fill((150, 30, 0))
class Player:
def __init__(self):
self.x = display_rect.w // 2
self.y = display_rect.h - 30 - 5
self.image = SNAKE_IMAGE
# Create a rect with the size of the image at coords (0, 0).
self.rect = self.image.get_rect()
# Set the topleft coords of the rect.
self.rect.x = self.x
self.rect.y = self.y
self.x_change = 0
def update(self):
"""Move the player."""
self.x += self.x_change
# Always update the rect, because it's
# needed for the collision detection.
self.rect.x = self.x
def draw(self, display):
display.blit(self.image, self.rect)
class Enemy:
def __init__(self):
self.x = random.randint(0, display_rect.w - 30)
self.y = 1
self.image = APPLE_IMAGE
# You can also pass the coords directly to `get_rect`.
self.rect = self.image.get_rect(topleft=(self.x, self.y))
self.speed = 10
def change_x(self):
self.x = random.randint(0, display_rect.w - self.rect.w)
self.rect.x = self.x
def change_y(self):
self.y += self.speed
self.rect.y = self.y
def draw(self, display):
display.blit(self.image, self.rect)
def reset(self):
"""Reset self.y position."""
self.y = -30
player = Player()
enemy = Enemy()
dodged = 0
done = False
while not done:
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_RIGHT:
player.x_change = 5
if event.key == pygame.K_LEFT:
player.x_change = -5
if event.type == pygame.KEYUP:
if event.key == pygame.K_RIGHT or pygame.K_LEFT:
player.x_change = 0
# Game logic.
player.update()
enemy.change_y()
# Brings enemy back to top once it has gotten to th bottom
if enemy.y > display_rect.h:
enemy.change_x()
dodged += 1
enemy.reset()
# Check if the player and the rect collide.
if player.rect.colliderect(enemy.rect):
print('Collided!')
# Draw everything.
display.fill(BLACK)
enemy.draw(display)
player.draw(display)
pygame.display.update()
clock.tick(60)
pygame.quit()
I've changed some more things (btw, better call the images self.image not thing ;)) especially in the classes:
The attributes of the classes should be in __init__ methods to make them instance attributes instead of class attributes (which get shared by all instances). Also, check out how to create instances of your classes.
The methods should all have self as their first parameter (that's a reference to the instance). To access the attributes inside of the classes prepend them with self, e.g. self.x += self.x_change.
The player.x += x_change line fits better inside the Player class' update method, so you can just update the position and other player attributes by calling player.update().
There's a convention that class names should be uppercase MyClass whereas instances should have lowercase names my_instance.

Categories

Resources