So I'm working on a pong copy using pygame. So far everything was working fine with pygame and everything was rendering. I wanted to add the player score to the screen, and I can't get it up. I'm not actually familiar with pygame that much so I pretty muched copied the text code from the docs and other sources. However they would not render, but when I opened a standalone, python file, it worked fine. Here is my main.py file where I render text and a link to the demo using replit: https://replit.com/#Glitchez/Pong-demo?v=1
import pygame
from paddles import *
from controls import *
from ball import *
pygame.font.init()
# SCREEN INIT
pygame.init()
win = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Pong")
# VARIABLES
ball_radius = 7
paddle_speed = 5
paddle_length = 100
FPS = 60
# DEFINE OBJECTS
paddle1 = Paddle(paddle_length, 15, 100, paddle_speed, True, WHITE)
paddle2 = Paddle(paddle_length, 970, 100, paddle_speed, False, WHITE)
ball = Ball(WIDTH // 2, HEIGHT // 2, ball_radius)
font = pygame.font.SysFont(None, 24)
# COLLISION MANAGEMENT
def handle_collision(ball, paddle1, paddle2):
if ball.y + ball.radius >= HEIGHT:
ball.y_vel *= -1
elif ball.y - ball.radius <= 0:
ball.y_vel *= -1
if ball.x_vel < 0:
if paddle1.y <= ball.y <= paddle1.y + paddle1.height:
if ball.x - ball.radius <= paddle1.x + paddle1.width:
ball.x_vel *= -1
middle_y = paddle1.y + paddle1.height / 2
difference_in_y = middle_y - ball.y
reduction_factor = (paddle1.height / 2) / ball.MAX_VEL
y_vel = difference_in_y / reduction_factor
ball.y_vel = -1 * y_vel
else:
if paddle2.y <= ball.y <= paddle2.y + paddle2.height:
if ball.x + ball.radius >= paddle2.x:
ball.x_vel *= -1
middle_y = paddle2.y + paddle2.height / 2
difference_in_y = middle_y - ball.y
reduction_factor = (paddle2.height / 2) / ball.MAX_VEL
y_vel = difference_in_y / reduction_factor
ball.y_vel = -1 * y_vel
# HANDLE ALL GRAPHICS
def graphics(screen):
screen.fill(BLACK)
paddle1.draw(screen)
paddle2.draw(screen)
ball.draw(screen)
# DRAWS DOTTED LINE
for i in range(10, HEIGHT, HEIGHT // 20):
if i % 2 == 1:
continue
pygame.draw.rect(screen, WHITE, (WIDTH // 2 - 5, i, 8, HEIGHT // 40))
# GAME LOOP
def main():
run = True
clock = pygame.time.Clock()
P1_SCORE, P2_SCORE = 0, 0
#ISSUE HERE!!!
my_font = pygame.font.SysFont('Comic Sans MS', 30)
text_surface = my_font.render(str(P1_SCORE), False, (255, 255, 255))
while run:
clock.tick(FPS)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
win.blit(text_surface, (250,250))
paddle1.move()
paddle2.move()
ball.move()
handle_collision(ball, paddle1, paddle2)
P1_SCORE, P2_SCORE = ball.check_win(P1_SCORE, P2_SCORE)
graphics(win)
pygame.display.update()
print(f"player 1: {P1_SCORE}, player 2: {P2_SCORE}")
pygame.quit()
if __name__ == '__main__':
main()
The code is rendering the score correctly, blit()ing it to the window perfectly... but then erasing everything when the screen is painted in graphics().
So, you have a function graphics(), move the score-drawing into there.
# HANDLE ALL GRAPHICS
def graphics(screen, font, p1_score, p2_score):
screen.fill(BLACK)
paddle1.draw(screen)
paddle2.draw(screen)
ball.draw(screen)
# DRAWS DOTTED LINE
for i in range(10, HEIGHT, HEIGHT // 20):
if i % 2 == 1:
continue
pygame.draw.rect(screen, WHITE, (WIDTH // 2 - 5, i, 8, HEIGHT // 40))
# DRAWS THE SCORE
# PLAYER 1 (LEFT)
text_surface = my_font.render(str(p1_score), False, (255, 255, 255))
screen.blit(text_surface, (250,250))
# PLAYER 2 (RIGHT)
text_surface = my_font.render(str(p2_score), False, (255, 255, 255))
screen.blit(text_surface, (WIDTH-WIDTH//4,250)) # 25% from the right-side
# GAME LOOP
def main():
run = True
clock = pygame.time.Clock()
P1_SCORE, P2_SCORE = 0, 0
my_font = pygame.font.SysFont('Comic Sans MS', 30)
while run:
clock.tick(FPS)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
paddle1.move()
paddle2.move()
ball.move()
handle_collision(ball, paddle1, paddle2)
P1_SCORE, P2_SCORE = ball.check_win(P1_SCORE, P2_SCORE)
graphics(win, my_font, P1_SCORE, P2_SCORE)
pygame.display.update()
print(f"player 1: {P1_SCORE}, player 2: {P2_SCORE}")
pygame.quit()
NOTE: This is not tested code, errors and omissions should be expected.
If the text-rendering becomes slow, you could also pre-render all the scores to an array of surfaces on start-up. Then just blit the one that matches the score.
Related
This question already has an answer here:
Spawning multiple instances of the same object concurrently in python
(1 answer)
Closed 4 months ago.
I'm very new to programing and I decided to try and make a very simple game to practice using pygame.
It's just a game where you're a rectangle and have to avoid geting hit by other rectangles(enemies).
However I'm having issues spawning in the enemies, something I did makes it so when I draw them to the screen they will draw on the same spot making it look like I have one very fast moving enemy rather than multiple of them.
I used a sprite for the enemy just to learn how to do sprites, it's just a red square and I'm aware that I could have used the drawRect function.
I have tried to look for answers on this and found that apparently the best to do this is with classes but I can't seem to make that work either.
Here is the code, I'm very sorry for the format of this post it's my first time posting here and I'm still not sure how to do this
Please let me know if I posted this in the wrong place, again I don't know how this works.
from textwrap import fill
import pygame
import os
import random
pygame.font.init()
text = "GAMEOVER!"
WIDTH, HEIGHT = 450, 450
WIN = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Rando game")
HEALTH_FONT = pygame.font.SysFont('comicsans', 40)
FPS = 60
WHITE = (255, 255, 255)
RED = (255, 0, 0)
BLUE = (0, 0, 255)
PURPLE = (255, 0, 255)
ENEMY_VEL = 5
PLAYER_VEL = 10
HIT = pygame.USEREVENT + 1
class enemy:
enemy_x = random.randint(0, WIDTH)
enemy_y = - 30
ENEMY_SPRITE = pygame.transform.scale(pygame.image.load(
'RED.png'), (30, 30))
#DRAW STUFF
def draw_window(enemy, player, health, enemies):
WIN.fill(WHITE)
#health
health_text = HEALTH_FONT.render(str(health), 1, PURPLE)
WIN.blit(health_text,(0, 0))
#enemies
for enemy in enemies:
WIN.blit(ENEMY_SPRITE, (enemy.enemy_x, enemy.enemy_y))
#player
pygame.draw.rect(WIN, BLUE, player)
pygame.display.update()
def handle_player_movement(player, keys_pressed):
if keys_pressed[pygame.K_d] and player.x + PLAYER_VEL <= WIDTH - 25:
player.x += PLAYER_VEL
if keys_pressed[pygame.K_a] and player.x - PLAYER_VEL >= 0:
player.x -= PLAYER_VEL
def enemy_movement(enemy, enemies):
for enemy in enemies:
enemy.enemy_y += ENEMY_VEL
def handle_collision(player, enemy, enemies):
for enemy in enemies:
if player.x + 25 > enemy.enemy_x and player.x <= enemy.enemy_x + 25 and player.y == enemy.enemy_y + 25:
enemies.remove(enemy)
pygame.event.post(pygame.event.Event(HIT))
enemies.append(enemy)
enemy.enemy_y = 0
enemy.enemy_x = random.randint(0, WIDTH - 30)
elif enemy.enemy_y > HEIGHT:
enemies.remove(enemy)
enemies.append(enemy)
enemy.enemy_y = 0
enemy.enemy_x = random.randint(0, WIDTH - 30)
def main():
clock = pygame.time.Clock() #locks fps
run = True
player = pygame.Rect(0, 425, 25, 25)
health = 3
while run:
clock.tick(FPS)
enemies = []
for n in range(6):
enemies.append(enemy)
for event in pygame.event.get():
if event.type == pygame.QUIT: #quits
run = False
pygame.quit()
if event.type == HIT:
health -= 1
if health <= 0:
enemies.remove(enemy)
draw_text = HEALTH_FONT.render(text, 1, PURPLE)
WIN.blit(draw_text, (WIDTH / 2 - draw_text.get_width() / 2, HEIGHT / 2 - draw_text.get_height() / 2))
pygame.display.update()
pygame.time.delay(2000)
break
print(enemies)
keys_pressed = pygame.key.get_pressed()
enemy_movement(enemy, enemies)
handle_player_movement(player, keys_pressed)
handle_collision(player, enemy, enemies)
draw_window(enemy, player, health, enemies)
main()
if __name__ == '__main__':
main()
My recommendation is to learn classes. They are absolutely a life saver in game programming.
Some info about classes from w3schools
All classes have a function called init(), which is always
executed when the class is being initiated.
Use the init() function to assign values to object properties, or
other operations that are necessary to do when the object is being
created
In your posted example, all six enemies were spawning in the exact same spot each time.
I've updated your code example so that multiple enemies spawn in different location.
from textwrap import fill
import pygame
import os
import random
pygame.font.init()
text = "GAMEOVER!"
WIDTH, HEIGHT = 450, 450
WIN = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Rando game")
HEALTH_FONT = pygame.font.SysFont('comicsans', 40)
FPS = 60
WHITE = (255, 255, 255)
RED = (255, 0, 0)
BLUE = (0, 0, 255)
PURPLE = (255, 0, 255)
ENEMY_VEL = 5
PLAYER_VEL = 10
HIT = pygame.USEREVENT + 1
ENEMY_SPRITE = pygame.transform.scale(pygame.image.load(
'RED.png'), (30, 30))
# Enemy class that stores a single enemy
class Enemy:
def __init__(self):
# Each time you call Enemy(), a new enemy is created with a random x value
self.enemy_x = random.randint(0, WIDTH)
self.enemy_y = -30
#DRAW STUFF
def draw_window(player, health, enemies):
WIN.fill(WHITE)
#health
health_text = HEALTH_FONT.render(str(health), 1, PURPLE)
WIN.blit(health_text,(0, 0))
#enemies
for enemy in enemies:
WIN.blit(ENEMY_SPRITE, (enemy.enemy_x, enemy.enemy_y))
#player
pygame.draw.rect(WIN, BLUE, player)
pygame.display.update()
def handle_player_movement(player, keys_pressed):
if keys_pressed[pygame.K_d] and player.x + PLAYER_VEL <= WIDTH - 25:
player.x += PLAYER_VEL
if keys_pressed[pygame.K_a] and player.x - PLAYER_VEL >= 0:
player.x -= PLAYER_VEL
def enemy_movement(enemies):
for enemy in enemies:
enemy.enemy_y += ENEMY_VEL
def handle_collision(player, enemies):
for enemy in enemies:
if player.x + 25 > enemy.enemy_x and player.x <= enemy.enemy_x + 25 and player.y == enemy.enemy_y + 25:
enemies.remove(enemy)
pygame.event.post(pygame.event.Event(HIT))
enemies.append(enemy)
enemy.enemy_y = 0
enemy.enemy_x = random.randint(0, WIDTH - 30)
elif enemy.enemy_y > HEIGHT:
enemies.remove(enemy)
enemies.append(enemy)
enemy.enemy_y = 0
enemy.enemy_x = random.randint(0, WIDTH - 30)
def main():
clock = pygame.time.Clock() #locks fps
run = True
player = pygame.Rect(0, 425, 25, 25)
health = 3
enemies = []
for _ in range(6):
enemies.append(Enemy()) # Instantiates 6 new enemies with different x values
while run:
clock.tick(FPS)
for event in pygame.event.get():
if event.type == pygame.QUIT: #quits
run = False
pygame.quit()
if event.type == HIT:
health -= 1
if health <= 0:
enemies = [] # Remove all enemies
draw_window(player, health, enemies) # Update the window
draw_text = HEALTH_FONT.render(text, 1, PURPLE)
WIN.blit(draw_text, (WIDTH / 2 - draw_text.get_width() / 2, HEIGHT / 2 - draw_text.get_height() / 2))
pygame.display.update()
pygame.time.delay(2000)
break
keys_pressed = pygame.key.get_pressed()
enemy_movement(enemies)
handle_player_movement(player, keys_pressed)
handle_collision(player, enemies)
draw_window(player, health, enemies)
if __name__ == '__main__':
main()
I want to add the tree sprite to the sprite group named tree_group
I expect the distance of the trees spawning is calculated like this: if 800 - (tree.x + TREE_HEIGHT) > Tree.get_distance(score): tree_group.draw(tree)
For some reason, the trees are not appearing and I believe that this is because the tree sprite is not in the group yet, that is why I want to use the add() function.
I want the draw_display function to iterate over all the trees currently on the screen and move them using the get_speed equation.
My code is this:
import pygame
import sys
import random
import os
import time
from pygame.event import post
# initializes pygame libraries
pygame.init()
pygame.font.init()
pygame.mixer.init()
score = 0
FPS = 60
VEL = 5
# region | main window attributes and background
WIDTH, HEIGHT = 800, 800
display = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Ski Game")
BACKGROUND = pygame.transform.scale(pygame.image.load(os.path.join("background.jpg")), (WIDTH, HEIGHT))
# endregion
# region | fonts and colors
SCORE_FONT = pygame.font.SysFont('comicsans', 40)
GAME_OVER_FONT = pygame.font.SysFont('comicsans', 100)
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
# endregion
# region | linking sprites and resizing then
SKIER_WIDTH = 65
SKIER_HEIGHT = 105
SKIER = pygame.transform.scale(pygame.image.load(
os.path.join("skier.png")), (SKIER_WIDTH, SKIER_HEIGHT))
# endregion
clock = pygame.time.Clock()
done = False
# create a custom event
CRASH_TREE = pygame.USEREVENT + 1
def draw_display(score, skier):
# blits the background
display.blit(BACKGROUND, (0, 0))
score_text = SCORE_FONT.render("Score: " + str(score), 1, BLACK)
display.blit(score_text, (WIDTH / 2 - score_text.get_width()/2, 10))
# blit skier
display.blit(SKIER, (skier.x, skier.y))
# blit trees
tree = Tree(score)
tree_group = pygame.sprite.Group()
tree_group.draw(display)
if score == 0:
tree_group.add(tree)
score += 1
elif 800 - (tree.rect.x + 150) > tree.get_distance(score):
tree_group.add(tree)
score += 1
pygame.display.update()
class Tree(pygame.sprite.Sprite):
def __init__(self, score):
super().__init__()
self.TREE_WIDTH = 80
self.TREE_HEIGHT = 150
self.image = pygame.transform.scale(pygame.image.load(os.path.join("tree.png")), (self.TREE_WIDTH, self.TREE_HEIGHT))
self.rect = self.image.get_rect()
self.rect.x = random.randrange(0, WIDTH)
self.rect.y = 700
print("init")
def get_speed(self, score, base=2, interval=10, multiplier=0.05):
return base + ((score//interval) * multiplier)
def get_distance(self, score, base=100, interval=10, multiplier=5):
return base + ((score//interval) * multiplier)
def update(self):
self.rect.y -= self.get_speed(score)
print("update")
def handle_skier_movement(keys_pressed, skier):
if keys_pressed[pygame.K_LEFT] and skier.x - VEL > 0: # LEFT
skier.x -= VEL
if keys_pressed[pygame.K_RIGHT] and skier.x + VEL + skier.width < WIDTH: # RIGHT
skier.x += VEL
if keys_pressed[pygame.K_UP] and skier.y - VEL > 0: # UP
skier.y -= VEL
if keys_pressed[pygame.K_DOWN] and skier.y + VEL + skier.width < WIDTH: # DOWN
skier.y += VEL
def game_over():
game_over_text = GAME_OVER_FONT.render("GAME OVER", 1, BLACK)
display.blit(game_over_text, (WIDTH/2 - game_over_text.get_width() /
2, HEIGHT/2 - game_over_text.get_height()/2))
pygame.display.update()
pygame.time.delay(5000)
def main():
skier = pygame.Rect(700, 300, SKIER_WIDTH, SKIER_HEIGHT)
score = 0
clock = pygame.time.Clock()
run = True
while run:
clock.tick(FPS)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
pygame.quit()
keys_pressed = pygame.key.get_pressed()
handle_skier_movement(keys_pressed, skier)
draw_display(score, skier)
tree = Tree(score)
tree.update()
if event.type == CRASH_TREE:
game_over()
score = 0
break
if __name__ == "__main__":
main()
In your draw_display function, you are first drawing the group and then adding the elements. That way, you are only drawing an empty group, and thus nothing happens. You should therefore place the tree_group.draw(display) line after the elif statement, right before pygame.display.update() line.
I am working on a pong game. When either of the scores hit 10, it is supposed to put up some text on the screen and say the right player has won or left player has won. However, in my program, it isn't working. When it has to show the text that the right or left player has won, it doesn't show it. But it works for everything else. Here is the code:
# Importing libraries
import pygame
import random
import time
# Initializing PyGame
pygame.init()
# Setting a window name
pygame.display.set_caption("Ping Pong")
# Creating a font
pygame.font.init()
font = pygame.font.SysFont(None, 30)
pong_font = pygame.font.SysFont("comicsansms", 75)
# Set the height and width of the screen
window_width = 700
window_height = 500
size = [window_width, window_height]
game_win = pygame.display.set_mode(size)
game_win2 = pygame.display.set_mode(size)
# Creating a messaging system
def message(sentence, color, x, y, font_type, display):
sentence = font_type.render(sentence, True, color)
display.blit(sentence, [x, y])
# Creating colors
white = (225, 225, 225)
black = (0, 0, 0)
gray = (100, 100, 100)
# Setting up ball
ball_size = 25
class Ball:
"""
Class to keep track of a ball's location and vector.
"""
def __init__(self):
self.x = 0
self.y = 0
self.change_x = 0
self.change_y = 0
def make_ball():
ball = Ball()
# Starting position of the ball.
ball.x = 350
ball.y = 250
# Speed and direction of rectangle
ball.change_x = 5
ball.change_y = 5
return ball
def main():
# Scores
left_score = 0
right_score = 0
pygame.init()
# Loop until the user clicks the close button.
done = False
ball_list = []
ball = make_ball()
ball_list.append(ball)
# Right paddle coordinates
y = 200
y_change = 0
x = 50
# Left paddle coordinates
y1 = 200
y1_change = 0
x1 = 650
while not done:
# --- Event Processing
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_w:
y_change = -7
elif event.key == pygame.K_s:
y_change = 7
elif event.key == pygame.K_UP:
y1_change = -7
elif event.key == pygame.K_DOWN:
y1_change = 7
elif event.type == pygame.KEYUP:
y_change = 0
y1_change = 0
y += y_change
y1 += y1_change
# Preventing from letting the paddle go off screen
if y > window_height - 100:
y -= 10
if y < 50:
y += 10
if y1 > window_height - 100:
y1 -= 10
if y1 < 50:
y1 += 10
# Logic
for ball in ball_list:
# Move the ball's center
ball.x += ball.change_x
ball.y += ball.change_y
# Bounce the ball if needed
if ball.y > 500 - ball_size or ball.y < ball_size:
ball.change_y *= -1
if ball.x > window_width - ball_size:
ball.change_x *= -1
left_score += 1
if ball.x < ball_size:
ball.change_x *= -1
right_score += 1
ball_rect = pygame.Rect(ball.x - ball_size, ball.y - ball_size, ball_size * 2, ball_size * 2)
left_paddle_rect = pygame.Rect(x, y, 25, 75)
if ball.change_x < 0 and ball_rect.colliderect(left_paddle_rect):
ball.change_x = abs(ball.change_x)
right_paddle_rect = pygame.Rect(x1, y1, 25, 75)
if ball.change_x > 0 and ball_rect.colliderect(right_paddle_rect):
ball.change_x = -abs(ball.change_x)
# Here is the where the messaging system doesn't work, I don't know why! It works fine for everything else
if right_score == 10:
message("RIGHT PLAYER HAS WON!!", white, 300, 200, font, game_win)
time.sleep(5)
pygame.quit()
quit()
elif left_score == 10:
message("LEFT PLAYER HAS WON!!", white, 300, 200, font, game_win)
time.sleep(5)
pygame.quit()
quit()
# Drawing
# Set the screen background
game_win.fill(black)
# Draw the balls
for ball in ball_list:
pygame.draw.circle(game_win, white, [ball.x, ball.y], ball_size)
# Creating Scoreboard
message("Left player score: " + str(left_score), white, 10, 10, font, game_win)
message("Right player score: " + str(right_score), white, 490, 10, font, game_win)
# Drawing a left paddle
pygame.draw.rect(game_win, white, [x, y, 25, 100])
# Drawing a right paddle
pygame.draw.rect(game_win, white, [x1, y1, 25, 100])
# Setting FPS
FPS = pygame.time.Clock()
FPS.tick(60)
# Updating so actions take place
pygame.display.flip()
while True:
game_win2.fill(black)
pygame.event.get()
mouse = pygame.mouse.get_pos()
click = pygame.mouse.get_pressed()
message("Pong", white, 280, 100, pong_font, game_win2)
if 150 + 100 > mouse[0] > 150 and 350 + 50 > mouse[1] > 350:
pygame.draw.rect(game_win, gray, [150, 350, 100, 50])
if click[0] == 1:
break
else:
pygame.draw.rect(game_win, white, [150, 350, 100, 50])
if 450 + 100 > mouse[0] > 450 and 350 + 50 > mouse[1] > 350:
pygame.draw.rect(game_win, gray, [450, 350, 100, 50])
if click[0] == 1:
pygame.quit()
quit()
else:
pygame.draw.rect(game_win, white, [450, 350, 100, 50])
message("Start", black, 175, 367, font, game_win2)
message("Quit", black, 475, 367, font, game_win2)
# Go ahead and update the screen with what we've drawn.
pygame.display.flip()
# Wrap-up
# Limit to 60 frames per second
clock = pygame.time.Clock()
clock.tick(60)
if __name__ == "__main__":
main()
I have added a little comment, it is: "# Here is the where the messaging system doesn't work, I don't know why! It works fine for everything else". Now when someone scores 10 points, Nothing happens. Its= wait for a couple of seconds. That is so you can read the "Left player has won" or "Right player has won" before the program closes. But it simply doesn't show up! I don't know why! Can someone help with this?
The display is updated only if either pygame.display.update() or pygame.display.flip()
is called. See pygame.display.flip():
This will update the contents of the entire display.
Further you've to handles the events with pygame.event.pump(), before the update of the display becomes visible in the window.
See pygame.event.pump():
For each frame of your game, you will need to make some sort of call to the event queue. This ensures your program can internally interact with the rest of the operating system.
If you want to display a text and delay the game, then you've to update the display and handle the events.
Write a function which delays the game and updates the display. I recommend to use the pygame.time module to implement the delay (e.g. pygame.time.delay())
def update_and_wait(delay):
pygame.display.flip()
pygame.event.pump()
pygame.time.delay(delay * 1000) # 1 second == 1000 milliseconds
Or even implement a function which its own event loop to keep the application responding. Measure the time by pygame.time.get_ticks():
def update_and_wait(delay):
start_time = pygame.time.get_ticks()
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
print("auit")
pygame.quit()
return False
if pygame.time.get_ticks() >= start_time + delay * 1000:
break
return True
Use the function in the application:
def main():
# [...]
while not done:
# [...]
for ball in ball_list:
# [...]
if right_score == 0:
message_wait("RIGHT PLAYER HAS WON!!", white, 300, 200, font, game_win)
update_and_wait(5)
quit()
elif left_score == 0:
message_wait("LEFT PLAYER HAS WON!!", white, 300, 200, font, game_win)
update_and_wait(5)
quit()
I making a small game with multiple falling cubes and the player(the square) has to avoid it. I manage to get the collision to work but the problem is when every time the circle and square collide it displays the text every time they collide. But I want the text to stay on when the circle and square first collide. Is there any way to do that?
import pygame
from pygame.locals import *
import os
import random
import math
import sys
import time
white = (255,255,255)
blue = (0,0,255)
gravity = 10
size =10
height = 500
width =600
varHeigth = height
ballNum = 5
eBall = []
apGame = pygame.display.set_mode((width, height))
pygame.display.set_caption("AP Project")
clock = pygame.time.Clock()
class Player(object):
def __init__(self):
red = (255, 0, 0)
move_x = 300
move_y = 400
self.rect = pygame.draw.rect(apGame,red, (move_x, move_y, 10, 10))
self.dist = 10
def handle_keys(self):
for e in pygame.event.get():
if e.type == pygame.QUIT:
pygame.quit();
exit()
key = pygame.key.get_pressed()
if key[pygame.K_LEFT]:
self.draw_rect(-1, 0)
elif key[pygame.K_RIGHT]:
self.draw_rect(1, 0)
elif key[pygame.K_ESCAPE]:
pygame.quit();
exit()
else:
self.draw_rect(0, 0)
def draw_rect(self, x, y):
red = (255, 0, 0)
black = (0, 0, 0)
'''apGame.fill(black)'''
self.rect = self.rect.move(x * self.dist, y * self.dist);
pygame.draw.rect(apGame, red , self.rect)
pygame.display.update()
def draw(self,surface):
red = (255, 0, 0)
move_x = 300
move_y = 400
pygame.draw.rect(apGame, red, (move_x, move_y, 10, 10))
#The game over text here
def show_go_screen():
pygame.font.init()
myfont = pygame.font.SysFont("Comic Sans MS", 30)
label = myfont.render("Game Over", 1, red)
apGame.blit(label, (300,100))
def instuct():
pygame.font.init()
myfont = pygame.font.SysFont("Comic Sans MS", 15)
label = myfont.render("Avoid The Circles", 1, red)
apGame.blit(label, (250,450))
'''game_over = False'''
move_x = 300
move_y = 400
red = (255, 0, 0)
black = (0, 0, 0)
player = Player()
clock = pygame.time.Clock()
'''apGame.fill(black)'''
player.draw(apGame)
pygame.display.update()
for q in range(ballNum):
x = random.randrange(0, width)
y = random.randrange(0, varHeigth)
eBall.append([x, y])
while True:
apGame.fill(black)
for i in range(len(eBall)):
ball_rect = pygame.draw.circle(apGame, blue, eBall[i], size)
#where the code is supposed to work
if player.rect.colliderect(ball_rect):
'''game_over = True'''
show_go_screen()
eBall[i][1] += 5
if eBall[i][1] > height:
y = random.randrange(-50, -10)
eBall[i][1] = y
x = random.randrange(0, width)
eBall[i][0] = x
instuct()
player.handle_keys()
pygame.display.flip()
clock.tick(30)
Whenever you want functionality to only run once, you should add a check outside of that function to make sure the code within that function only runs once. Here's an example of that using your code.
collidedOnce = False
if player.rect.colliderect(ball_rect):
if(collidedOnce == False):
collidedOnce = True #This makes the code only run once since it's setting this variable to be true within the condition
#game_over = True
show_go_screen()
eBall[i][1] += 5
if eBall[i][1] > height:
y = random.randrange(-50, -10)
eBall[i][1] = y
x = random.randrange(0, width)
eBall[i][0] = x
instuct()
player.handle_keys()
pygame.display.flip()
clock.tick(30)
Hope this helps
I tried to build a simple game in python using pygame. At first my problem was to make the movement more smooth, because about every second the movement of the rectangles stuck for a few milliseconds. Then I found an solution by adding "os.environ['SDL_VIDEODRIVER'] = 'directx'" in to my code and changing the display mode to "FULLSCREEN" and "DOUBLEBUFF". The movement is more fluid now, but whenever I Alt + Tab out of the fullscreen game, i get this error:
Traceback (most recent call last):
File "C:\Users\L-Tramp-GAMING\Documents\Python\Game\Main_Game.py", line 64, in <module>
screen.fill(BG_COLOR)
pygame.error: IDirectDrawSurface3::Blt: Surface was lost
I don't know how to bypass this problem. I am also wondering if i can somehow run the game in windowed mode with the directx line added in normal speed. At the moment the game runs in much higher speed when it is in windowed mode. I hope some of you guys can help me. Thank you, Paul
import pygame
import random
import os
#Variables
WIDTH = 1280
HEIGHT = 720
GAME_OVER = False
BG_COLOR = (0, 0, 20)
playerWidth = 50
playerHeight = 50
playerPosX = WIDTH / 2 - playerWidth / 2
playerPosY = HEIGHT - (playerHeight + 75)
playerSpeed = 10
enemieWidth = 75
enemieHeight = 75
enemiePosX = random.randint(0, WIDTH - enemieWidth)
enemiePosY = 0
enemieSpeed = 5
enemieCounter = 1
####################################################################################################
os.environ['SDL_VIDEODRIVER'] = 'directx'
pygame.init()
screen = pygame.display.set_mode((WIDTH, HEIGHT), pygame.FULLSCREEN | pygame.DOUBLEBUF)
pygame.display.set_caption("Game")
pygame.key.set_repeat(1, 10)
clock = pygame.time.Clock()
#GameLoop
while not GAME_OVER:
for e in pygame.event.get():
if e.type == pygame.QUIT:
GAME_OVER = True
if e.type == pygame.KEYDOWN:
if e.key == pygame.K_a:
playerPosX -= playerSpeed
print(hex(screen.get_flags() & 0xFFFFFFFF))
if e.key == pygame.K_d:
playerPosX += playerSpeed
#Graphics
screen.fill(BG_COLOR)
player = pygame.draw.rect(screen, (0, 255, 0), (playerPosX, playerPosY, playerWidth, playerHeight))
if enemiePosY < HEIGHT:
enemie = pygame.draw.rect(screen, (255, 0, 0), (enemiePosX, enemiePosY, enemieWidth, enemieHeight))
enemiePosY += enemieSpeed
else:
enemieCounter += 1
enemiePosY = 0
enemiePosX = random.randint(0, WIDTH - enemieWidth)
if (enemieCounter + 1) % 2 == 0:
pass
#End Graphics
pygame.display.flip()
Your movement lag was caused by pygame.key.set_repeat. To allow the player to hold down a and d to move you can update the players position in your game loop instead of using set_repeat by keeping track of a speed variable. If you wanted to use os.environ for another reason besides fixing the lag then this won't work but otherwise this should be fine.
import pygame
import random
import os
#Variables
WIDTH = 1280
HEIGHT = 720
GAME_OVER = False
BG_COLOR = (0, 0, 20)
playerWidth = 50
playerHeight = 50
playerPosX = WIDTH / 2 - playerWidth / 2
playerPosY = HEIGHT - (playerHeight + 75)
playerSpeed = 10
enemieWidth = 75
enemieHeight = 75
enemiePosX = random.randint(0, WIDTH - enemieWidth)
enemiePosY = 0
enemieSpeed = 5
enemieCounter = 1
####################################################################################################
#os.environ['SDL_VIDEODRIVER'] = 'directx'
pygame.init()
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Game")
#pygame.key.set_repeat(1, 10) <----- This line is the problem
clock = pygame.time.Clock()
#GameLoop
speed = 0
while not GAME_OVER:
for e in pygame.event.get():
if e.type == pygame.QUIT:
GAME_OVER = True
if e.type == pygame.KEYDOWN:
if e.key == pygame.K_a:
speed = -playerSpeed
if e.key == pygame.K_d:
speed = +playerSpeed
playerPosX += speed
#Graphics
screen.fill(BG_COLOR)
player = pygame.draw.rect(screen, (0, 255, 0), (playerPosX, playerPosY, playerWidth, playerHeight))
if enemiePosY < HEIGHT:
enemie = pygame.draw.rect(screen, (255, 0, 0), (enemiePosX, enemiePosY, enemieWidth, enemieHeight))
enemiePosY += enemieSpeed
else:
enemieCounter += 1
enemiePosY = 0
enemiePosX = random.randint(0, WIDTH - enemieWidth)
if (enemieCounter + 1) % 2 == 0:
pass
#End Graphics
pygame.display.flip()
Can the code handle the error, and then try re-creating the screen object ?
This is the same sort of process as when switching from full-screen to windowed.
EDIT: Added some code from the PyGame Wiki: https://www.pygame.org/wiki/toggle_fullscreen to hopefully work around further issues from OP's comment.
try:
screen.fill(BG_COLOR)
except pygame.error as e:
# Get the size of the screen
screen_info= pygame.display.Info()
cursor = pygame.mouse.get_cursor() # Duoas 16-04-2007
new_width = screen_info.current_w
new_height = screen_info.current_h
# re-initialise the display, creating a re-sizable window
pygame.display.quit()
pygame.display.init()
screen = pygame.display.set_mode( ( new_width, new_height ), pygame.HWSURFACE|pygame.DOUBLEBUF|pygame.RESIZABLE )
pygame.key.set_mods( 0 ) # HACK: work-a-round for a SDL bug??
pygame.mouse.set_cursor( *cursor ) # Duoas 16-04-2007
# did it work?
screen.fill(BG_COLOR)