I know this question has been asked before but I'v tried different approaches and I can't seem to be able to fix it.
I know I have to reset my important global variables in order to correctly restart the game.
The reset of those variables is done when lives == 0 -> I reset the global variables, main menu becomes True and Game False which should put me back in the main menu.
However when I run my game, as soon as the lives reach 0 the code finishes and exits -> Process finished with exit code 0.
The issue must be in my while game loop but I'm unsure what I'm doing wrong.
I'v also tried wrapping my game logic in a function, this seems to mess with my game since I only get the frozen state screen, no enemy spawning and not able to move.
Any ideas what might cause this issue?
Full code:
import pygame
import pygame_gui
import random
# Initialize game window here
pygame.init()
# Variables for the game window
window = pygame.display.set_mode((800, 800))
manager = pygame_gui.UIManager((800, 800))
pygame.display.set_caption('Sea Invaders')
clock = pygame.time.Clock() # Adds the clock for spawn timers
score_font = pygame.font.SysFont('Calibri', 36)
multiplier_font = pygame.font.SysFont('Calibri', 18)
# Sprites, background, UI and music
background = pygame.image.load('Background.jpg')
whale_sprite = pygame.image.load('Whale.png')
speedboat_sprite = pygame.image.load('Speedboat.png')
beam_sprite = pygame.image.load('Beam.png')
life_sprite = pygame.image.load('Life.png')
pirate_boss_sprite_right = pygame.image.load('Pirateboss_right.png')
game_title = pygame_gui.elements.UILabel(relative_rect=pygame.Rect((200, 100), (400, 100)), text='SEA INVADERS',
manager=manager)
description_box = pygame_gui.elements.UILabel(relative_rect=pygame.Rect((150, 250), (500, 100)),
text='Protect the ocean as long as possible by destroying ships',
manager=manager)
start_button = pygame_gui.elements.UIButton(relative_rect=pygame.Rect((350, 400), (100, 50)), text='Start',
manager=manager)
quit_button = pygame_gui.elements.UIButton(relative_rect=pygame.Rect((350, 450), (100, 50)), text='Quit',
manager=manager)
# Classes
class Player():
def __init__(self, x, y, width, height):
# Variables for the Whale go here
self.x = x
self.y = y
self.width = width
self.height = height
self.mov_speed = 5
self.hitbox = (self.x, self.y, self.width, self.height)
def draw(self, window):
# This function draws the whale using the sprite and the defined location in the class parameters
window.blit(whale_sprite, (self.x, self.y))
self.hitbox = (self.x, self.y, self.width, self.height)
# Whale hitbox check
# pygame.draw.rect(window, (255, 0, 0), self.hitbox, 2)
class Enemy(pygame.sprite.Sprite):
def __init__(self, width, height, mov_speed):
# Variables for the various enemies
pygame.sprite.Sprite.__init__(self)
self.width = width
self.height = height
self.mov_speed = mov_speed
self.image = speedboat_sprite
self.rect = self.image.get_rect()
self.rect.x = random.randint(64, 734)
self.rect.y = random.randrange(-150, -100)
self.hitbox = (self.rect.x + 22, self.rect.y + 15, 19, 45)
self.alive = True
def update(self):
# This function lets the enemy go forward until the end of the screen
max_distance = 800 - self.height
if self.rect.y < max_distance:
self.rect.y += self.mov_speed
def hit(self):
# This function deletes the sprite from the sprite group when hit by an attack from a player
self.kill()
self.alive = False
class Boss():
def __init__(self, x, y, width, height, mov_speed, hitpoints):
# Variables for the boss objects
self.x = x
self.y = y
self.width = width
self.height = height
self.mov_speed = mov_speed
self.hitpoints = hitpoints
self.hitbox = (self.x + 30, self.y + 50, 225, 160) # Dimensions of the hitbox to make it close to the model
self.alive = False
self.killed = False
self.end_reached = False
def draw(self, window):
if self.alive and not self.killed:
window.blit(pirate_boss_sprite_right, (self.x, self.y))
self.hitbox = (self.x + 30, self.y + 50, 225, 160)
pygame.draw.rect(window, (255, 0, 0),
(self.x + ((self.width / 2) - (self.hitpoints / 2)), self.y + 220, 50, 10))
pygame.draw.rect(window, (0, 255, 0),
(self.x + ((self.width / 2) - (self.hitpoints / 2)), self.y + 220, self.hitpoints, 10))
# Pirate Boss hitbox check
# pygame.draw.rect(window, (255, 0, 0), self.hitbox, 2)
def move(self):
# This function moves the boss forward. As soon as the boss reaches the end it spawns lower on the screen.
# If the end is reached the model is deleted and the end_reached parameter is set tot True.
max_distance = 800 - self.height
if self.x < (800 + self.width):
self.x += self.mov_speed
else:
self.y += 100
self.x = -51
if self.y >= max_distance:
self.alive = False
self.end_reached = True
def hit(self):
# As soon as the Whale hitpoints reaches 0, the model is overwritten on screen.
if self.hitpoints <= 0:
self.killed = True
return True
class Projectile():
def __init__(self, x, y, width, height, speed, damage, image):
# Variables for the player attacks (ranged)
self.x = x
self.y = y
self.width = width
self.height = height
self.speed = speed
self.damage = damage
self.image = image
self.rect = self.image.get_rect()
def draw(self, window):
window.blit(self.image, (self.x, self.y))
def checkCollision(self, enemy):
# This function checks collision with enemies that belong to a Sprite Group.
self.rect.x = int(self.x)
self.rect.y = int(self.y)
# noinspection PyTypeChecker
return any(pygame.sprite.spritecollide(self, enemy, True))
class Hud():
# class to place the HUDS on the screen (lives, score)
def __init__(self, x, y, sprite):
self.x = x
self.y = y
self.sprite = sprite
def draw(self, window):
window.blit(self.sprite, (self.x, self.y))
# Methods
def redrawUI():
window.blit(background, (0, 0)) # Loads in the background
whale.draw(window) # Draws the Whale in the game
window.blit(speedboat_sprite, (100, 100))
window.blit(speedboat_sprite, (620, 100))
manager.draw_ui(window)
if lives == 0:
text = f'Game over! Your score: {score}.'
game_over = score_font.render(text, True, (0, 0, 0))
window.blit(game_over, (200, 200))
pygame.display.update()
def redrawGameWindow():
window.blit(background, (0, 0)) # Loads in the background
whale.draw(window) # Draws the Whale in the game
scoreboard = score_font.render(str(score), True, (255, 255, 255))
multiplier_message = multiplier_font.render(f'multiplier: {multiplier}', True, (255, 255, 255))
window.blit(scoreboard, (700, 760))
window.blit(multiplier_message, (85, 766))
x_life = 0
# This for loop places the lives next to eachother on the HUD
for life in range(lives):
life = Hud(x_life, 760, life_sprite)
x_life += 25
life.draw(window)
for b in bosses:
b.alive = True
b.draw(window)
b.move()
speedboats.draw(window)
speedboats.update()
for fired_beam in beams:
fired_beam.draw(window)
pygame.display.update() # This updates the above changes to the game window
# Game logic here
main_menu = True
game = False
FPS = 100
whale = Player(334, 650, 128, 128) # Spawns the Player at the start of the game in the middle of the screen
speedboat_locations = (125, 150, 200, 250, 300, 350, 400, 450, 500, 550, 600, 650, 700, 750, 800)
speedboats = pygame.sprite.Group()
bosses = []
beams = []
cooldown = 0
lives = 3
score = 0
speedboat_hits = 0
multiplier = 1
start = pygame.time.get_ticks()
while main_menu:
time_delta = clock.tick(60) / 1000.0
for event in pygame.event.get(): # this for-loop makes sure the game exits when clicking x
if event.type == pygame.QUIT:
main_menu = False
if event.type == pygame.USEREVENT:
if event.user_type == pygame_gui.UI_BUTTON_PRESSED:
if event.ui_element == start_button:
game = True
main_menu = False
if event.ui_element == quit_button:
main_menu = False
manager.process_events(event)
manager.update(time_delta)
redrawUI()
while game:
for event in pygame.event.get(): # this for-loop makes sure the game exits when clicking x
if event.type == pygame.QUIT:
game = False
# Life check
for speedboat in speedboats:
if speedboat.rect.y >= 734:
speedboat.kill()
lives -= 1
if not speedboat.alive:
speedboats.remove(speedboat)
for pirate_boss in bosses:
if pirate_boss.end_reached and not pirate_boss.killed:
lives = 0
if lives == 0:
whale = Player(334, 650, 128, 128) # Spawns the Player at the start of the game in the middle of the screen
speedboat_locations = (125, 150, 200, 250, 300, 350, 400, 450, 500, 550, 600, 650, 700, 750, 800)
speedboats = pygame.sprite.Group()
bosses = []
beams = []
cooldown = 0
lives = 3
score = 0
speedboat_hits = 0
multiplier = 1
main_menu = True
game = False
# Basic cooldown for the projectiles of the player
if cooldown > 0:
cooldown += 1
if cooldown > 50:
cooldown = 0
# Collision of attacks
for beam in beams:
if beam.checkCollision(speedboats):
speedboat_hits += 1
score += (25 * multiplier)
beams.pop(beams.index(beam))
for pirate_boss in bosses:
if pirate_boss.alive and not pirate_boss.killed:
if beam.y - beam.width < pirate_boss.hitbox[1] + pirate_boss.hitbox[3] and beam.y + beam.width > \
pirate_boss.hitbox[1]:
if beam.x + beam.height > pirate_boss.hitbox[0] and beam.x - beam.height < pirate_boss.hitbox[0] + \
pirate_boss.hitbox[2]:
pirate_boss.hitpoints -= beam.damage
beams.pop(beams.index(beam))
alive_check = pirate_boss.hit()
if alive_check:
multiplier += 1
bosses.remove(pirate_boss)
if beam.y > 0:
beam.y -= beam.speed # This makes sure the bullet moves forward as long as it is not of the screen
beam.rect.center = (beam.x, beam.y)
else:
beams.pop(beams.index(beam)) # If the bullet goes of the screen it gets removed from the list
# --- PLAYER CONTROLS ---
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT] and whale.x > whale.mov_speed:
# Makes sure the whale can move left
# and prevents the whale from exiting the screen
whale.x = whale.x - whale.mov_speed
if keys[pygame.K_RIGHT] and whale.x < 800 - whale.mov_speed - whale.width:
# Makes sure the whale can move right
# and prevents the whale from exiting the screen
whale.x = whale.x + whale.mov_speed
if keys[pygame.K_SPACE] and cooldown == 0:
# This block of code takes care of the beam-projectile the player can shoot
if len(beams) < 3:
beams.append(
Projectile(round(whale.x + (whale.width // 2) - (32 // 2)), round(whale.y - (32 // 2)), 32, 32, 2,
10, beam_sprite))
# The beam gets spawned at the whale X/Y Coordinate. To make the beam appear in the middle and at the
# nose we add half the sprites width - half the width of the projectile to the for the x coordinate
# and we use the y coordinate - half the length of the projectile to make the attack spawn at the top
cooldown = 1
# --- ENEMY SPAWNING ---
now = pygame.time.get_ticks()
spawn_time = 3000
speedboat = Enemy(64, 64, 1)
boss = Boss(1, 1, 256, 256, 1, 50)
# Game loop to increase difficulty
if score > 500:
spawn_time = 2000
if score > 1000:
spawn_time = 1500
if score > 5000:
speedboat = Enemy(64, 64, 2)
spawn_time = 2000
if score > 10000:
speedboat = Enemy(64, 64, 2)
spawn_time = 1500
if now - start > spawn_time:
start = now
speedboats.add(speedboat)
if speedboat_hits >= 10:
bosses.append(boss)
speedboat_hits = 0
redrawGameWindow()
clock.tick(FPS)
You are setting game = False, but using that in the while loop. As soon as game is set to False the while loop exits and the game ends. If you want to do it this way, use another variable in the while loop:
running = True
while running:
if game:
game_loop()
elif menu:
menu_loop()
Then use game and menu as switches to decide which thing to show.
Related
I'm newbe in programming and I'm still learn and i try make my first platform game.
In first steps everything was good but i have problem with detect collision with platform.
I add collision if player is falling and it work good, but if I try add collision with bottom, left and right side platform, is not working good :(
I add all code to cleary view. If player is falling, code work okay.
Do You have idea what I can do, to add collisions?
#main
# Project 1 - platform game
import pygame as pg
import random
from settings import *
from sprites import *
from os import path
class Game:
def __init__(self):
# inicjalizacja okna gry itd
pg.init()
pg.mixer.init()
self.screen = pg.display.set_mode((WIDTH, HEIGHT))
pg.display.set_caption(TITLE)
self.clock = pg.time.Clock()
self.running = True
self.font_name = pg.font.match_font(FONT_NAME) # fonts
def new(self):
# start a new game
self.all_sprites = pg.sprite.Group() # all sprite's
self.platforms = pg.sprite.Group()
self.player = Player(self) # dodaję gracza
self.all_sprites.add(self.player)
# dodaję platformy
for plat in PLATFORM_LIST:
p = Platform(*plat)
self.all_sprites.add(p)
self.platforms.add(p)
#ground generator
i = 0
x = 0
while i < 35:
ground = Platform(x, HEIGHT - 40, 50, 40)
self.all_sprites.add(ground)
self.platforms.add(ground)
i += 1
x += 50
self.run() # game loop start
def run(self):
# game loop
self.playing = True
while self.playing:
self.clock.tick(FPS)
self.events()
self.update()
self.draw()
def update(self):
# game loop udpate
self.all_sprites.update()
# collision if player is falling
if self.player.vel.y > 0:
hits = pg.sprite.spritecollide(self.player, self.platforms, False)
if hits:
self.player.pos.y = hits[0].rect.top
self.player.vel.y = 0
# still I don't have idea what I can make collision with right, left and bottom
platform
# if player reach 1/2 screen
if self.player.rect.right >= WIDTH / 2:
self.player.pos.x -= abs(self.player.vel.x)
for plat in self.platforms:
plat.rect.right -= abs(self.player.vel.x)
if plat.rect.right <= WIDTH:
plat.kill
# player die
if self.player.rect.bottom > HEIGHT:
self.playing = False
def events(self):
# game loop - events
for event in pg.event.get():
if event.type == pg.QUIT:
if self.playing:
self.playing = False
self.running = False
if event.type == pg.KEYDOWN:
if event.key == pg.K_SPACE:
self.player.jump()
def draw(self):
#game loop - draw
self.screen.fill(BLACK)
self.all_sprites.draw(self.screen)
pg.display.flip()
def show_start_screen(self):
# start screen not add yet
pass
def show_go_screen(self):
# game over screen
if not self.running:
return
self.screen.fill(BLUE)
self.draw_text("GAME OVER!", 48, WHITE, WIDTH / 2, HEIGHT / 4)
self.draw_text("Press button to play again", 22, WHITE, WIDTH / 2, HEIGHT * 3 / 4)
pg.display.flip()
self.wait_for_key()
def wait_for_key(self):
waiting = True
while waiting:
self.clock.tick(FPS)
for event in pg.event.get():
if event.type == pg.QUIT:
waiting = False
self.running = False
if event.type == pg.KEYUP:
waiting = False
def draw_text(self, text, size, color, x, y):
font = pg.font.Font(self.font_name, size)
text_surface = font.render(text, True, color)
text_rect = text_surface.get_rect()
text_rect.midtop = (x, y)
self.screen.blit(text_surface, text_rect)
g = Game()
g.show_start_screen()
while g.running:
g.new()
g.show_go_screen()
pg.quit()
#SPRITES
import pygame as pg
from settings import *
import random
vec = pg.math.Vector2
class Player(pg.sprite.Sprite):
def __init__(self, game):
pg.sprite.Sprite.__init__(self)
self.game = game
self.image = pg.Surface((30, 40))
self.image.fill(YELLOW)
self.rect = self.image.get_rect()
self.rect.center = (WIDTH / 2, HEIGHT / 2)
self.pos = vec(WIDTH / 2, HEIGHT / 2)
self.vel = vec(0, 0)
self.acc = vec(0, 0)
def jump(self):
self.rect.x += 1
hits = pg.sprite.spritecollide(self, self.game.platforms, False)
self.rect.x -= 1
if hits:
self.vel.y = - PLAYER_JUMP
def update(self):
self.acc = vec(0, PLAYER_GRAV) # PLAYER_GRAV - gravity
keys = pg.key.get_pressed()
if keys[pg.K_LEFT]:
self.acc.x = - PLAYER_ACC
if keys[pg.K_RIGHT]:
self.acc.x = PLAYER_ACC
# add friction
self.acc.x += self.vel.x * PLAYER_FRICTION
# równanie ruchu
self.vel += self.acc
if abs(self.vel.x) < 0.1:
self.vel.x = 0
self.pos += self.vel + 0.5 * self.acc
if self.pos.x > WIDTH:
self.pos.x = WIDTH
if self.pos.x < 0:
self.pos.x = 0
self.rect.midbottom = self.pos
class Platform(pg.sprite.Sprite):
def __init__(self, x, y, w, h):
pg.sprite.Sprite.__init__(self)
self.image = pg.Surface((w, h))
self.image.fill(GREEN)
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
# settings
TITLE = "Project One"
WIDTH = 800
HEIGHT = 600
FPS = 60
FONT_NAME = 'comic sans ms' # arial, verdana, times new roman, palatino, garamond, comic sans ms
# ustawienia gracza
PLAYER_FRICTION = -0.12
PLAYER_ACC = 0.5
PLAYER_JUMP = 20
PLAYER_GRAV = 0.8
# lista platform
GROUND_LIST =[(0, HEIGHT - 40, 50, 40),
(50, HEIGHT - 40, 50, 40),
(100, HEIGHT - 40, 50, 40),
(150, HEIGHT - 40, 50, 40),
(200, HEIGHT - 40, 50, 40),
(250, HEIGHT - 40, 50, 40),
(300, HEIGHT - 40, 50, 40),
(350, HEIGHT - 40, 50, 40),
(400, HEIGHT - 40, 50, 40)]
PLATFORM_LIST = [(300, 300, 75, 40),
(400, 350, 75, 40),
(600, 300, 75, 40),
(800, 250, 75, 40),
(1000, 350, 75, 40),
(1200, 400, 75, 40),
(1400, 200, 75, 40),]
# defined 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)
I write again,
I did some work and found a solution to my problem :) I had to describe the collisions for x and y separately. Additionally, entering the collisions inside the Player class helped to eliminate the problem with the player jumping to the top platforms.
I'm making a snake game in python, and I've almost finished, but I'm struggling to solve an issue. In the main class in the collision method, I wrote some code to detect the snake collision with the borders of the screen, and if the statement is true, the snake will return to its original state. However, when I run the program the collision detection only works once. Afterwards, the snake is able to simply move off the screen. Thanks in advance.
import pygame
import random
pygame.init()
clock = pygame.time.Clock()
# Screen setup
screen_width = 600
screen_height = 600
screen = pygame.display.set_mode((screen_width, screen_height))
pygame.display.set_caption("Snake")
cellSize = 20
# Colors
black = (0, 0, 0)
white = (255, 255, 255)
blue = (255, 0, 0)
green = (0, 0, 255)
# Grid
def draw_grid():
# Vertical lines
for x in range(0, screen_height, cellSize):
pygame.draw.line(screen, white, (x, 0), (x, screen_height))
# Horizontal lines
for y in range(0, screen_width, cellSize):
pygame.draw.line(screen, white, (0, y), (screen_width, y))
# Maze
class MAZE:
def __init__(self):
self.rect_width = 20
self.rect_height = 20
self.rects = []
def draw_rects(self):
# Drawing Maze
pass
# Snake
class SNAKE(MAZE):
def __init__(self):
super().__init__()
self.width = 20
self.height = 20
self.speed = 20
self.initBody = [[3 * cellSize, 40], [4 * cellSize, 40], [5 * cellSize, 40]]
self.body = [[3 * cellSize, 40], [4 * cellSize, 40], [5 * cellSize, 40]]
self.rects = []
self.move = [0, 0]
self.grow = False
def draw_snake(self):
# Drawing snake body
for cor in self.body:
snake_rect = pygame.Rect(cor[0], cor[1], self.width, self.height)
self.rects.append(snake_rect)
pygame.draw.rect(screen, blue, snake_rect)
def move_snake(self):
# Key bindings
key = pygame.key.get_pressed()
if key[pygame.K_UP]:
self.move = [0, -1]
if key[pygame.K_DOWN]:
self.move = [0, 1]
if key[pygame.K_LEFT]:
self.move = [-1, 0]
if key[pygame.K_RIGHT]:
self.move = [1, 0]
if self.move[0] != 0 or self.move[1] != 0:
# Adding rects to the end of snake body
new_rect = self.body[-1][:]
new_rect[0] += self.move[0] * cellSize
new_rect[1] += self.move[1] * cellSize
self.body.append(new_rect)
# Removing rects from tail
if self.grow == False:
self.body.pop(0)
self.grow = False
# Food
class FOOD_1:
def __init__(self):
self.width = 20
self.height = 20
self.x = 4 * cellSize
self.y = 4 * cellSize
self.food_rect = pygame.Rect(self.x, self.y, self.width, self.height)
def draw_food_1(self):
pygame.draw.rect(screen, green, self.food_rect)
maze = MAZE()
snake = SNAKE()
food_1 = FOOD_1()
class MAIN():
def __init__(self):
self.maze = MAZE()
self.snake = SNAKE()
self.food_1 = FOOD_1()
def draw(self):
self.maze.draw_rects()
self.snake.draw_snake()
self.food_1.draw_food_1()
def move(self):
self.snake.move_snake()
def collision(self):
# Snake and food collision
for rect in self.snake.rects:
if rect.colliderect(self.food_1.food_rect):
self.food_1.x = random.randint(0, 29) * cellSize
self.food_1.y = random.randint(0, 29) * cellSize
self.food_1.food_rect.topleft = (self.food_1.x, self.food_1.y)
self.snake.grow = True
# Border collisions
if self.snake.body[-1][0] <= 0:
self.snake.body = self.snake.initBody
elif self.snake.body[-1][0] >= 600:
self.snake.body = self.snake.initBody
elif self.snake.body[-1][1] <= 0:
self.snake.body = self.snake.initBody
elif self.snake.body[-1][1] >= 600:
self.snake.body = self.snake.initBody
main = MAIN()
# Main loop
run = True
while run:
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
# Drawing on screen
screen.fill(black)
main.draw()
draw_grid()
# Movement and Collisions
main.move()
main.collision()
pygame.display.flip()
clock.tick(10)
pygame.quit()
When you do self.snake.body = self.snake.initBody, you are not making a copy of initBody, you are defining body as being the same object as initBody, so when you modify one, the other is modified too...which happens while playing.
So after the first collision, initBody is modified at the same time as body (as they have become the same thing), so when another collision happens, the line self.snake.body = self.snake.initBody does nothing.
You need to replace it with self.snake.body = self.snake.initBody.copy() so that the original initBody remains intact.
Better you make a code like this in your loop.
if playerx = 0:
playerx = 0
if playerx = 600:
playerx = 600:
Use same method for also y axis.
I have a simple shooter game using pygame. I'm having some problems making the bullet's y coordinate slowly increasing up. I know this is something to do with the way I've programmed the Player class even though a bullet Rect is in it. I think I have to change the update function inside it. This is my code:
import pygame, random, sys, time
pygame.init()
#Constants
WIDTH = 800
HEIGHT = 500
BLACK = (0, 0, 0)
WHITE = (255, 255, 255) # Background Colour
RED = (255, 0, 0)
GREEN = (0, 255, 0)
window = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Pygame Shooter Game")
clock = pygame.time.Clock()
fps = 60
run = True
class Player():
def __init__(self, width, colour, x, y):
self.width = width
self.colour = colour
self.x = x
self.y = y
self.vel = 5
self.shoot = False
self.player = pygame.Rect(self.x, self.y, self.width, self.width)
self.cartridge = pygame.Rect(0, 0, self.width/2, self.width/2)
self.bullet = pygame.Rect(0, 0, 10, 20)
self.shoot = False
def draw(self, win):
self.win = win
pygame.draw.rect(self.win, self.colour, self.player) # Draw player(rect)
pygame.draw.rect(self.win, GREEN, self.cartridge) #Draw cartridge
if self.shoot:
pygame.draw.rect(self.win, BLACK, self.bullet)
def move(self):
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT] and self.x > 0: self.x -= self.vel # We don't do elif cuz we want them to be able to move diagonally
if keys[pygame.K_RIGHT] and self.x < WIDTH-self.width: self.x += self.vel
if keys[pygame.K_UP] and self.y > 0: self.y -= self.vel
if keys[pygame.K_DOWN] and self.y < HEIGHT-self.width: self.y += self.vel
if keys[pygame.K_SPACE]:
self.shoot = True
def update(self):
self.player = pygame.Rect(self.x, self.y, self.width, self.width)
self.cartridge.midbottom = self.player.midtop
self.bullet.midbottom = self.cartridge.midtop
if self.shoot:
while self.bullet.y > 0:
self.bullet.y -= 1
def main(win):
run = True
player = Player(50, RED, WIDTH/2, HEIGHT/2)
while run:
win.fill(WHITE)
clock.tick(fps)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
player.move()
player.update()
player.draw(win)
pygame.display.update()
pygame.quit()
sys.exit()
main(window)
Also, how can I make the create classes for each individual Cartridge and Bullet, to make the whole code more efficient?
update is invoked continuously in the main application loop. Therefore, no additional animation loops are required for the update. Change the loop to a selection (change while to if):
while self.bullet.y > 0:
if self.bullet.y > 0:
self.bullet.y -= 1
The starting position of the bullet must be set when the bullet is shot, rather than continuously when the bullet is updated:
class Player():
# [...]
def move(self):
# [...]
if keys[pygame.K_SPACE]:
self.shoot = True
self.bullet.midbottom = self.cartridge.midtop # <--- INSERT
def update(self):
self.player = pygame.Rect(self.x, self.y, self.width, self.width)
self.cartridge.midbottom = self.player.midtop
# self.bullet.midbottom = self.cartridge.midtop <--- DELETE
if self.shoot:
if self.bullet.y > 0: # <--- if (not while)
self.bullet.y -= 1
See also:
How can i shoot a bullet with space bar?
How do I stop more than 1 bullet firing at once?
I have a problem when I made my code and This is the error it shows
platforms_list.append[pl,Platform([200,20], 100, 450, White), Platform([200,20], 400, 250, White)]
TypeError: 'builtin_function_or_method' object is not subscriptable
I don't get what it means by subscriptable. I have a circle player that can jump move and can go around but falls off his platform because there is no bottom platform and I don't no how to make it
import math
import os
import sys
# It is importing everything
import pygame
from pygame.locals import *
class Platform:
def __init__(self, size, x, y, color):
#size is a list, this means it has width and height
self.size = size
self.x = x
self.y = y
self.color = color
# This is what the platform class has and what it does
def draw(self):
display = pygame.display.get_surface()
pygame.draw.rect(display, self.color, (int(self.x), int(self.y), self.size[0], self.size[1]))
# This is def draw function is showing that how I want my Platform to look like
def do(self):
self.draw()
# The def do function is running def draw function
class Player:
def __init__(self, velocity, maxJumpRange, x, y, size):
self.falling = True
self.jumpCounter = 0
self.xVelocity = 0
self.y = y
self.x = x
self.jumping = False
self.velocity = velocity
self.maxJumpRange = maxJumpRange
self.jump_offset = 0
self.size = size
self.TouchedGround = False
# The player class is making how the Player is going to look and what are his limits
def keys(self):
k = pygame.key.get_pressed()
# The def keys(self): is creating a variable for pygame.key.get_pressed() and underneath is a function to make the player move around
if k[K_LEFT]:
self.xVelocity = -self.velocity
elif k[K_RIGHT]:
self.xVelocity = self.velocity
else:
self.xVelocity = 0
if (k[K_SPACE] or k[K_UP]) and not self.jumping and self.TouchedGround:
self.jumping = True
self.jumpCounter = 0
self.TouchedGround = False
# The if k[K_Space] or k[K_UP] is making sure the player has a jump limit and can't continue jumping forever.
def move(self):
self.x += self.xVelocity
# if the player is jumping, change y value
if self.jumping:
self.y -= self.velocity
self.jumpCounter += 1
if self.jumpCounter == self.maxJumpRange:
self.jumping = False
self.falling = True
elif self.falling:
self.y += self.velocity
self.jumpCounter -= 1
def draw(self):
display = pygame.display.get_surface()
pygame.draw.circle(display, White, (int(self.x), int(self.y)), self.size)
def do(self):
self.keys()
self.move()
self.draw()
# This Function is doing all of the Functions self.keys(), self.move(), self.draw()
def events():
for event in pygame.event.get():
if event.type == QUIT or (event.type == KEYDOWN and event.key == K_ESCAPE):
pygame.quit()
sys.exit()
#window size
w = 576
h = 516
# The above is showing the width the height and Area
os.environ['SDL_VIDEO_WINDOW_POS'] = "50,50"
# the above is showing what the graphics are
#player
p = Player(1, 100, 290, 250, 30)
#start pygame
pygame.init()
Clock = pygame.time.Clock()
DS = pygame.display.set_mode((w, h)) # This is what the display size is
pygame.display.set_caption("Try to get point B")
#variables
FPS = 120
Black = (0, 0, 0, 255)
White = (255, 255, 255, 255)
Red = (255, 0, 0)
# Bkgd stands for background
bkgd = pygame.Surface((w,h)) # didnt have the image so i made it blue
bkgd.fill((0,0,255))
#platforms
pl = Platform([290,20], 250, 350, White)
#this is a list that holds all the platforms
platforms_list = [pl,Platform([200,20], 100, 450, White), Platform([200,20], 400, 250, White)]
platforms_list.append[pl,Platform([200,20], 100, 450, White), Platform([200,20], 400, 250, White)]
#this is how much to scroll the background by
background_scroll = 0
# What the while true loop is doing is to make sure that the background moves while the player moves
while True:
events()
#blit the background, since the image is same size as window blit twice so when scrolls, you dont have blackness
DS.blit(bkgd, (-background_scroll, 0))
DS.blit(bkgd, (w-background_scroll, 0))
#check for x button clicked
events()
#update the player
p.do()
#update platforms and check for collision with player
platform_color = Red
for platform in platforms_list:
platform.color = platform_color
if p.jumping == 0:
platform.color = White
platform.do()
#if bottom of player is in the platform, move the player on top of the platform
if p.y + p.size > platform.y and p.y + p.size < platform.y + platform.size[1]:
if p.x > platform.x and p.x < platform.x + platform.size[0]:
p.y = platform.y - p.size
p.TouchedGround = True
#if the player reaches the side of the screen, move the background and platforms to make it look like it is moving
if p.x + p.size >= w:
p.x = w - p.size
background_scroll += 1
for platform in platforms_list:
platform.x -= 1
if background_scroll == w:
background_scroll = 0
#same but for the left
if p.x - p.size <= 0:
p.x = 0 + p.size
background_scroll -= 1
for platform in platforms_list:
platform.x += 1
if background_scroll == 0:
background_scroll = w
#update screen
pygame.display.update()
Clock.tick(FPS)
DS.fill(Black)
platforms_list.append[pl,Platform([200,20], 100, 450, White), Platform([200,20], 400, 250, White)] this is the code that I added but it keeps giving me the code
I think append needs to be .append() not [].
Try this:
platforms_list.append(pl,Platform([200,20], 100, 450, White), Platform([200,20], 400, 250, White))
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)