pygame Pong - how to attribute my scoring system and collision detection - pygame

Hey I'm working on pong and regardless of how hard I try, I keep facing the same problem; the scoring system doesn't appear on the window when I run the code.
I was told I need to initialize attributes such as scoring system, ball and paddles and I guess I did so for the ball and paddle even though I don't really get what that means since this course is the farthest thing from being kind to students who are new to python. But I guess I didn't do so for the scoring system since it's not appearing on the screen.
I've been struggling with these past few weeks and still haven't found a way to fix this and I need to hand in this next week which is making me freak out.
I would appreciate it if you can explain me what did I do wrong and what initializing attribute means and also check my codes for collision detection!
Thank you all SO MUCH!! (By the way, this always happens and confuses me a lot since I get no error message but the scoring system is just not working as I expected)
# Pong V2
# Pong game needs two players and players try to prevent the ball from hitting
# the edge of the screen of their side. If the ball hits the edge of the window,
# the counterpart of the player who couldn't defence the wall gains a point.
# When one of the players reach 11 points, game ends and the player with higher
# points win the game. Players and move the paddles of their own by pressing
# some keys and ball bounces off when the ball has hit the front part of the
# paddle but passes through when they hit the back part of the paddle.
# wall, game continuing until the player presses 'x' button to close the window,
# paddles on the screen but cannot be moved.
# Version 2 of Pong implies the scoring system and game ending when someone hits
# 11 scores. Also, now collision detection for the paddles and the ball has been
# added as a new feature even though still player cannot move the paddles.
import pygame
from random import randint
def main():
# initialize all pygame modules (some need initialization)
pygame.init()
# create a pygame display window
pygame.display.set_mode((500, 400))
# set the title of the display window
pygame.display.set_caption('Pong')
# get the display surface
w_surface = pygame.display.get_surface()
# create a game object
game = Game(w_surface)
# start the main game loop by calling the play method on the game object
game.play()
# quit pygame and clean up the pygame window
pygame.quit()
class Game:
def __init__(self, surface):
# Initialize a Game.
self.surface = surface
self.bg_color = pygame.Color('black')
self.FPS = 60
self.game_Clock = pygame.time.Clock()
self.close_clicked = False
self.continue_game = True
#iniotialize the ball
self.ball = Ball('white', 5, [250, 200], [1, 2], self.surface)
self.max_frames = 150
self.frame_counter = 0
# initialize paddles
self.paddleA = pygame.Rect((70, 170), (10, 60))
self.paddleB = pygame.Rect((415, 170), (10, 60))
# initialize paddles
self.scoreA = 0
self.scoreB = 0
def draw_score_A(self):
# this method draws the player's score in the top-left corner of the
# game window.
strscoreA = str(self.scoreA)
font_color = pygame.Color('white')
font_bg = pygame.Color('black')
font = pygame.font.SysFont("arial", 72)
text_img = font.render(strscoreA, True, font_color, font_bg)
text_pos = (0, 0)
self.surface.blit(text_img, text_pos)
def draw_score_B(self):
# this method draws the player's score in the top-right corner of the
# game window.
strscoreB = str(self.scoreB)
font_color = pygame.Color('white')
font_bg = pygame.Color('black')
font = pygame.font.SysFont("arial", 72)
text_img = font.render(strscoreB, True, font_color, font_bg)
text_pos = (425,0)
self.surface.blit(text_img, text_pos)
def update_score(self):
# check if the ball has hit the left or right side edge and update score
# if the ball hit left side, scoreB goes up by 1 and if the ball hit the right
# side the scoreA goes up by 1.
if self.ball.center[0] < self.ball.radius:
self.scoreB += 1
if self.ball.center[0] + self.ball.radius > self.surface.get_width():
self.scoreA += 1
return self.scoreA, self.scoreB
def play(self):
# Play the game until the player presses the close box.
# - self is the Game that should be continued or not.
while not self.close_clicked: # until player clicks close box
# play frame
self.handle_events()
self.draw()
self.update_score()
self.draw_score_A()
self.draw_score_B()
if self.continue_game:
self.update()
self.decide_continue()
self.game_Clock.tick(self.FPS) # run at most with FPS Frames Per Second
def handle_events(self):
# Handle each user event by changing the game state appropriately.
# - self is the Game whose events will be handled
events = pygame.event.get()
for event in events:
if event.type == pygame.QUIT:
self.close_clicked = True
def draw(self):
# Draw all game objects.
self.surface.fill(self.bg_color) # clear the display surface first
# draw ball on the surface
self.ball.draw()
# draw both paddles on the surface
paddleA = pygame.Rect((70, 170), (10, 60))
self.paddleA = pygame.draw.rect(self.surface, (255, 255, 255), paddleA)
paddleB = pygame.Rect((415, 170), (10, 60))
self.paddleB = pygame.draw.rect(self.surface, (255, 255, 255), paddleB)
pygame.display.update() # make the updated surface appear on the display
def collision_detection(self):
# figure out if the paddle and the ball has collide or not.
# If the ball has hit the front of the paddle, it is recognizes as
# a collision and bounces off to the opposite direction. However
# if the ball has hit the backside of the paddle, this is not
# considered as a collision and this will not make the ball bounce of but
# go through the paddle.We need to check if the center of the ball has passed
# the center of the paddle or not and for this we will use rect.collidepoint
if self.paddleA.collidepoint(self.center) and self.velocity[index] > 0 is True:
self.velocity[index] = self.velocity[index]
elif self.paddleA.collidepoint(self.center) and self.velocity[index] < 0 is True:
self.velocity[index] = - self.velocity[index]
elif self.paddleB.collidepoint(self.center) and self.velocity[index] > 0 is True:
self.velocity[index] = - self.velocity[index]
elif self.paddleB.collidepoint(self.center) and self.velocity[index] < 0 is True:
self.velocity[index] = self.velocity[index]
def update(self):
# Update the game objects for the next frame.
self.ball.move()
self.frame_counter += self.frame_counter
def decide_continue(self):
# Check and remember if the game should continue
# if the score of one of the players reaches 11, the game should end.
# thus we need to check if anyone's score has reached 11 or not and
# decide if we'll continue the game or not.
if self.scoreA == 11 or self.scoreB == 11 :
self.continue_game = False
class Ball:
# An object in this class represents a ball that moves
def __init__(self, ball_color, ball_radius, ball_center, ball_velocity,
surface):
# Initialize a ball.
# - self is the ball to initialize
# - color is the pygame.Color of the ball
# - center is a list containing the x and y int
# coords of the center of the dot
# - radius is the int pixel radius of the ball
# - velocity is a list containing the x and y components
# - surface is the window's pygame.Surface object
self.color = pygame.Color(ball_color)
self.radius = ball_radius
self.center = ball_center
self.velocity = ball_velocity
self.surface = surface
def move(self):
# Change the location of the ball by adding the corresponding
# speed values to the x and y coordinate of its center
# we need the height and width of the screen to determine when ball
# should change their direction of motion (bounce)
screen_width = self.surface.get_width()
screen_height = self.surface.get_height()
# updates the ball's position based on its velocity and also bounces the
# ball off a wall if it gets too close
screen_size = (screen_width, screen_height)
for index in range(0, len(self.center)):
self.center[index] += self.velocity[index]
if (self.center[index] <= 0 + self.radius or self.center[index] >=
screen_size[index] - self.radius):
self.velocity[index] = -self.velocity[index]
def draw(self):
# Draw the ball on the surface
pygame.draw.circle(self.surface, self.color, self.center, self.radius)
main()

The code is calling draw() (to repaint and flush the screen), and then calling draw_score_A() and draw_score_B() without flushing. So the changes made by the draw_score_ functions are never seen by the user.
If you have a function draw() - make it draw everything. This keeps all the drawing and flushing operations in a single place. Sure the draw() function calls other functions to do the painting, but it's all starts from one place.
def draw( self ):
# Draw all game objects.
# clear the display surface first
self.surface.fill( self.bg_color )
# draw ball on the surface
self.ball.draw()
# draw both paddles on the surface
pygame.draw.rect( self.surface, ( 255, 255, 255 ), self.paddleA )
pygame.draw.rect( self.surface, ( 255, 255, 255 ), self.paddleB )
# Paint the scores
self.draw_score_A()
self.draw_score_B()
# make the updated surface appear on the display
pygame.display.update()
Also, your draw() function seems to be re-defining paddleA and paddleB as part of the drawing. I corrected this in the version above.

Related

Pygame keeps flickering even though display.update is only called once. Couldn't find an applicable answer from previous posts

I can't seem to figure out why my groups Pygame code keeps flickering when we run it. pygame.display.update is only called once, but our background seems to be potentially causing the issue.
Any an all help would be greatly appreciated! :)
Here's a link to my Replit with the code:
https://replit.com/#LukaLUSV6912/Santa-vs-Evil-Elves-Game?v=1
We are trying to get rid of the flickering from the Pygame animation and implement a winning and loosing screen based off the visibility of the elves(enemies) when the timer runs down to 0
Instructions: move with right + left arrow keys and fire snowballs with spacebar
'''"""
import pygame, random
pygame.init() # initialize pygame managers
# create a window
w = 600
h = 600
win = pygame.display.set_mode((w,h)) # define window variable
# pygame.display.set_caption("Read carefully.") # uncomment & edit to caption the window
#======================== Variables & functions ===================================================
img_size = (50,100)
img_size2 = (30,30)
# class that creates Santa
class Santa:
def __init__(self,color,x,y):
self.color = color
self.x = x
self.y = y
self.img = pygame.image.load("santaimg.png").convert_alpha()
self.img = pygame.transform.scale(self.img, img_size)
self.center=(x,y)
# The methods Right and Left allow Santa to move right and left and have boundries
def Right(self):
if self.x <551:
self.x +=20
self.center=(self.x,self.y)
# self.rect=self.img.get_rect(center=self.center)
def Left(self):
if self.x >0:
self.x -=20
self.center=(self.x,self.y)
# self.rect=self.img.get_rect(center=self.center)
# method that allows the bubbles to be drawn on the screen
def show(self):
# self.img = pygame.image.load("santaimg.png").convert()
# self.rect=self.img.get_rect(center=self.center)
win.blit(self.img, self.center)
#pygame.draw.ellipse(win,self.color,self.img)
#Class that creates the elves
class Elves():
def __init__(self, color, pos_x, pos_y):
self.color = color
self.pos_x= pos_x
self.pos_y = pos_y
self.square = 20
self.velocity = 0 # elves start stationary
self.box = pygame.Rect(self.pos_x,self.pos_y,self.square,self.square)
self.img2 = pygame.image.load("elfimg.png").convert_alpha()
self.img2 = pygame.transform.scale(self.img2,img_size2)
#self.area = pygame.Surface((self.square,self.square))
self.draw = True
# method that displays the elves
def Show(self):
if (self.draw == True):
win.blit(self.img2, (self.pos_x, self.pos_y))
# method that makes elves dissapear if snowball hits them
def dissapear(self, box):
global Dis
if (self.draw):
if self.box.colliderect(box): # box is the rect for elf
Dis += 1 # Each time user hits elf with snowball, value of Dis goes up one
self.draw = False
if (Dis == 20): # New victory image shows once 20 collisions occur
print("Victory! You Saved Christmas!")
global BG
BG = False # Makes it so background image stops refreshing
global SUp
SUp = False #Snowballs stop moving
gameDisplay = pygame.display.set_mode((w,h)) # Background Code - https://stackoverflow.com/questions/65009141/in-pygame-how-do-i-make-an-image-the-background#:~:text=Load%20a%20back%20ground%20image%20%28e.g.%20%27background.jpg%27%29%2C%20scale,pygame.transform.smoothscale%20%28background%2C%20gameDisplay.get_size%20%28%29%29%20gameDisplay.blit%20%28background%2C%20%280%2C%200%29%29
background = pygame.image.load('Victory.png').convert() #Retrieve the image
background = pygame.transform.smoothscale(background, gameDisplay.get_size()) # Sets the image size to the window size
gameDisplay.blit(background, (0, 0)) # Draws the image onto the screen
global running
running = False
# allows the elves to move up and down continuously
def Moving (self):
self.pos_y += self.velocity # Elves move based on velocity value
if self.pos_y >= 0 and self.pos_y < h/2.4: # Elves accelerate downwards when in top half of screen
self.velocity +=.3 # Velocity goes up, pos_y goes down
if self.pos_y > h/2.4: # Elves accelerate upwards when in bottom half of screen
self.velocity -= .3 # Velocity goes down, pos_y goes up
self.box = pygame.Rect(self.pos_x,self.pos_y,self.square,self.square)
#Class that creates snowballs
class Snow:
def __init__(self,color,x,y):
self.x = x
self.y = y
self.color = color
self.height = 15
self.length = 15
self.draw = True
self.snowy = pygame.draw.ellipse(win,self.color,(self.x,self.y,self.height,self.length))
# Show snowballs on screen
def show(self):
if (self.draw == True):
self.snowy = pygame.draw.ellipse(win,self.color,self.snowy)
#Snowballs go up
def upward(self):
global SUp
if SUp == True:
self.snowy.y -= 5
self.snowy = pygame.draw.ellipse(win,self.color,self.snowy)
# class that creates a timer
class Timer:
def __init__(self,limit):
self.limit = limit
self.clock = pygame.time.Clock()
self.start=pygame.time.get_ticks() # get starter tick at Timer instantiation
self.timeLeft = self.countDown()
def countDown(self):
'''Note: Will count down based on time passed, not frame rate, or call frequency.
Retuurns whole value time in seconds (int)'''
currTime=(self.start + pygame.time.get_ticks())/1500 #calculate how many seconds
# if self.timeLeft > 0:
return int(self.limit - currTime) # returns whole second numbers
#================================ Animation loop ===================================================
class Manager:
def __init__(self):
self.colors = ((255,255,255),(0,0,0),(173,216,230),(252,36,2),(0,0,255))
self.ElvesList = []
self.snowballs=[]
global SUp
SUp = True
global BG
BG = True
global Dis
Dis = 0
def main(self):
global running
running = True
clock = pygame.time.Clock()
# code that allows elves to show, everytime you play the game the elves have a different x and y
for i in range(20):
x = random.randint(0,w-20)
y= random.randint(0,h/3)
self.ElvesList.append(Elves(self.colors[2],x,y)) # instantiates the elves class
# calls Santa class in a variable called "SantaC"
SantaC= Santa(self.colors[3],w/2,h-50)
while running:
# clear window (comment out to have trace behind animation)
if (BG == True): # Refresh of image can be turned on/off
gameDisplay = pygame.display.set_mode((w,h)) # Background Code - https://stackoverflow.com/questions/65009141/in-pygame-how-do-i-make-an-image-the-background#:~:text=Load%20a%20back%20ground%20image%20%28e.g.%20%27background.jpg%27%29%2C%20scale,pygame.transform.smoothscale%20%28background%2C%20gameDisplay.get_size%20%28%29%29%20gameDisplay.blit%20%28background%2C%20%280%2C%200%29%29
background = pygame.image.load('SnowBackground.webp').convert() #Retrieve the image
background = pygame.transform.smoothscale(background, gameDisplay.get_size()) # Sets the image size to the window size
gameDisplay.blit(background, (0, 0)) # Draws the image onto the screen
# for every elf created in line 128 they will all show and move, methods of the elves are being called
for evil in self.ElvesList:
evil.Show()
evil.Moving()
# method that allows Santa to be shown
SantaC.show()
#borrowed code in order to display score in left corner (line 141-152)
font = pygame.font.Font("freesansbold.ttf",32)
textx = 10
texty = 10
timer = Timer(27) # 27 is used because there is a 2 second delay to run the code
timeLeft =timer.countDown()
# function that displays timer
def showtimer(x,y):
timing = font.render("Timer :" +str(timeLeft),True,(self.colors[4]))
win.blit(timing,(x,y))
showtimer(textx,texty) # determines where the timer will be displayed
# when the game reaches 0 seconds on the timer, "gameover" is displayed to the terminal
if timeLeft<=0:
gameDisplay = pygame.display.set_mode((w,h)) # Background Code - https://stackoverflow.com/questions/65009141/in-pygame-how-do-i-make-an-image-the-background#:~:text=Load%20a%20back%20ground%20image%20%28e.g.%20%27background.jpg%27%29%2C%20scale,pygame.transform.smoothscale%20%28background%2C%20gameDisplay.get_size%20%28%29%29%20gameDisplay.blit%20%28background%2C%20%280%2C%200%29%29
background = pygame.image.load('Defeat.png').convert() #Retrieve the image
background = pygame.transform.smoothscale(background, gameDisplay.get_size()) # Sets the image size to the window size
gameDisplay.blit(background, (0, 0)) # Draws the image onto the screen
for s in self.snowballs:
s.show()
s.upward()
# Sees if the rect of snowball and rect of elves has collided, if so the elf dissapears
for evil in self.ElvesList:
for s in self.snowballs:
evil.dissapear(s.snowy)
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False # stops animation
if event.type == pygame.KEYDOWN:
# handles key press event
if event.key == pygame.K_SPACE:
# When the spacebar is pressed, a snowball will be shot out of Santas location
self.snowballs.append(Snow(self.colors[0],17.5+ SantaC.x,SantaC.y))
if event.key == pygame.K_RIGHT or event.key == pygame.K_d: # santa moves right if right key is clicked. Calls method from Santa's class.
SantaC.Right()
if event.key == pygame.K_LEFT or event.key == pygame.K_a: # santa moves left if left key is clicked. Calls method from Santa's class.
SantaC.Left()
# snowballs will be shown and move upward
#================== Animation control ===================
pygame.display.update()
clock.tick(30) # framerate in fps (30-60 is typical)
Manager().main()
The code is doing a lot of image and font loading repeatedly in the main loop. It's just re-loading the same thing, so this should be moved to before the loop. But I suspect the flickering is caused by the repeated calls to pygame.display.set_mode((w,h)) which is typically only called once, or when handling a window-resize event.
So maybe you want something like this for your main loop:
def showtimer(x,y,font,timeLeft,win):
timing = font.render("Timer :" +str(timeLeft),True,(self.colors[4]))
win.blit(timing,(x,y))
# Set the window size, and setup the timer
gameDisplay = pygame.display.set_mode((w,h))
timer = Timer(27) # 27 because there is a 2 second delay to run the code
timer_x = 10
timer_y = 10
# Load & scale any images, fonts, etc.
font = pygame.font.Font("freesansbold.ttf",32)
snowBackground = pygame.image.load('SnowBackground.webp').convert()
snowBackground = pygame.transform.smoothscale( snowBackground, gameDisplay.get_size())
defBackground = pygame.image.load('Defeat.png').convert()
defBackground = pygame.transform.smoothscale( defBackground, gameDisplay.get_size())
victBackground = pygame.image.load('Victory.png').convert()
victBackground = pygame.transform.smoothscale( victBackground, gameDisplay.get_size())
while running:
timeLeft = timer.countDown()
# clear window (comment out to have trace behind animation)
if (BG == True): # Refresh of image can be turned on/off
# when the game reaches 0 seconds on the timer, "gameover" is displayed to the terminal. Otherwise it's a snowy background
if Dis >= 20:
background = victBackground # player won!
elif timeLeft<=0:
background = defBackground # player defeated
else:
background = snowBackground # still playing
gameDisplay.blit( background, (0, 0) )
# paint & update Evil Elves
for evil in self.ElvesList:
evil.Show()
evil.Moving()
# method that allows Santa to be shown
SantaC.show()
# paint the timer
showtimer( timer_x, timer_y, font, timeLeft, win )
# flush the updates to the window
pygame.display.update()
# handle events & user input
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False # stops animation
# ... etc.
clock.tick( 60 )
I'm not 100% sure how the timer system works, so I just re-arranged it to how I guess it functions. Errors and Omissions should be expected.
The upshot of the changes above is that anything that can be pre-calculated is done outside of the loop. There absolutely no need to re-load and re-scale a background image to the window size every update loop. If you do need to handle window re-size events, do that in an event handler.

How to blit numbers in pygame?

Currently, I am working on a game in which you are asked a mathematical question such as 2 + 1 and numbers will fall from the top of the screen. The player has to click the right answer before it falls below the screen. However, I don't want to download images of the numbers because it would waste lots of time. Is there a way to draw or blit numbers instead? If there is, can the numbers be in a circle shape instead of a rectangle?
EDIT: I could create the numbers by displaying them as text. However, that would mean I have to create hundreds of different rectangles for each possible answer. My question then is, is there a way for me to tell Python to generate numbers and place them on a rectangle without me having to do it manually?
One solution would be to create a class in which you store the actual answer, the text surface and the rect for the collision detection. I use a pygame.sprite.Sprite subclass here, but you can do the same with a normal class. When a new question gets asked, you can just create a bunch of instances and add them to a sprite group, so that you can update them altogether in the main loop. You can use the pygame.Rect.collidepoint method for the collision detection.
import random
import pygame as pg
from pygame.math import Vector2
pg.init()
BLUE = pg.Color('dodgerblue1')
FONT = pg.font.Font(None, 42)
class Answer(pg.sprite.Sprite):
def __init__(self, pos, number):
super().__init__()
# Store the actual number, so that we can compare it
# when the user clicks on this object.
self.number = number
# Render the new text image/surface.
self.image = FONT.render(str(number), True, BLUE)
# A rect with the size of the surface, used for collision
# detection and rendering.
self.rect = self.image.get_rect(topleft=pos)
self.vel = Vector2(0, random.uniform(1, 4))
self.pos = Vector2(pos)
def update(self):
self.pos += self.vel
self.rect.center = self.pos
if self.rect.top > 480: # Screen bottom.
self.kill() # Remove the sprite from all groups.
def main():
screen = pg.display.set_mode((640, 480))
clock = pg.time.Clock()
all_sprites = pg.sprite.Group()
done = False
while not done:
for event in pg.event.get():
if event.type == pg.QUIT:
done = True
elif event.type == pg.MOUSEBUTTONDOWN:
if event.button == 3: # Right mouse button.
# Add 20 numbers (Answer objects).
for _ in range(20):
number = random.randrange(100)
all_sprites.add(Answer((random.randrange(620), -20), number))
elif event.button == 1: # Left mouse button.
# See if the user clicked on a number.
for answer in all_sprites:
# event.pos is the mouse position.
if answer.rect.collidepoint(event.pos):
print(answer.number)
all_sprites.update()
screen.fill((30, 30, 30))
all_sprites.draw(screen)
pg.display.flip()
clock.tick(30)
if __name__ == '__main__':
pg.init()
main()
pg.quit()
(Right click to spawn the numbers, left click to touch single numbers.)

Moving a Sprite in the direction of an angle in Pygame [duplicate]

This question already has answers here:
How to turn the sprite in pygame while moving with the keys
(1 answer)
Image rotation while moving
(2 answers)
Closed 2 years ago.
Im trying to move a sprite in the direction of an angle in pygame, using the left & right arrow keys to change the direction of the sprite but when I press the up key, the sprite just moves right. I have 2 variables that take speed and a velocity calculation and adds them together (vel_x & vel_y), I then add this to the position (orientation) of the sprite but it isnt following the sprite orientation when it moves forward (if keybd_tupl[K_UP]).
import pygame
import random
import math
from pygame.locals import *
window_wid = 800
window_hgt = 600
frame_rate = 50
delta_time = 1 / frame_rate
STATE_READY = 2
def game_loop_inputs():
# look in the event queue for the quit event
quit_ocrd = False
for evnt in pygame.event.get():
if evnt.type == QUIT:
quit_ocrd = True
return quit_ocrd
def game_loop_update(circle_hitbox):
# start by assuming that no collisions have occurred
circle_hitbox["col"] = False
# return the new state of the rotating line and the circle hitbox
return circle_hitbox
def game_loop_render(circle_hitbox, window_sfc):
# clear the window surface (by filling it with black)
window_sfc.fill( (0,0,0) )
# draw the circle hitbox, in red if there has been a collision or in white otherwise
if circle_hitbox["col"]:
#pygame.draw.circle(window_sfc, (255, 0, 0), circle_hitbox["pos"], circle_hitbox["rad"])
rotated_damage = pygame.transform.rotate(circle_hitbox["damage"], circle_hitbox["angle"])
window_sfc.blit(rotated_damage, circle_hitbox["pos"])
else:
#pygame.draw.circle(window_sfc, (255, 255, 255), circle_hitbox["pos"], circle_hitbox["rad"])
rotated_image = pygame.transform.rotate(circle_hitbox["sprite"], circle_hitbox["angle"])
window_sfc.blit(rotated_image, circle_hitbox["pos"])
# update the display
pygame.display.update()
def main():
# initialize pygame
pygame.init()
# create the window and set the caption of the window
window_sfc = pygame.display.set_mode( (window_wid, window_hgt) )
pygame.display.set_caption('"Toy" for the MDA Exercise')
# create a clock
clock = pygame.time.Clock()
# this is the initial game state
game_state = STATE_READY
#####################################################################################################
# these are the initial game objects that are required (in some form) for the core mechanic provided
#####################################################################################################
# this game object is a circulr
circle_hitbox = {}
circle_hitbox["pos"] = (window_wid // 2, window_hgt // 2)
circle_hitbox["rad"] = 30
circle_hitbox["col"] = False
circle_hitbox["sprite"] = pygame.image.load("cars_racer_{}.png".format(random.randint(1, 3)))
circle_hitbox["damage"] = pygame.image.load("cars_racer_red.png")
circle_hitbox["crash"] = pygame.image.load("explosion.png")
circle_hitbox["damaged"] = False
circle_hitbox["angle"] = 0
speed = 10.0
vel_x = speed * math.cos(circle_hitbox["angle"] * (math.pi / 180))
vel_y = speed * math.sin(circle_hitbox["angle"] * (math.pi / 180))
# the game loop is a postcondition loop controlled using a Boolean flag
closed_flag = False
while not closed_flag:
#####################################################################################################
# this is the "inputs" phase of the game loop, where player input is retrieved and stored
#####################################################################################################
closed_flag = game_loop_inputs()
keybd_tupl = pygame.key.get_pressed()
if keybd_tupl[K_UP]:
circle_hitbox["pos"] = (circle_hitbox["pos"][0] + vel_x, circle_hitbox["pos"][1] + vel_y)
print(vel_y)
if keybd_tupl[K_LEFT]:
circle_hitbox["angle"] = (circle_hitbox["angle"] + 10.0)
if keybd_tupl[K_RIGHT]:
circle_hitbox["angle"] = (circle_hitbox["angle"] - 10.0)
#####################################################################################################
# this is the "update" phase of the game loop, where the changes to the game world are handled
#####################################################################################################
circle_hitbox = game_loop_update(circle_hitbox)
#####################################################################################################
# this is the "render" phase of the game loop, where a representation of the game world is displayed
#####################################################################################################
game_loop_render(circle_hitbox, window_sfc)
# enforce the minimum frame rate
clock.tick(frame_rate)
if __name__ == "__main__":
main()
It just isnt working & I dont know why.
You have to calculate the vel_x and vel_y in the while loop.
while not closed_flag:
closed_flag = game_loop_inputs()
keybd_tupl = pygame.key.get_pressed()
if keybd_tupl[K_UP]:
circle_hitbox["pos"] = (circle_hitbox["pos"][0] + vel_x, circle_hitbox["pos"][1] + vel_y)
print(vel_y)
if keybd_tupl[K_LEFT]:
circle_hitbox["angle"] -= 1.0
if keybd_tupl[K_RIGHT]:
circle_hitbox["angle"] += 1.0
# `math.radians` can be used instead of `* (math.pi / 180)`
vel_x = speed * math.cos(math.radians(circle_hitbox["angle"]))
vel_y = speed * math.sin(math.radians(circle_hitbox["angle"]))
Also, pass the negative angle to pygame.transform.rotate in the game_loop_render function:
rotated_damage = pygame.transform.rotate(circle_hitbox["damage"], -circle_hitbox["angle"])
The rotation probably still doesn't look right (I'm using some replacement images and they don't rotate correctly). Take a look at this answer if you want to know how to rotate pygame sprites and images around their center in pygame.

Recreating Flow in pygame [duplicate]

# User-defined functions
def main():
# initialize all pygame modules (some need initialization)
pygame.init()
# create a pygame display window
pygame.display.set_mode((500, 400))
# set the title of the display window
pygame.display.set_caption('Memory')
# get the display surface
w_surface = pygame.display.get_surface()
# create a game object
game = Game(w_surface)
# start the main game loop by calling the play method on the game
#object
game.play()
# quit pygame and clean up the pygame window
pygame.quit()
# User-defined classes
class Game:
# An object in this class represents a complete game.
def __init__(self, surface):
# Initialize a Game.
# - self is the Game to initialize
# - surface is the display window surface object
self.surface = surface
self.bg_color = pygame.Color('black')
self.FPS = 60
self.game_Clock = pygame.time.Clock()
self.close_clicked = False
self.continue_game = True
Tile.set_surface(self.surface)
grid_size = 4
self.create_grid(grid_size)
def create_grid(self, grid_size):
# Creates a grid of tiles that is grid_size x grid_size in size.
self.grid = [ ]
# this for loop creates each row in our grid
for row_num in range(grid_size):
new_row = self.create_row(row_num, grid_size)
self.grid.append(new_row)
def create_row(self, row_num, size):
# Create one row in a grid. Each row contains size Tiles. a
#row_num is
# required for calculating the tile's x,y coordinates on screen
# - row_num: the nth row of the grid being created
# - size : the number of tiles in the row
# returns the newly created row'
image_1=pygame.image.load('image1.bmp')
image_2=pygame.image.load('image2.bmp')
image_3=pygame.image.load('image3.bmp')
image_4=pygame.image.load('image4.bmp')
image_5=pygame.image.load('image5.bmp')
image_6=pygame.image.load('image6.bmp')
image_7=pygame.image.load('image7.bmp')
image_8=pygame.image.load('image8.bmp')
pygame_image_surfaces=[]
pygame_image_surfaces.append(image_1)
pygame_image_surfaces.append(image_2)
pygame_image_surfaces.append(image_3)
pygame_image_surfaces.append(image_4)
pygame_image_surfaces.append(image_5)
pygame_image_surfaces.append(image_6)
pygame_image_surfaces.append(image_7)
pygame_image_surfaces.append(image_8)
pygame_image_surfaces=pygame_image_surfaces+pygame_image_surfaces
random.shuffle(pygame_image_surfaces)
image_surfaces=pygame_image_surfaces
tile_height = self.surface.get_height() // size
tile_width = 3/4*self.surface.get_width() // size
one_row = [ ]
for col_num in range(size):
y = row_num * tile_height
x = col_num * tile_width
pos = (x,y)
one_tile = Tile(pos, tile_width, tile_height)
i=0
content = image_surfaces[i]
i+=1
one_tile.set_content(content)
one_row.append(one_tile)
return one_row
def play(self):
# Play the game until the player presses the close box.
# - self is the Game that should be continued or not.
while not self.close_clicked: # until player clicks close box
# play frame
self.handle_events()
self.draw()
if self.continue_game:
self.update()
self.decide_continue()
self.game_Clock.tick(self.FPS) # run at most with FPS Frames
#Per Second
def handle_events(self):
# Handle each user event by changing the game state
#appropriately.
# - self is the Game whose events will be handled
events = pygame.event.get()
for event in events:
if event.type == pygame.QUIT:
self.close_clicked = True
if event.type == pygame.MOUSEBUTTONDOWN:
self.handle_mouse_click(event)
def handle_mouse_click(self, event):
# responds to one mouse click on screen; that means changing the
# content of a tile if it is empty.
print("Screen was clicked at " + str(event.pos))
def draw(self):
# Draw all game objects.
# - self is the Game to draw
self.surface.fill(self.bg_color) # clear the display surface
#first
for row in self.grid:
for tile in row:
tile.draw()
pygame.display.update() # make the updated surface appear on the
def update(self):
# Update the game objects for the next frame.
# - self is the Game to update
pass
def decide_continue(self):
# Check and remember if the game should continue
# - self is the Game to check
return True
class Tile:
# A tile represents one location on a grid. Tiles hold content
# class attributes that are common to all tiles
surface = None
fg_color = pygame.Color("white")
bg_color = pygame.Color("black")
border_width = 3
#classmethod
def set_surface(cls, surface):
# sets the class attribute, surface
cls.surface = surface
def __init__(self, screen_position, width, height):
# initialize one instance of our Tile class. Tiles represent
# one 'position' in our board.
# - self: the tile being initialized
# - screen_position: the [x, y] coordinates to draw the tile at
# - width: the width of the tile
# - height: the height of the tile
self.screen_position = screen_position
self.content = ''
# create a rectangle defining our boundaries
x, y = screen_position
self.rect = pygame.Rect(x, y, width, height)
def draw_content(self):
image_1=pygame.image.load('image1.bmp')
image_2=pygame.image.load('image2.bmp')
image_3=pygame.image.load('image3.bmp')
image_4=pygame.image.load('image4.bmp')
image_5=pygame.image.load('image5.bmp')
image_6=pygame.image.load('image6.bmp')
image_7=pygame.image.load('image7.bmp')
image_8=pygame.image.load('image8.bmp')
pygame_image_surfaces=[]
pygame_image_surfaces.append(image_1)
pygame_image_surfaces.append(image_2)
pygame_image_surfaces.append(image_3)
pygame_image_surfaces.append(image_4)
pygame_image_surfaces.append(image_5)
pygame_image_surfaces.append(image_6)
pygame_image_surfaces.append(image_7)
pygame_image_surfaces.append(image_8)
pygame_image_surfaces=pygame_image_surfaces+pygame_image_surfaces
random.shuffle(pygame_image_surfaces)
image_surfaces=pygame_image_surfaces
for i in range(len(image_surfaces)):
Tile.surface.blit(i)
#Tile.surface.blit(text_img, text_pos)
def draw(self):
# draw the contents of a tile to its surface.
# - self: the tile being drawn
self.draw_content()
pygame.draw.rect(Tile.surface, Tile.fg_color, self.rect,
Tile.border_width)
def set_content(self, new_content):
# - self: the tile whose content is being updated
self.content = new_content
main()
Trying to create a memory game in pygame but I'm having problems trying to blit the images onto each individual tile and would like some help troubleshooting. What I'm trying to do is from the list of image files that are now surface objects, I would like to blit one onto each tile. For some reason though my logic is wrong. I'm not sure if this stuff should go in my game class or my tile class since its describing the tile rather than the game.
Tldr: don't know how to blit the images onto each tile from a list
First of all, t he code which defines and loads the images, can be simplified a lot:
il = ['image' + str(i) + '.bmp' for i in range(1,9)]
pygame_image_surfaces = [pygame.image.load(os.path.join(path, name)) for name in imagenames]
The image which is associated to a Tile is stored in the instance attribute self.content of the Tile object. Use this attribute to draw the tile:
class Tile:
# [...]
def draw_content(self):
image_rect = self.content.get_rect(center = self.rect.center)
Tile.surface.blit(self.content, image_rect)
def draw(self):
# draw the contents of a tile to its surface.
# - self: the tile being drawn
self.draw_content()
pygame.draw.rect(Tile.surface, Tile.fg_color, self.rect, Tile.border_width)
def set_content(self, new_content):
# - self: the tile whose content is being updated
self.content = new_content
Create 1 random list of images. And use this list to set the images for the entire grid of tiles:
class Game:
# [...]
def create_grid(self, grid_size):
# Creates a grid of tiles that is grid_size x grid_size in size.
imgnames = ['image' + str(i) + '.bmp' for i in range(1,9)]
image_surfaces = [pygame.image.load(os.path.join(path, name)) for name in imgnames]
image_surfaces = image_surfaces + image_surfaces
random.shuffle(image_surfaces)
self.grid = []
# this for loop creates each row in our grid
for row_num in range(grid_size):
new_row = self.create_row(row_num, grid_size, image_surfaces)
self.grid.append(new_row)
def create_row(self, row_num, size, images):
# Create one row in a grid. Each row contains size Tiles.
# required for calculating the tile's x,y coordinates on screen
# - row_num: the nth row of the grid being created
# - size : the number of tiles in the row
# returns the newly created row'
tile_height = self.surface.get_height() // size
tile_width = 3/4*self.surface.get_width() // size
new_row = []
for col_num in range(size):
pos = (row_num * tile_height + 10, col_num * tile_width + 10)
content = images[row_num*size + col_num]
one_tile = Tile(pos, tile_width, tile_height)
one_tile.set_content(content)
new_row.append(one_tile)
return new_row

Pygame: Why is my circle not being drawn onto my sprite's surface?

This is probably so simple, but I cannot see my error. Why is my ball not being drawn onto my sprite's surface and thus not appearing on the screen? When I change the 'draw ellipse' line in the class so that it is drawn onto the screen (instead of onto the surface), it shows. What am I doing wrong?
import pygame
BLACK = ( 0, 0, 0)
WHITE = (255, 255, 255)
RED = (255, 0, 0)
class Ball(pygame.sprite.Sprite):
"""This class represents the ball."""
def __init__(self, width, height):
""" Constructor. Pass in the balls x and y position. """
# Call the parent class (Sprite) constructor
super().__init__()
# Create the surface, give dimensions and set it to be transparent
self.image = pygame.Surface([width, height])
self.image.fill(WHITE)
self.image.set_colorkey(WHITE)
# Draw the ellipse onto the surface
pygame.draw.ellipse(self.image, (255,0,0), [0,0,width,height], 10)
# Initialize Pygame
pygame.init()
# Set the height and width of the screen
screen_width = 700
screen_height = 400
screen = pygame.display.set_mode((screen_width, screen_height))
# Used to manage how fast the screen updates
clock = pygame.time.Clock()
# Loop until the user clicks the close button.
done = False
# -------- Main Program Loop -----------
while not done:
# --- Events code goes here (mouse clicks, key hits etc)
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
# --- Clear the screen
screen.fill((255,255,255))
# --- Draw all the objects
ball = Ball(100,100)
# --- Update the screen with what we've drawn.
pygame.display.flip()
# --- Limit to 60 frames per second
clock.tick(60)
pygame.quit()
The circle is drawn onto your sprite's surface, but you never draw the sprite onto the screen.
Also, you should probably only create one instance of Ball, not one on every iteration of your main loop.
You usually put your sprites into groups and call draw on those to actually draw the sprites, like
...
# Loop until the user clicks the close button.
done = False
# --- Create sprites and groups
ball = Ball(100,100)
g = pygame.sprite.Group(ball)
# -------- Main Program Loop -----------
while not done:
# --- Events code goes here (mouse clicks, key hits etc)
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
# --- Clear the screen
screen.fill((255,255,255))
# --- Draw all the objects
g.draw(screen)
# --- Update the screen with what we've drawn.
pygame.display.flip()
# --- Limit to 60 frames per second
clock.tick(60)
pygame.quit()
Note that your sprite needs also a rect attribute for this to work:
...
# Create the surface, give dimensions and set it to be transparent
self.image = pygame.Surface([width, height])
self.image.fill(WHITE)
self.image.set_colorkey(WHITE)
# this rect determinies the position the ball is drawn
self.rect = self.image.get_rect()
# Draw the ellipse onto the surface
pygame.draw.ellipse(self.image, (255,0,0), [0,0,width,height], 10)
...