import pygame
from pygame.locals import *
pygame.init()
screen_width = 600
screen_height = 500
fpsClock = pygame.time.Clock()
screen = pygame.display.set_mode((screen_width, screen_height))
pygame.display.set_caption('Pong')
#define font
font = pygame.font.SysFont('None', 30)
#define game variables
margin = 50
cpu_score = 0
player_score = 0
fps = 90
live_ball = False
winner = 0
speed_increase = 0
#define colours
bg = (12, 0, 91)
white = (241, 185, 0)
ball_color = (168, 43, 17)
bar_color = (10, 106, 86)
def draw_board():
screen.fill(bg)
pygame.draw.line(screen, white, (0, margin), (screen_width, margin), 2)
def draw_text(text, font, text_col, x, y):
img = font.render(text, True, text_col)
screen.blit(img, (x, y))
class paddle():
def __init__(self, x, y):
self.x = x
self.y = y
self.rect = Rect(x, y, 20, 100)
self.speed = 5
self.ai_speed = 5
def move(self):
key = pygame.key.get_pressed()
if key[pygame.K_UP] and self.rect.top > margin:
self.rect.move_ip(0, -1 * self.speed)
if key[pygame.K_DOWN] and self.rect.bottom < screen_height:
self.rect.move_ip(0, self.speed)
def draw(self):
pygame.draw.rect(screen, bar_color, self.rect)
def ai(self):
#ai to move the paddle automatically
#move down
if self.rect.centery < pong.rect.top and self.rect.bottom < screen_height:
self.rect.move_ip(0, self.ai_speed)
#move up
if self.rect.centery > pong.rect.bottom and self.rect.top > margin:
self.rect.move_ip(0, -1 * self.ai_speed)
class ball():
def __init__(self, x, y):
self.reset(x, y)
def move(self):
#check collision with top margin
if self.rect.top < margin:
self.speed_y *= -1
#check collision with bottom of the screen
if self.rect.bottom > screen_height:
self.speed_y *= -1
if self.rect.colliderect(player_paddle) or self.rect.colliderect(cpu_paddle):
self.speed_x *= -1
#check for out of bounds
if self.rect.left < 0:
self.winner = 1
if self.rect.left > screen_width:
self.winner = -1
#update ball position
self.rect.x += self.speed_x
self.rect.y += self.speed_y
return self.winner
def draw(self):
pygame.draw.circle(screen, ball_color, (self.rect.x + self.ball_rad, self.rect.y + self.ball_rad), self.ball_rad)
def reset(self, x, y):
self.x = x
self.y = y
self.ball_rad = 8
self.rect = Rect(x, y, self.ball_rad * 2, self.ball_rad * 2)
self.speed_x = -4
self.speed_y = 4
self.winner = 0# 1 is the player and -1 is the CPU
#create paddles
player_paddle = paddle(screen_width - 40, screen_height // 2)
cpu_paddle = paddle(20, screen_height // 2)
#create pong ball
pong = ball(screen_width - 60, screen_height // 2 + 50)
#create game loop
run = True
while run:
fpsClock.tick(fps)
draw_board()
draw_text('CPU: ' + str(cpu_score), font, white, 20, 15)
draw_text('Sihu: ' + str(player_score), font, white, screen_width - 100, 15)
draw_text('BALL SPEED: ' + str(abs(pong.speed_x)), font, white, screen_width // 2 - 100 , 15)
#draw paddles
player_paddle.draw()
cpu_paddle.draw()
if live_ball == True:
speed_increase += 1
winner = pong.move()
if winner == 0:
#draw ball
pong.draw()
#move paddles
player_paddle.move()
cpu_paddle.ai()
else:
live_ball = False
if winner == 1:
player_score += 1
elif winner == -1:
cpu_score += 1
#print player instructions
if live_ball == False:
if winner == 0:
draw_text('CLICK ANYWHERE TO START', font, white, 160, screen_height // 2 -0)
if winner == 1:
draw_text('YOU SCORED!', font, white, 220, screen_height // 2 -100)
draw_text('CLICK ANYWHERE TO START', font, white, 160, screen_height // 2 -0)
if winner == -1:
draw_text('CPU SCORED!', font, white, 220, screen_height // 2 -100)
draw_text('CLICK ANYWHERE TO START', font, white, 160, screen_height // 2 -0)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
if event.type == pygame.MOUSEBUTTONDOWN and live_ball == False:
live_ball = True
pong.reset(screen_width - 60, screen_height // 2 + 50)
if speed_increase > 500:
speed_increase = 0
if pong.speed_x < 0:
pong.speed_x -= 1
if pong.speed_x > 0:
pong.speed_x += 1
if pong.speed_y < 0:
pong.speed_y -= 1
if pong.speed_y > 0:
pong.speed_y += 1
pygame.display.update()
pygame.quit()
I get the code on YOUTUBE
and edit the code a little bits
but I did not add the restart code
How can I make the restart function in pygame?
I just want to over the game when player get a 5 score in the game.
and want to make the game restart.
When the game is overed, the player can restart the game with the button.
To restart you will need to reset any variables that change during the game. Write a function that sets all objects and variables to its initial state:
def reset():
global player_paddle, cpu_paddle, pong
global cpu_score, player_score
global live_ball, winner, speed_increase
player_paddle = paddle(screen_width - 40, screen_height // 2)
cpu_paddle = paddle(20, screen_height // 2)
pong = ball(screen_width - 60, screen_height // 2 + 50)
cpu_score = 0
player_score = 0
live_ball = False
winner = 0
speed_increase = 0
Call the function when you want to restart the game.
Have the loop it's own method, call it from a main() run, when the game is over and ends, have main() ask the user if they want to play again, and if so recall the main loop after setting everything as its default
or
Just have the part that asks again clear and reinitialize all variables as there defaults and let the loop if the user wants to play again
Related
I am making a BrickBreaker/Breakout game using pygame. I want my game to create rows of bricks until the a brick hits the paddle but I can't figure out how to do so. Currently it only creates 1 row of bricks. I also want to make the bricks dissappear when the ball hits them. Currently when the bricks are hit they just move off the screen, but I want them to get permanently deleted.
Thanks!
My current code:
# Brick Breaker Game
import pygame
import random
# Initialize the pygame
pygame.init()
# create the screen
screen = pygame.display.set_mode((800, 600))
# background
background = pygame.image.load("realBackground.png")
# Title and Icon
pygame.display.set_caption("Brick Breaker")
icon = pygame.image.load("Brick Breaker Icon.png")
pygame.display.set_icon(icon)
# Paddle
paddleImage = pygame.image.load("scaledPaddle.png")
paddleX = 335
paddleY = 550
paddleX_change = 0
# BrickCoordinates
brickX = []
brickY = []
brickX_change = []
brickY_change = []
numOfBricks = 6
brickXValue = 15
for i in range(numOfBricks):
brickX.append(brickXValue)
brickY.append(0)
brickX_change.append(0.3)
brickY_change.append(0)
# Add 120 if thick lines in middle bricks
# Add 110 if uniform thickness
brickXValue += 130
#Bricks
yellowBrickImage = pygame.image.load("yellowBrick.png")
greenBrickImage = pygame.image.load("greenBrick.png")
blueBrickImage = pygame.image.load("blueBrick.png")
pinkBrickImage = pygame.image.load("pinkBrick.png")
# ball
ballImage = pygame.image.load("Ball.png")
ballX = 380
ballY = 280
ballX_change = 1.5
ballY_change = 1.5
#Score
scoreValue = 0
font = pygame.font.Font("Neufreit-ExtraBold.otf",24)
textX = 10
textY = 10
def showScore(x,y):
score = font.render("Score : " + str(scoreValue), True, (255,255,255))
screen.blit(score,(x,y))
def paddle(x, y):
screen.blit(paddleImage, (x, y))
def yellowBrick(x, y, i):
screen.blit(yellowBrickImage, (x, y))
def greenBrick(x, y, i):
screen.blit(greenBrickImage, (x, y))
def blueBrick(x, y, i):
screen.blit(blueBrickImage, (x, y))
def pinkBrick(x, y, i):
screen.blit(pinkBrickImage, (x, y))
def ball(x, y):
screen.blit(ballImage, (x, y))
#To pick random brick colours
colourOfBrick = []
for i in range(numOfBricks):
colourOfBrick.append(random.randint(1,4))
# Game Loop (makes sure game is always running)
running = True
while running:
# To change background colour
screen.fill((128, 128, 128))
# background image
screen.blit(background, (0, 0))
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
# If keystroke is pressed check whether left or right
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
paddleX_change = -5
if event.key == pygame.K_RIGHT:
paddleX_change = 5
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT or event.key == pygame.K_RIGHT:
paddleX_change = 0
# Checking boudries of paddle
paddleX += paddleX_change
if paddleX <= 0:
paddleX = 0
elif paddleX >= 669:
paddleX = 669
#Draw Rectangles around bricks
brickRect = []
for i in range(numOfBricks):
brickRect.append(pygame.draw.rect(screen, (0, 0, 0), (brickX[i], brickY[i], 120, 42),1))
# Brick Movement
for i in range(numOfBricks):
brickY[i] += brickY_change[i]
if brickY[i] <= 0:
brickY_change[i] = 0.3
elif brickY[i] >= 500:
brickY_change[i] = -0.3
# Makes brick show up on screen
if colourOfBrick[i] == 1:
yellowBrick(brickX[i], brickY[i], i)
elif colourOfBrick[i] == 2:
greenBrick(brickX[i], brickY[i], i)
elif colourOfBrick[i] == 3:
blueBrick(brickX[i], brickY[i], i)
elif colourOfBrick[i] == 4:
pinkBrick(brickX[i], brickY[i], i)
# Ball Movement and boundary checking
ballX += ballX_change
if ballX <= 0:
ballX_change *= -1
elif ballX >= 760:
ballX_change *= -1
ballY += ballY_change
if ballY <= 0:
ballY_change *= -1
elif ballY >= 560:
ballX = 380
ballY = 280
# Paddle and Ball Collision
if ballY > 530 and ballY < 535 and (ballX+20) < paddleX + 131 and (ballX+20) > paddleX:
ballY_change *= -1
paddle(paddleX, paddleY)
ballCircle = pygame.draw.circle(screen, (255,0,0), (int(ballX+20),int(ballY+20)) ,20)
ball(ballX, ballY)
#Ball and Brick Collision
for i in range (numOfBricks):
if ballCircle.colliderect(brickRect[i]):
if abs(ballCircle.top - brickRect[i].bottom < 10) and ballY_change < 0:
brickX[i] = -400
ballY_change *= -1
scoreValue += 1
showScore(textX,textY)
pygame.display.update()
In your code all bricks have brickY.append(0) so all bricks are in one row. You have to create bricks with different Y values to create other rows.
You may need nested for-loops for this - like this
row_number = 3
brickYValue = 0
for row in range(row_number):
brickXValue = 15
for column in range(numOfBricks):
brickX.append(brickXValue)
brickY.append(brickYValue)
brickX_change.append(0.3)
brickY_change.append(0)
brickXValue += 130
# after `for column`
brickYValue += 15 # row height
But it will create more bricks then numOfBricks - you will have numOfBricks*row_number bricks so you would have to change other for-loops and use range(numOfBricks*row_number) instead of range(numOfBricks)
Or you should learn how to use for-loop without range()
brickRect = []
for x, y in zip(brickX, brickY):
brickRect.append(pygame.draw.rect(screen, (0, 0, 0), x, y, 120, 42),1))
BTW: you should also learn how to use pygame.Rect() to keep size and position of brick, paddle and ball. Rect() has methods to check collisions and you would no need long if ... and ... and ...
EDIT: I added rows in this code but I made many other changes so it may not be good example.
I draw surfaces instead of loading images so everyone can run it without images.
import pygame
import random
# --- classes ---
class Brick():
def __init__(self, x, y, image):
self.image = image
self.rect = self.image.get_rect(x=x, y=y)
self.x = x
self.y = y
self.x_change = 0
self.y_change = 1
def draw(self, screen):
self.rect.x = int(self.x)
self.rect.y = int(self.y)
screen.blit(self.image, self.rect)
pygame.draw.rect(screen, (0, 0, 0), self.rect, 1)
def update(self):
self.y += self.y_change
self.rect.y = int(self.y)
if self.rect.y <= 0:
self.y_change = 1
elif self.rect.y >= 500:
self.y_change = -1
class Ball():
def __init__(self):
#self.image = pygame.image.load("Ball.png")
self.image = pygame.Surface((16, 16)).convert_alpha()
self.image.fill((0,0,0,0)) # transparent background
pygame.draw.circle(self.image, (255,255,255), (8, 8), 8)
self.rect = self.image.get_rect(centerx=380, centery=280)
self.x = 380
self.y = 280
self.x_change = 3
self.y_change = 3
def reset(self):
self.x = 380
self.y = 280
def draw(self, screen):
self.rect.centerx = int(self.x)
self.rect.centery = int(self.y)
screen.blit(self.image, self.rect)
def update(self):
# Ball Movement and boundary checking
self.x += self.x_change
self.rect.centerx = int(self.x)
if self.rect.left <= 0:
self.x_change *= -1
elif self.rect.right >= 800:
self.x_change *= -1
self.y += self.y_change
self.rect.centery = int(self.y)
if self.rect.top <= 0:
self.y_change *= -1
elif self.rect.bottom >= 600:
self.reset()
class Paddle():
def __init__(self):
#self.image = pygame.image.load("scaledPaddle.png")
self.image = pygame.Surface((100, 30))
self.image.fill((255,0,0))
self.rect = self.image.get_rect(x=335, y=550)
self.x_change = 0
self.y_change = 0
def reset(self):
self.rect.x = 335
self.rect.y = 550
def draw(self, screen):
screen.blit(self.image, self.rect)
def update(self):
# Checking boudries of paddle
self.rect.x += self.x_change
if self.rect.left <= 0:
self.rect.left = 0
elif self.rect.right >= 800:
self.rect.right = 800
class Score():
def __init__(self):
#self.font = pygame.font.Font("Neufreit-ExtraBold.otf", 24)
self.font = pygame.font.SysFont(None, 24)
self.value = 0
self.x = 10
self.y = 10
def reset(self):
self.value = 0
def draw(self, screen):
self.image = self.font.render("Score : " + str(self.value), True, (255,255,255))
self.rect = self.image.get_rect(x=self.x, y=self.y)
screen.blit(self.image, self.rect)
# --- functions ---
# empty
# --- main ---
pygame.init()
screen = pygame.display.set_mode((800, 600))
pygame.display.set_caption("Brick Breaker")
#icon = pygame.image.load("Brick Breaker Icon.png")
#pygame.display.set_icon(icon)
# Background Image
#background_image = pygame.image.load("realBackground.png")
background_image = pygame.Surface((800,600))
for y in range(5, 600, 25):
for x in range(5, 800, 25):
color = random.choice([(255,128,128), (128,255,128), (128,128,255)])
background_image.fill(color, [x,y,15,15])
# Brick Images
#brick_images = [
# pygame.image.load("yellowBrick.png"),
# pygame.image.load("greenBrick.png"),
# pygame.image.load("blueBrick.png"),
# pygame.image.load("pinkBrick.png"),
#]
brick_images = [
pygame.Surface((100, 30)),
pygame.Surface((100, 30)),
pygame.Surface((100, 30)),
pygame.Surface((100, 30)),
pygame.Surface((100, 30)),
pygame.Surface((100, 30)),
]
brick_images[0].fill((255,0,0))
brick_images[1].fill((0,255,0))
brick_images[2].fill((0,0,255))
brick_images[3].fill((255,255,0))
brick_images[4].fill((255,0,255))
brick_images[5].fill((0,255,255))
# Objects
paddle = Paddle()
ball = Ball()
score = Score()
# bricks
rows_number = 5
cols_number = 7
all_bricks = []
y = 0
for row in range(rows_number):
x = 50
for col in range(cols_number):
color_image = random.choice(brick_images)
brick = Brick(x, y, color_image)
all_bricks.append(brick)
x += 100
y += 30
# Game Loop
clock = pygame.time.Clock()
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
# If keystroke is pressed check whether left or right
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
paddle.x_change = -5
if event.key == pygame.K_RIGHT:
paddle.x_change = 5
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT or event.key == pygame.K_RIGHT:
paddle.x_change = 0
# --- updates ---
paddle.update()
ball.update()
# Bricks Update
for brick in all_bricks:
brick.update()
# Ball and Paddle Collision
if ball.rect.colliderect(paddle):
ball.y_change *= -1
# Ball and Bricks Collision
for brick in all_bricks:
if ball.rect.colliderect(brick):
brick.x = -400
ball.y_change *= -1
score.value += 1
# --- draws ---
# To change background colour
# screen.fill((128, 128, 128)) # you don't need it if background fill all screen
# background image
screen.blit(background_image, (0, 0))
for brick in all_bricks:
brick.draw(screen)
paddle.draw(screen)
ball.draw(screen)
score.draw(screen)
pygame.display.flip()
clock.tick(60) # 60 FPS (Frames Per Second) on all computers
# --- end ---
pygame.quit()
I am trying to make a platformer game and I want the circle to jump, but whenever I try to make a jump, I get the following error, I found various methods of doing the jump, but none of them worked.
I think that the error is whenever I jump, a float number is happening and the draw method can't contain floats, only integers
here is the code for the game:
import pygame
import os
import time
import random
pygame.font.init()
Width, Height = 1280, 720
win = pygame.display.set_mode((Width, Height))
pygame.display.set_caption("Parkour Ball")
BG = pygame.image.load(os.path.join("assets", "Background.jpg"))
class Ball:
def __init__(self, x, y):
self.x = x
self.y = y
def draw(self, window):
pygame.draw.circle(window, (255,0,0), (self.x, self.y), 25)
def main():
run = True
FPS = 60
clock = pygame.time.Clock()
level = 0
lives = 10
main_font = pygame.font.SysFont("comicsans", 50)
lost_font = pygame.font.SysFont("comicsans", 60)
spikes = []
holes = []
hammers = []
platforms = []
enemies = []
player_vel = 5
jump = False
jumpCount = 10
player = Ball(300, 450)
lost = False
lost_popup = 0
def redraw():
win.blit(BG, (0,0))
player.draw(win)
pygame.display.update()
while run:
clock.tick(FPS)
redraw()
if lives == 0:
lost = True
lost_popup += 1
if lost:
if lost_popup > FPS * 3:
run = False
else:
continue
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT] and player.x - player_vel - 25 > 0:
player.x -= player_vel
if keys[pygame.K_RIGHT] and player.x + player_vel + 25 < Width:
player.x += player_vel
if keys[pygame.K_w]and player.y - player_vel > 0: #up
player.y -= player_vel
if keys[pygame.K_s] and player.y + player_vel < Height: #down
player.y += player_vel
if not(jump):
if keys[pygame.K_SPACE]:
jump = True
else:
if jumpCount >= -10:
neg = 1
if jumpCount < 0:
neg = -1
player.y -= (jumpCount ** 2) / 2 * neg
jumpCount -= 1
main()
The coordinates to pygame.draw.circle() have to be integral values. round() the floating point coordinates to integral coordinates:
pygame.draw.circle(window, (255,0,0), (self.x, self.y), 25)
pygame.draw.circle(window, (255,0,0), (round(self.x), round(self.y)), 25)
This question already has answers here:
Could not open resource file, pygame error: "FileNotFoundError: No such file or directory."
(1 answer)
Is there any other way to load a resource like an image, sound, or font into Pygame? [closed]
(1 answer)
Closed 2 years ago.
I'm making a game and I tried to add some images instead of surfaces but I don't really know how it works I was wondering if some could explain to how its work cause I'm getting pygame.error: Unsupported image format and I don't know what that means or what I've done wrong.
Below is an image of the code in question as well as my directory files (on the left)
also im using a program called Pycharm idk if that might affect at all or not
# import images for sprites
img_dir = path.join(path.dirname(__file__), 'Img')
# load images
player_img = py.image.load(path.join(img_dir, "Playerimg.png")).convert()
class Player(py.sprite.Sprite):
def __init__(self):
py.sprite.Sprite.__init__(self)
self.image = player_img
self.rect = self.image.get_rect()
self.rect.centerx = WIDTH / 2
self.rect.bottom = HEIGHT / 2
self.Yspeed = 0
self.rotatableimage = self.image
The rest of the code is below if you need it also I know it might be hard to troubleshoot image-based stuff soo here the code but without the images (two parts btw)
import random
import math
import pygame as py
from PlayerSprite import *
WIDTH = 800
HEIGHT = 600
FPS = 60
# define colors
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)
YELLOW = (255, 255, 0)
# initialize pygame and create window
py.init()
py.mixer.init()
screen = py.display.set_mode((WIDTH, HEIGHT))
py.display.set_caption("Dimensional Drifter")
clock = py.time.Clock()
all_sprites = py.sprite.Group()
NPCs = py.sprite.Group()
bullets = py.sprite.Group()
player = Player()
all_sprites.add(player)
for i in range(14):
n = NPC(player)
all_sprites.add(n)
NPCs.add(n)
# Game loop
running = True
while running:
# keep loop running at the right speed
clock.tick(FPS)
for event in py.event.get():
# check for closing window
if event.type == py.QUIT:
running = False
elif event.type == py.MOUSEBUTTONDOWN:
if event.button == 1:
New_bullet = player.Shoot()
all_sprites.add(New_bullet)
bullets.add(New_bullet)
# Update
all_sprites.update()
# # check if there a collision between the bullet and NPC
hits = py.sprite.groupcollide(NPCs, bullets, True, True)
# check if there a collision between the player and NPC
hits = py.sprite.spritecollide(player, NPCs, True)
if hits:
running = False
# updates the position of of mouse and rotates it towards the mouse position
mouse_x, mouse_y = py.mouse.get_pos()
player.rotate(mouse_x, mouse_y)
# render
screen.fill(BLACK)
all_sprites.draw(screen)
# flip the display
py.display.flip()
py.quit()
import pygame as py
import math
import random
WIDTH = 800
HEIGHT = 600
FPS = 60
# define colors
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)
YELLOW = (255, 255, 0)
class Player(py.sprite.Sprite):
def __init__(self):
py.sprite.Sprite.__init__(self)
self.image = py.Surface((40, 40), py.SRCALPHA)
self.image.fill(GREEN)
self.rect = self.image.get_rect()
self.rect.centerx = WIDTH / 2
self.rect.bottom = HEIGHT / 2
self.Yspeed = 0
self.rotatableimage = self.image
def update(self):
self.Xspeed = 0
self.Yspeed = 0
# line below allow for key press to equate to move of sprite
keypreesed = py.key.get_pressed()
if keypreesed[py.K_a]:
self.Xspeed = - 11
if keypreesed[py.K_d]:
self.Xspeed = 11
if keypreesed[py.K_w]:
self.Yspeed = - 11
if keypreesed[py.K_s]:
self.Yspeed = 11
self.rect.x += self.Xspeed
self.rect.y += self.Yspeed
# line below allow the sprite to wrap around the screen
if self.rect.left > WIDTH:
self.rect.right = 0
if self.rect.right < 0:
self.rect.left = WIDTH
if self.rect.top > HEIGHT:
self.rect.top = 0
if self.rect.bottom < 0:
self.rect.bottom = HEIGHT
def rotate(self, mouse_x, mouse_y):
rel_x = mouse_x - self.rect.x
rel_y = mouse_y - self.rect.y
angle = (180 / math.pi) * -math.atan2(rel_y, rel_x)
self.image = py.transform.rotate(self.rotatableimage, int(angle))
self.rect = self.image.get_rect(center=(self.rect.centerx, self.rect.centery))
return
def Shoot(self):
pos = self.rect.centerx, self.rect.centery
mpos = py.mouse.get_pos()
direction = py.math.Vector2(mpos[0] - pos[0], mpos[1] - pos[1])
direction.scale_to_length(10)
return Bullet(pos[0], pos[1], round(direction[0]), round(direction[1]))
class NPC(py.sprite.Sprite):
def __init__(self, player):
py.sprite.Sprite.__init__(self)
self.player = player
self.image = py.Surface((30, 30)).convert_alpha()
self.image.fill(RED)
self.originalimage = self.image
self.rect = self.image.get_rect()
self.spawn()
# allows of spawning from all four side of the screen and set the x, y speed and spawn position
def spawn(self):
self.direction = random.randrange(4)
if self.direction == 0:
self.rect.x = random.randrange(WIDTH - self.rect.width)
self.rect.y = random.randrange(-100, -40)
self.Xspeed = random.randrange(-2, 2)
self.Yspeed = random.randrange(4, 8)
elif self.direction == 1:
self.rect.x = random.randrange(WIDTH - self.rect.width)
self.rect.y = random.randrange(HEIGHT, HEIGHT + 60)
self.Xspeed = random.randrange(-2, 2)
self.Yspeed = -random.randrange(4, 8)
elif self.direction == 2:
self.rect.x = random.randrange(-100, -40)
self.rect.y = random.randrange(HEIGHT - self.rect.height)
self.Xspeed = random.randrange(4, 8)
self.Yspeed = random.randrange(-2, 2)
elif self.direction == 3:
self.rect.x = random.randrange(WIDTH, WIDTH + 60)
self.rect.y = random.randrange(HEIGHT - self.rect.height)
self.Xspeed = -random.randrange(4, 8)
self.Yspeed = random.randrange(-2, 2)
def update(self):
self.rect.x += self.Xspeed
self.rect.y += self.Yspeed
# makes it so that NPC point to wards the player as it passes from side to side
dir_x, dir_y = self.player.rect.x - self.rect.x, self.player.rect.y - self.rect.y
self.rot = (180 / math.pi) * math.atan2(-dir_x, -dir_y)
self.image = py.transform.rotate(self.originalimage, self.rot)
# Respawns the NPC when they hit an side
if self.direction == 0:
if self.rect.top > HEIGHT + 10:
self.spawn()
elif self.direction == 1:
if self.rect.bottom < -10:
self.spawn()
elif self.direction == 2:
if self.rect.left > WIDTH + 10:
self.spawn()
elif self.direction == 3:
if self.rect.right < -10:
self.spawn()
class Bullet(py.sprite.Sprite):
def __init__(self, x, y, Xspeed, Yspeed):
py.sprite.Sprite.__init__(self)
self.image = py.Surface((5, 5))
self.image.fill(YELLOW)
self.rect = self.image.get_rect()
self.rect.bottom = y
self.rect.centerx = x
self.Xspeed = Xspeed
self.Yspeed = Yspeed
def update(self):
self.rect.x += self.Xspeed
self.rect.y += self.Yspeed
# kill if moved of screen
if self.rect.bottom > HEIGHT or self.rect.top < 0:
self.kill()
if self.rect.right > WIDTH or self.rect.left < 0:
self.kill()
it might be hard to help me on this one so because of images and what not but if could just explain it to me then i could implement on my own that could work too :)
edit 3:
Edit 2:
Edit: image of error
If you play the game and win, clicking on the screen will cause the game to play again. On the second play, the game segmentation faults after a second or two.
This code is for an intro to coding class and many others have coded this game successfully. I don't understand what is the problem here.
Help!
import sys
import os
import pygame
import random
import math
#Force static position of screen
os.environ ['SDL_VIDEO_CENTERED'] = '1'
#constants
BLACK = (0,0,0)
WHITE = (255, 255, 255)
SHIP_WIDTH = 13
SHIP_HEIGHT = 13
SIZE = WIDTH, HEIGHT = 920, 570
TOP_BUFFER = 50
PILL_HEIGHT = 30
PILL_WIDTH = 10
YELLOW = (157, 185, 45)
RED = (185, 45, 45)
BLUE = (45, 115, 185)
GREEN = (5, 94, 16)
#Runs imported module
pygame.init()
class Text:
def __init__(self, size, text, color, xpos, ypos):
self.font = pygame.font.SysFont("Britannic Bold", size)
self.image = self.font.render(text, 1, color)
self.rect = self.image.get_rect()
self.rect = self.rect.move(xpos, ypos)
class Ship(pygame.sprite.Sprite):
def __init__ (self, x, y, side):
pygame.sprite.Sprite.__init__(self)
self.density = SHIP_HEIGHT * SHIP_WIDTH
self.speed = 10
self.image = pygame.Surface((math.sqrt(self.density), math.sqrt(self.density))).convert()
self.rect = self.image.get_rect()
self.rect = self.rect.move(x, y)
self.type = side
self.score = Text(30, str(self.density - 169), BLACK, WIDTH / 4 , HEIGHT/ 17)
self.score_2 = Text(30, str(self.density - 169), BLACK, WIDTH * .75, HEIGHT / 17)
def update(self, pill_group):
key = pygame.key.get_pressed()
if self.type == "left":
if key[pygame.K_w]:
self.rect.y -= self.speed
if key[pygame.K_s]:
self.rect.y += self.speed
if key[pygame.K_a]:
self.rect.x -= self.speed
if key[pygame.K_d]:
self.rect.x += self.speed
if self.type == "left":
#Boundary Conditions
if self.rect.right > WIDTH/2:
self.rect.right = WIDTH/2
if self.rect.left < 0:
self.rect.left = 0
if self.rect.top < 50:
self.rect.top = 50
if self.rect.bottom > 570:
self.rect.bottom = 570
elif self.type == "right":
if key[pygame.K_UP]:
self.rect.y -= self.speed
if key[pygame.K_DOWN]:
self.rect.y += self.speed
if key[pygame.K_LEFT]:
self.rect.x -= self.speed
if key[pygame.K_RIGHT]:
self.rect.x += self.speed
# Ship 2 boundary conditions
if self.rect.right > WIDTH:
self.rect.right = WIDTH
if self.rect.top < TOP_BUFFER:
self.rect.top = TOP_BUFFER
if self.rect.left < WIDTH/2:
self.rect.left = WIDTH/2
if self.rect.bottom > HEIGHT:
self.rect.bottom = HEIGHT
collisions = pygame.sprite.spritecollide(self, pill_group, True)
for p in collisions:
self.density += p.density * 50
print(self.density)
self.score.image = self.score.font.render(str(self.density - 169), 1, BLACK)
self.score_2.image = self.score.font.render(str(self.density), 1, BLACK)
##if self.density > 500:
##self.play == False
self.rect.width = self.rect.height = math.sqrt(self.density)
self.image = pygame.transform.scale(self.image, (self.rect.width, self.rect.height))
class Pill(pygame.sprite.Sprite):
def __init__(self, xpos, density):
pygame.sprite.Sprite.__init__(self)
self.density = density
self.speed = 3
self.image = pygame.Surface((PILL_WIDTH, PILL_HEIGHT)).convert()
self.image.fill(self.set_color())
self.rect = pygame.Rect(xpos, -PILL_HEIGHT, 10, 30)
self.rect = self.image.get_rect()
self.rect = self.rect.move(xpos, HEIGHT/15)
def set_color(self):
if self.density == 1:
return YELLOW
elif self.density == 2:
return RED
elif self.density == 3:
return BLUE
elif self.density == 4:
return GREEN
def update(self):
self.rect.y += self.speed
if self.rect.y > HEIGHT:
self.kill()
def main():
#Initialize Local Vars
size = width, height = 920, 570
fps = 30
LeftWins = Text(30, "Left Ship Wins!", BLACK, WIDTH / 2.5, HEIGHT / 2)
RightWins = Text(30, "Right Ship Wins!", BLACK, WIDTH / 2.5, HEIGHT / 2)
Winner = Text (30, "Click here to play again", BLACK, WIDTH / 2.6, HEIGHT * .75)
pygame.display.set_caption('Density')
screen = pygame.display.set_mode(SIZE, pygame.SRCALPHA)
clock = pygame.time.Clock()
play = True
loop_counter = 0
vertical = pygame.Surface((1, HEIGHT - TOP_BUFFER)).convert()
horizontal = pygame.Surface((WIDTH, 1)).convert()
#Create Game Objects
ship_left = Ship(WIDTH/4 - SHIP_WIDTH/2, HEIGHT - (4 * SHIP_HEIGHT), "left")
ship_right = Ship((WIDTH * 3) / 4 - SHIP_WIDTH / 2, HEIGHT - (4 * SHIP_HEIGHT), "right")
#Create Groups
ship_group = pygame.sprite.Group()
ship_group.add(ship_left, ship_right)
pill_group = pygame.sprite.Group()
#play = True
outro = True
while True:
#Gameplay
while play:
for event in pygame.event.get():
if event.type == pygame.QUIT: sys.exit()
if loop_counter % 10 == 0:
pill = Pill(random.randrange(0, (WIDTH/2) - PILL_WIDTH), int(random.choice('1111111111111111111122222334')))
pill2 = Pill(random.randrange((WIDTH/2) + PILL_WIDTH, WIDTH - PILL_WIDTH), int(random.choice('1111111111111111111122222334')))
pill_group.add(pill)
pill_group.add(pill2)
#Update Groups
ship_group.update(pill_group)
pill_group.update()
#Draw/Blit Groups
screen.fill(WHITE)
screen.blit(ship_left.score.image, ship_left.score.rect)
screen.blit(ship_right.score_2.image, ship_right.score_2.rect)
ship_group.draw(screen)
pill_group.draw(screen)
screen.blit(vertical, (WIDTH/2, TOP_BUFFER))
screen.blit(horizontal, (0, TOP_BUFFER))
#60 / second one pill / 10 iterations
loop_counter += 1
#Limits frames per iteration of while loop
clock.tick(60)
# Writes to main surface
pygame.display.flip()
if (ship_left.density >= 500 or ship_right.density >= 500):
play = False
while outro:
for event in pygame.event.get():
if event.type == pygame.QUIT: sys.exit()
if event.type == pygame.MOUSEBUTTONDOWN or pygame.key.get_pressed()[pygame.K_RETURN != 0]:
outro = False
play = True
ship_left.density = 0
ship_right.density = 0
for p in pill_group:
p.kill()
ship_left = Ship(WIDTH / 4 - SHIP_WIDTH / 2, HEIGHT - (4 * SHIP_HEIGHT), "left")
ship_right = Ship((WIDTH * 3) / 4 - SHIP_WIDTH / 2, HEIGHT - (4 * SHIP_HEIGHT), "right")
screen.blit(ship_left.image, ship_left.rect)
screen.blit(ship_right.image, ship_right.rect)
#Draw/Blit Groups
screen.fill(WHITE)
if (ship_left.density >= 500):
screen.blit(LeftWins.image, LeftWins.rect)
screen.blit(Winner.image, Winner.rect)
if (ship_right.density >= 500):
screen.blit(RightWins.image, RightWins.rect)
screen.blit(Winner.image, Winner.rect)
#Limits frames per iteration of while loop
clock.tick(60)
# Writes to main surface
pygame.display.flip()
if __name__ == "__main__":
main()
One way to solve this (but arguably not the best one) is to move the setup code inside the while True loop and ditch the reset code in while outro:
def main():
# The setup code from here ...
while True:
# Goes here
#Gameplay
while play:
# The Gameplay code
while outro:
for event in pygame.event.get():
if event.type == pygame.QUIT: sys.exit()
if event.type == pygame.MOUSEBUTTONDOWN or pygame.key.get_pressed()[pygame.K_RETURN != 0]:
outro = False
#Draw/Blit Groups
screen.fill(WHITE)
# The reset of outro
When my player sprite collides with the coin group the coins disappear as wanted, but when it collides with the enemys group nothing happens. The code is the same. I don't know what I did wrong because I did the same thing twice but it only works once. Does it have anything to do with the enemys moving? Here is the the code:
import pygame as pg
import random
a_white = (245, 245, 245)
a_red = (10, 0, 0)
black = (0, 0, 0)
white = (255, 255, 255)
blue_grey = (51, 93, 127)
dark_red = (85, 0, 0)
red = (255, 0, 0)
green = (0, 255, 0)
blue = (0, 0, 255)
yellow = (255, 255, 0)
bg_color = dark_red
width = 600
height = 500
FPS = 60
p_width = 70
p_height = 70
c_width = 35
c_height = 35
score = 0
level = 0
lives = 3
title = 'This Is My Game!'
pg.init()
pg.mixer.init()
clock = pg.time.Clock()
screen = pg.display.set_mode((width, height))
pg.display.set_caption(title)
font_name = pg.font.match_font("arial")
coin_img = pg.image.load('coin3.png').convert()
player_img = pg.image.load('smiley.png').convert_alpha()
gegner_1 = pg.image.load('gegner_black.png').convert_alpha()
coin_snd = pg.mixer.Sound('coin_snd_2.ogg')
def new_coin():
x = random.randrange(c_width, width - c_width)
y = random.randrange(c_height, height - c_height)
coins = Coin(x, y)
all_sprites.add(player, coins)
coin_group.add(coins)
def draw_text(screen, text, t_color, size, t_x, t_y):
font = pg.font.Font(font_name, size)
text_surface = font.render(text, True, t_color)
text_rect = text_surface.get_rect()
text_rect.midtop = (t_x, t_y)
screen.blit(text_surface, text_rect)
def start_screen():
screen.fill(bg_color)
draw_text(screen, 'Welcome... !', white, 75, width / 2, height / 4 - 100)
draw_text(screen, 'ready to play my game*?', white, 24, width - 150, height / 4 - 20)
draw_text(screen, "Press any key to begin", white, 20, width / 2 + 60, height / 4 + 10)
draw_text(screen, "*The name of the game is \'MY GAME\' but that ",
white, 16, width / 2, height - 150)
draw_text(screen, " has nothing to do with the fact, that the game is", white, 16, width / 2, height - 130)
draw_text(screen, " my game. Yes, the game is actually my game, ", white, 16, width / 2, height - 110)
draw_text(screen, " but that\'s not the reason I named it my game. ", white, 16, width / 2, height - 90)
draw_text(screen, "...or is it?", white, 13, width - 28, height - 20)
pg.display.update()
waiting = True
while waiting:
clock.tick(FPS)
for event in pg.event.get():
if event.type == pg.QUIT:
pg.quit()
if event.type == pg.KEYUP:
waiting = False
class Player(pg.sprite.Sprite):
def __init__(self):
super().__init__()
self.image_orig = pg.transform.scale(player_img, (p_width, p_height))
self.image = self.image_orig.copy()
self.rect = self.image.get_rect()
self.rect.center = (width / 2), (height / 2)
self.radius = 35
def update(self):
keys = pg.key.get_pressed()
if keys[pg.K_RIGHT]:
self.rect.x += 5
if keys[pg.K_LEFT]:
self.rect.x -= 5
if keys[pg.K_UP]:
self.rect.y -= 5
if keys[pg.K_DOWN]:
self.rect.y += 5
if self.rect.right > width:
self.rect.right = width
if self.rect.left < 0:
self.rect.left = 0
if self.rect.top < 0:
self.rect.top = 0
if self.rect.bottom > height:
self.rect.bottom = height
class Coin(pg.sprite.Sprite):
def __init__(self, x, y):
super().__init__()
self.image = pg.transform.scale(coin_img, (c_width, c_height))
self.image.set_colorkey(white)
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
self.radius = 18
class Gegner_1(pg.sprite.Sprite):
def __init__(self, x, y, yon):
super().__init__()
self.image_orig = pg.transform.scale(gegner_1, (p_width, p_height))
self.image_orig.set_colorkey(white)
self.image = self.image_orig.copy()
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
self.radius = 35
self.yon = yon
if yon == 'yes':
self.speedx = 5
self.speed = self.speedx
elif yon == 'no':
self.speedy = 5
self.speed = self.speedy
def update(self):
if self.yon == 'yes':
self.rect.x += self.speed
if self.yon == 'no':
self.rect.y += self.speed
if self.rect.right > width:
self.speed = -5
if self.rect.left == 0:
self.speed = 5
if self.rect.bottom > height:
self.speed = -5
if self.rect.top < 0:
self.speed = 5
all_sprites = pg.sprite.Group()
coin_group = pg.sprite.Group()
enemys_group = pg.sprite.Group()
player = Player()
gegner1 = Gegner_1(0, 60, 'yes')
gegner2 = Gegner_1(width, 350, 'yes')
gegner3 = Gegner_1(50, p_height, 'no')
gegner4 = Gegner_1(width - p_width - 20, p_height, 'no')
enemys_group.add(gegner1, gegner2, gegner3, gegner4)
all_sprites.add(player)
for c in range(3):
new_coin()
start_game = True
game_over = False
done = False
while not done:
for event in pg.event.get():
if event.type == pg.QUIT:
done = True
if start_game:
start_screen()
start_game = False
screen.fill(bg_color)
if score >= 5:
all_sprites.add(gegner1)
if score >= 10:
all_sprites.add(gegner2)
if score >= 15:
all_sprites.add(gegner3)
if score >= 20:
all_sprites.add(gegner4)
all_sprites.draw(screen)
all_sprites.update()
draw_text(screen, 'SCORE: ' + str(score), white, 20, 55, 10)
hits = pg.sprite.spritecollide(player, coin_group, True, pg.sprite.collide_circle)
for hit in hits:
score += 1
coin_snd.play()
new_coin()
hits = pg.sprite.spritecollide(player, enemys_group, True, pg.sprite.collide_circle)
for hit in hits:
lives -= 1
pg.display.update()
clock.tick(FPS)
pg.quit()
I also don't get any errors because of this.
The way you add and remove the gegner instances causes this problem. The enemys_group contains the gegners in the beginning and is used for the collision detection. That means you can already collide with them before they are visible (print the groups and hit in the for hit in hits: loop to check this). If you hit an instance, it is removed from the enemys_group correctly.
Then if you reach a score of 5 or higher you keep adding the instances, that are still bound to the gegner1, etc. variables, to the all_sprites group each frame, so the sprites become visible, but if they're not in the enemys_group they can't collide anymore.
You need to restructure the code. I'd leave the enemys_group empty at the beginning and then add the gegner instances in the coin collision loop:
hits = pg.sprite.spritecollide(player, coin_group, True, pg.sprite.collide_circle)
for hit in hits:
score += 1
new_coin()
if score == 5:
gegner = Gegner_1(0, 60, 'yes')
all_sprites.add(gegner)
enemys_group.add(gegner)
elif score == 10:
gegner = Gegner_1(width, 350, 'yes')
all_sprites.add(gegner)
enemys_group.add(gegner)
elif score == 15:
gegner = Gegner_1(50, p_height, 'no')
all_sprites.add(gegner)
enemys_group.add(gegner)
elif score == 20:
gegner = Gegner_1(width - p_width - 20, p_height, 'no')
all_sprites.add(gegner)
enemys_group.add(gegner)