I have been trying to make a Fangame for Undertale with pygame but i am stuck. This is my first project. I want to replay the main loop with a few changes, for example i want the knife movement to be different, but i dont know how to do it. I have tried with attack2 to replay everything but it doesnt work, for example the player can't move and the knife is also not moving. I also tried defining the main loop but then i can't change anything. Please comment if you can help me. This is the code i have:
import math
import pygame
from pygame import mixer
pygame.init()
screen = pygame.display.set_mode((1000, 800))
# FPS
FPS = 60
clock = pygame.time.Clock()
# Title and icon
pygame.display.set_caption("CharaFight")
icon = pygame.image.load('Chara.png')
pygame.display.set_icon(icon)
# images
fight_button = pygame.image.load('Fight.png')
fight_button2 = pygame.image.load('Fight2.png')
hp_bar1 = pygame.image.load('hp_bar.png')
hp_bar2 = pygame.image.load('hp_bar2.png')
# music and sounds
background_muziek = mixer.music
damage_sound = mixer.Sound('Undertale Sound Effect - Taking Damage.wav')
background_muziek.load('Prepare for Battle!.wav')
background_muziek.set_volume(0.4)
background_muziek.play(-1)
# backgrounds
background = pygame.image.load("Background1.png")
background2 = pygame.image.load("Background2.png")
# Player
playerImg = pygame.image.load("Soul.png")
PlayerX = 450
PlayerY = 550
PlayerX_change = 0
PlayerY_change = 0
HP = 0
# Enemy
enemyImg = pygame.image.load("Chara2.png")
charaImg = pygame.image.load("Chara3.png")
EnemyX = 390
EnemyY = 50
EnemyX_change = 0
EnemyY_change = 0
# Knife
knifeImg = pygame.image.load("knife.png")
KnifeX = 350
KnifeY = 580
KnifeX_change = 5
KnifeY_change = 0
Knife_state = "ready"
# Game over text
over_font = pygame.font.Font('8-BIT WONDER.TTF', 64)
det_font = pygame.font.Font('8-BIT WONDER.TTF', 30)
emy_font = pygame.font.Font('Determination_text.ttf', 45)
def game_over_text():
over_text = over_font.render("GAME OVER", True, (255, 255, 255))
det_text = det_font.render(" Stay Determined ", True, (255, 255, 255))
screen.blit(over_text, (230, 250))
screen.blit(det_text, (280, 400))
def enemy_text():
chara_text = emy_font.render(" * Give me your SOUL! ", True, (255, 255, 255))
screen.blit(chara_text, (150, 500))
def fade(width, height):
fade1 = pygame.Surface((width, height))
fade1.fill((0, 0, 0))
for alpha in range(0, 150):
fade1.set_alpha(alpha)
screen.blit(fade1, (0, 0))
pygame.display.update()
pygame.time.delay(5)
def player(x, y):
screen.blit(playerImg, (x, y))
def enemy(x, y):
screen.blit(enemyImg, (x, y))
def fire_knife(x, y):
global Knife_state
Knife_state = "fire"
screen.blit(knifeImg, (x, y))
def isCollision(PlayerX, PlayerY, KnifeX, KnifeY):
distance = math.sqrt(math.pow(PlayerX - KnifeX, 2) + (math.pow(PlayerY - 37 - KnifeY, 2)))
if distance < 27:
return True
else:
return False
# Here is my attempt to replay the main loop
def attack2():
screen.fill((0, 0, 0))
player(PlayerX, PlayerY)
enemy(EnemyX, EnemyY)
fire_knife(KnifeY, KnifeX)
screen.blit(background, (100, 300))
pygame.display.flip()
# main loop
running = True
while running:
screen.fill((0, 0, 0))
screen.blit(background, (100, 300))
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
# Movement
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
PlayerX_change = -2.5
if event.key == pygame.K_RIGHT:
PlayerX_change = 2.5
if event.key == pygame.K_UP:
PlayerY_change = -2.5
if event.key == pygame.K_DOWN:
PlayerY_change = 2.5
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT or event.key == pygame.K_RIGHT:
PlayerX_change = 0
if event.key == pygame.K_UP or event.key == pygame.K_DOWN:
PlayerY_change = 0
# Boundaries for player
PlayerY += PlayerY_change
if PlayerY >= 700:
PlayerY = 700
elif PlayerY <= 520:
PlayerY = 520
PlayerX += PlayerX_change
if PlayerX <= 370:
PlayerX = 370
elif PlayerX >= 570:
PlayerX = 570
# Knife movement
if KnifeX >= 550:
KnifeX = 340
KnifeY += 20
Knife_state = "ready"
if KnifeY >= 680:
KnifeY = 480
Knife_state = "ready"
if Knife_state == "fire":
fire_knife(KnifeX, KnifeY)
KnifeX += KnifeX_change
# collision and game over screen
collision = isCollision(PlayerX, PlayerY, KnifeX, KnifeY)
if collision:
Knife_state = "ready"
damage_sound.set_volume(1.5)
damage_sound.play()
HP += 1
if HP > 100:
fade(1000, 800)
screen.fill((0, 0, 0))
game_over_text()
background_muziek.stop()
game_over_sound = mixer.music
game_over_sound.load('Undertale Game Over Theme.wav')
game_over_sound.play(-1)
pygame.display.flip()
pygame.time.wait(5000)
while True:
if pygame.key.get_pressed():
running = True
pygame.quit()
# Fight screen
if pygame.time.get_ticks() > 21700:
fade(1000, 800)
screen.fill((0, 0, 0))
enemy_text()
screen.blit(background2, (140, 250))
screen.blit(charaImg, (390, 50))
screen.blit(fight_button, (330, 630))
screen.blit(hp_bar1, (440, 350))
pygame.display.flip()
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = True
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
screen.blit(fight_button2, (330, 630))
screen.blit(hp_bar2, (440, 350))
damage_sound.set_volume(10)
damage_sound.play()
pygame.display.flip()
pygame.time.wait(5000)
attack2()------------------> here i try to replay the main loop but i cant move and the knife is also not moving.
if pygame.key.get_pressed():
running = True
clock.tick(FPS)
player(PlayerX, PlayerY)
enemy(EnemyX, EnemyY)
fire_knife(KnifeX, KnifeY)
pygame.display.update()
You can use a class like this to animate stuff:
import pygame
from os import listdir, path
def load_animations(folder_path: str) -> tuple:
animation = listdir(folder_path)
animation = tuple(pygame.image.load(path.join(folder_path, frame)).convert_alpha() for frame in animation)
return animation
class Animation:
def __init__(self, FPS: int, animation_folder: str, speed: float, pos: tuple):
self.animation = load_animations(animation_folder)
self.speed = speed
self.FPS = FPS
self.current_frame = 0
self.image = None
self.rect = None
self.pos = pos
def get_frame(self) -> pygame.Surface:
self.current_frame += self.speed * 10 / self.FPS
if self.current_frame >= len(self.animation):
return
return self.animation[int(self.current_frame)]
def play(self, screen: pygame.Surface):
self.image = self.get_frame()
if not self.image:
return
self.rect = self.image.get_rect(center=self.pos)
screen.blit(self.image, self.rect)
And to use this you would do something like:
animation = Animation(60, "path to the folder", 1, (100, 100))
# Put this inside the main loop.
animation.play(# Put the display surface in here)
And you should make a draw function for your whole game and put this code inside of the draw function (This function should handle all the graphics of your game).
Related
This question already has answers here:
how restarting game on pygame works
(1 answer)
Pygame restart function
(2 answers)
In game loop, how do I restart game properly using nested class or loop?
(1 answer)
Reset and restart pygame program doesn't work
(1 answer)
Closed 3 months ago.
I followed a tutorial guide on how to make this game but they never said how to put in a restart. I'm not quite sure how to do it, would anyone here know off the top of their head? Here's the code.
import pygame
import math
import random
from pygame import mixer
# Start the Program
pygame.init()
# Create the Screen
screen = pygame.display.set_mode((800, 600))
running = True
# Background
background = pygame.image.load('background.png')
# Background Sound
mixer.music.load('theme.mp3')
mixer.music.play(-1)
# Title and Icon
pygame.display.set_caption("Boot Craft")
icon = pygame.image.load('Starcraft.png')
pygame.display.set_icon(icon)
# Player
player_image = pygame.image.load('BC.png')
playerX = 370
playerY = 480
playerX_change = 0
playerY_change = 0
# Enemy
enemy_image = []
enemyX = []
enemyY = []
enemyX_change = []
enemyY_change = []
num_of_enemies = 6
for i in range(num_of_enemies):
enemy_image.append(pygame.image.load('Zergling.png'))
enemyX.append(random.randint(0, 768))
enemyY.append(random.randint(50, 150))
enemyX_change.append(0.2)
enemyY_change.append(40)
# Bullet
# Ready - You can't see the bullet on the screen
# Fire - The bullet is currently moving
bullet_image = pygame.image.load('Bullet.png')
bulletX = 0
bulletY = 480
bulletX_change = 0
bulletY_change = .5
bullet_state = "ready"
# Score
score_value = 0
font = pygame.font.Font('freesansbold.ttf', 32)
textX = 10
textY = 10
# Game Over
over_font = pygame.font.Font('freesansbold.ttf', 64)
def show_score(x,y):
score = font.render('Score: ' + str(score_value), True, (255,255,255))
screen.blit(score, (x, y))
def game_over_text():
over_text = over_font.render('GAME OVER', True, (255, 255, 255))
continue_text = over_font.render('CONTINUE? Y/N', True, (255, 255, 255))
screen.blit(over_text, (200, 250))
screen.blit(continue_text, (160, 350))
def player(x, y):
screen.blit(player_image, (x, y))
def enemy(x, y, i):
screen.blit(enemy_image[i], (x, y))
def fire_bullet(x, y):
global bullet_state
bullet_state = "fire"
screen.blit(bullet_image, (x + 8, y + 10))
def isCollision(enemyX, enemyY, bulletX, bulletY):
distance = math.sqrt((math.pow(enemyX - bulletX, 2)) + (math.pow(enemyY - bulletY, 2)))
if distance < 27:
return True
else:
return False
# Game Loop - Runs Game
while running:
# RGB Color Values 0-255
screen.fill((0, 0, 0))
# Background Image
screen.blit(background, (0, 0))
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_y:
running = True
# Check Key pressed.
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT or event.key == pygame.K_a:
playerX_change = -0.2
if event.key == pygame.K_RIGHT or event.key == pygame.K_d:
playerX_change = 0.2
if event.key == pygame.K_SPACE:
if bullet_state == "ready":
bullet_sound = mixer.Sound('laser.wav')
bullet_sound.play()
# Get the current X coordinate of the spaceship
bulletX = playerX
fire_bullet(bulletX, bulletY)
# Check Key released.
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT or event.key == pygame.K_RIGHT or event.key == pygame.K_a or event.key == pygame.K_d:
playerX_change = 0
playerX += playerX_change
# Adds Boundary
if playerX <= 0:
playerX = 0
elif playerX >= 721:
playerX = 721
# Enemy Movement
for i in range(num_of_enemies):
# Game Over
if enemyY[i] > 440:
for j in range(num_of_enemies):
enemyY[j] = 2000
game_over_text()
enemyX[i] += enemyX_change[i]
if enemyX[i] <= 0:
enemyX_change[i] = 0.2
enemyY[i] += enemyY_change[i]
elif enemyX[i] >= 768:
enemyX_change[i] = -0.2
enemyY[i] += enemyY_change[i]
# Collision
collision = isCollision(enemyX[i],enemyY[i],bulletX,bulletY)
if collision:
explosion_sound = mixer.Sound('explode.wav')
explosion_sound.play()
bulletY = 480
bullet_state = "ready"
score_value += 1
enemyX[i] = random.randint(0, 768)
enemyY[i] = random.randint(50, 150)
enemy(enemyX[i], enemyY[i], i)
# Bullet Movement
if bulletY <= 0:
bulletY = 480
bullet_state = "ready"
if bullet_state == "fire":
fire_bullet(bulletX, bulletY)
bulletY -= bulletY_change
player(playerX, playerY)
show_score(textX, textY)
pygame.display.update()
I'm not sure what to try, as what I googled used different ways of running the game. New to this, so genuinely confused.
I've completed a PyGame lesson and written all of the tutorial's code. And I'm presently working on a Restart button for the game, which basically allows you to re-play the game without having to re-run the code. I've created the button's class and made the button itself clickable; the only thing I'm lacking is a mechanism to restart the game by hitting the button.
import pygame
import random
import math
from pygame import mixer
# Initialize PyGame
pygame.init()
# Create the screen
screen = pygame.display.set_mode((800, 600))
# Background
background = pygame.image.load('background.png')
# Background Music
mixer.music.load('background.wav')
mixer.music.play(-1)
# Title and Icon
pygame.display.set_caption("Space Invaders")
icon = pygame.image.load('ufo.png')
pygame.display.set_icon(icon)
# Player
PlayerImg = pygame.image.load('player.png')
PlayerX = 370
PlayerY = 480
PlayerX_change = 0
# Enemy
enemyImg = []
enemyX = []
enemyY = []
enemyX_change = []
enemyY_change = []
num_of_enemies = 6
for i in range(num_of_enemies):
enemyImg.append(pygame.image.load('enemy.png'))
enemyX.append(random.randint(100, 736))
enemyY.append(random.randint(50, 150))
enemyX_change.append(4)
enemyY_change.append(40)
# Bullet
# Ready - You can't see the bullet on the screen
# Fire - The bullet is currently moving
bulletImg = pygame.image.load('bullet.png')
bulletX = 0
bulletY = 480
bulletX_change = 0
bulletY_change = 2.5
bullet_state = "ready"
# Score
score_value = 0
font = pygame.font.Font('freesansbold.ttf', 32)
textX = 10
textY = 10
# Game Over
over_font = pygame.font.Font('freesansbold.ttf', 64)
# Final Score
final_font = pygame.font.Font('freesansbold.ttf', 40)
# Restart Button
button_img = pygame.image.load('restart.png')
buttonX = 350
buttonY = 375
GameOver = False
def show_score(x, y):
score = font.render("Score : " + str(score_value), True, (255, 255, 255))
screen.blit(score, (x, y))
def game_over_text():
over_text = over_font.render("GAME OVER", True, (255, 255, 255))
screen.blit(over_text, (200, 250))
def final_score_text():
final_text = final_font.render("Final Score: " + str(score_value), True, (255, 255, 255))
screen.blit(final_text, (260, 325))
def player(x, y):
screen.blit(PlayerImg, (x, y))
def enemy(x, y):
screen.blit(enemyImg[i], (x, y))
def fire_bullet(x, y):
global bullet_state
bullet_state = "fire"
screen.blit(bulletImg, (x + 16, y + 10))
def isCollision(enemyX, enemyY, bulletX, bulletY):
distance = math.sqrt(math.pow(enemyX - bulletX, 2) + (math.pow(enemyY - bulletY, 2)))
if distance < 27:
return True
else:
return False
class Button():
def __init__(self, x, y, image):
self.image = image
self.rect = self.image.get_rect()
self.rect.topleft = (x, y)
def draw(self):
action = False
# get mouse position
pos = pygame.mouse.get_pos()
# check if mouse is over the button
if self.rect.collidepoint(pos):
if pygame.mouse.get_pressed()[0] == 1:
action = True
# draw button
screen.blit(self.image, (self.rect.x, self.rect.y))
return action
# create restart button instance
button = Button(buttonX, buttonY, button_img)
# Game loop
running = True
while running:
# RGB - Red, Green, Blue
screen.fill((0, 0, 0))
# Background Image
screen.blit(background, (0, 0))
if GameOver is False:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
# If keystroke is pressed, check whether it's Right or Left
if event.type == pygame.KEYDOWN:
if event.key == ord(','):
PlayerX_change = -7
if event.key == ord('.'):
PlayerX_change = 7
if event.key == pygame.K_SPACE:
if bullet_state == "ready":
bullet_sound = mixer.Sound('laser.wav')
bullet_sound.play()
bulletX = PlayerX
fire_bullet(bulletX, bulletY)
if event.type == pygame.KEYUP:
if event.key == ord(',') or event.key == ord('.'):
PlayerX_change = 0
# Blits
player(PlayerX, PlayerY)
show_score(textX, textY)
# Player Boundaries
PlayerX += PlayerX_change
if PlayerX <= 0:
PlayerX = 0
elif PlayerX >= 736:
PlayerX = 736
# Enemy Movement
for i in range(num_of_enemies):
enemyX[i] += enemyX_change[i]
if enemyX[i] <= 0:
enemyX_change[i] = 3
enemyY[i] += enemyY_change[i]
elif enemyX[i] >= 736:
enemyX_change[i] = -3
enemyY[i] += enemyY_change[i]
# Collision
collision = isCollision(enemyX[i], enemyY[i], bulletX, bulletY)
if collision:
explosion_sound = mixer.Sound('explosion.wav')
explosion_sound.play()
bulletY = 480
bullet_state = "ready"
score_value += 100
enemyX[i] = random.randint(0, 736)
enemyY[i] = random.randint(50, 150)
enemy(enemyX[i], enemyY[i])
# Bullet Movement
if bulletY <= 0:
bulletY = 480
bullet_state = "ready"
if bullet_state == "fire":
fire_bullet(bulletX, bulletY)
bulletY -= bulletY_change
# Game Over
if enemyY[i] > 420:
GameOver = True
if GameOver is True:
for j in range(num_of_enemies):
enemyY[j] = 2000
game_over_text()
textY = 2000
final_score_text()
if button.draw() is True:
print("Clicked")
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
pygame.display.update()
Write a function that initializes all game states. The function must set all the relevant variables in global name space (Use the global statement):
def init_game():
global PlayerX, PlayerY, PlayerX_change
global bulletX, bulletY, bulletX_change, bulletY_change, bullet_state
global enemyImg, enemyX, enemyX, enemyX_change, enemyY_change, num_of_enemies
PlayerX = 370
PlayerY = 480
PlayerX_change = 0
bulletX = 0
bulletY = 480
bulletX_change = 0
bulletY_change = 2.5
bullet_state = "ready"
enemyImg = []
enemyX = []
enemyY = []
enemyX_change = []
enemyY_change = []
num_of_enemies = 6
for i in range(num_of_enemies):
enemyImg.append(pygame.image.load('enemy.png'))
enemyX.append(random.randint(100, 736))
enemyY.append(random.randint(50, 150))
enemyX_change.append(4)
enemyY_change.append(40)
Call the function before the application loop. Call it again when you click the button:
button = Button(buttonX, buttonY, button_img)
init_game()
# Game loop
running = True
while running:
# [...]
if GameOver is True:
# [...]
if button.draw() is True:
print("Clicked")
GameOver = False
init_game()
# [...]
In my below code using PyGame, the character won't move left or right and the bullet won't shoot. I'm not sure what's causing this. It works without the whole start menu with buttons concept so I was wondering if that is the issue?
import pygame
from pygame import mixer
import math
import random
import time
# Initialize pygame module
pygame.init()
# Create the screen
screen = pygame.display.set_mode((800, 600))
display_width = 800
display_height = 600
# Background
background = pygame.image.load('space1.jpg')
# Background Sound
mixer.music.load('background.wav')
mixer.music.play(-1)
# Title and Icon
pygame.display.set_caption('Space Invaders')
icon = pygame.image.load('ufo.png')
pygame.display.set_icon(icon)
# Player
playerImg = pygame.image.load('space-invaders.png')
playerX = 370
playerY = 480
player_change = 0
playerX += player_change
# Enemy
enemyImg = []
enemyX = []
enemyY = []
enemyX_change = []
enemyY_change = []
num_of_enemies = 6
# Colours
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
RED = (150, 0, 0)
GREEN = (0, 150, 0)
BRIGHT_RED = (255, 0,0)
BRIGHT_GREEN = (0, 255, 0)
for i in range(num_of_enemies):
enemyImg.append(pygame.image.load('alien.png'))
enemyX.append(random.randint(0, 736))
enemyY.append(random.randint(50, 150))
enemyX_change.append(2)
enemyY_change.append(40)
# Bullet
# Ready - You cant see the bullet on the screen
# Fire - The bullet is current moving
bulletImg = pygame.image.load('bullet.png')
bulletX = 0
bulletY = 480
bulletY_change = 10
bullet_state = 'ready'
# Score
score_value = 0
font = pygame.font.Font('freesansbold.ttf', 32)
textX = 10
textY = 10
# Game Over Text
over_font = pygame.font.Font('freesansbold.ttf', 64)
# Clock
clock = pygame.time.Clock()
def show_score(x, y):
score = font.render('score : ' + str(score_value), True, (0, 255, 0))
screen.blit(score, (x, y))
def game_over_text():
over_text = over_font.render('GAME OVER', True, (0, 255, 0))
screen.blit(over_text, (200, 250))
def player(x, y):
screen.blit(playerImg, (x, y))
def enemy(x, y, i):
screen.blit(enemyImg[i], (x, y))
def fire_bullet(x, y):
global bullet_state
bullet_state = 'fire'
screen.blit(bulletImg, (x + 16, y + 10))
def isCollision(enemyX, enemyY, bulletX, bulletY):
distance = math.sqrt((math.pow(enemyX - bulletX, 2)) + (math.pow(enemyY - bulletY, 2)))
if distance < 27:
return True
else:
return False
def text_objects(text, font):
textSurface = font.render(text, True, WHITE)
return textSurface, textSurface.get_rect()
def game_intro():
intro = True
while intro:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
screen.fill(BLACK)
largeText = pygame.font.Font('freesansbold.ttf', 105)
TextSurf, TextRect = text_objects('Space Invaders', largeText)
TextRect.center = ((display_width/2), 200)
screen.blit(TextSurf, TextRect)
button('Start Invasion', 325, 350, 150, 50, GREEN, BRIGHT_GREEN, 'play')
button('Quit Mission', 325, 450, 150, 50, RED, BRIGHT_RED, 'quit')
pygame.display.update()
clock.tick(15)
#Game Loop
def game_loop(playerX, playerY, player_change, bulletX, bulletY, bulletX_change, bulletY_change, bullet_state, bulletImg):
running = True
while running:
playerX = 370
playerY = 480
player_change = 0
playerX += player_change
# RGB R G B
screen.fill((0, 0, 0))
# 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 its left or right
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
player_change = -5
if event.key == pygame.K_RIGHT:
player_change = 5
if event.key == pygame.K_SPACE:
if bullet_state is 'ready':
bullet_sound = mixer.Sound('laser.wav')
bullet_sound.play()
# Get the current x coordinate of the spaceship
bulletX = playerX
fire_bullet(bulletX, bulletY)
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT or event.key == pygame.K_RIGHT:
player_change = 0
# boundary for spaceship
if playerX <= 0:
playerX = 0
elif playerX >= 736:
playerX = 736
# Enemy movement
for i in range(num_of_enemies):
# Game Over
if enemyY[i] > 440:
for j in range(num_of_enemies):
enemyY[j] = 2000
game_over_text()
break
enemyX[i] += enemyX_change[i]
if enemyX[i] <= 0:
enemyX_change[i] = 2
enemyY[i] += enemyY_change[i]
elif enemyX[i] >= 736:
enemyX_change[i] = -2
enemyY[i] += enemyY_change[i]
# Collision
collision = isCollision(enemyX[i], enemyY[i], bulletX, bulletY)
if collision:
explosion_sound = mixer.Sound('explosion.wav')
explosion_sound.play()
bulletY = 480
bullet_state = "ready"
score_value += 1
enemyX[i] = random.randint(0, 736)
enemyY[i] = random.randint(50, 150)
enemy(enemyX[i], enemyY[i], i)
# Bullet movement
if bulletY <= 0:
bulletY = 480
bullet_state = 'ready'
if bullet_state is 'fire':
fire_bullet(bulletX, bulletY)
bulletY -= bulletY_change
player(playerX, playerY)
show_score(textX, textY)
pygame.display.update()
def button(msg, x, y, w, h, inactivecolour, activecolour, action=None):
mouse = pygame.mouse.get_pos()
click = pygame.mouse.get_pressed()
if x + w > mouse[0] > x and y + h > mouse[1] > y:
pygame.draw.rect(screen, activecolour, (x, y, w, h))
if click[0] == 1 and action != None:
if action == 'play':
game_loop(370, 480, 0, 0, 480, 0, 10, 'ready', pygame.image.load('bullet.png'))
if action == 'quit':
pygame.quit()
quit()
else:
pygame.draw.rect(screen, inactivecolour, (x, y, w, h))
smallText = pygame.font.Font('freesansbold.ttf', 20)
textSurf, textRect = text_objects(msg, smallText)
textRect.center = ((x + (w / 2)), (y + (h / 2)))
screen.blit(textSurf, textRect)
game_intro()
the character won't move
The movement of the player player_change is continuously set 0, in the main application loop. Further more, the position of the player is continuously initialized:
def game_loop(playerX, playerY, player_change, bulletX, bulletY, bulletX_change, >bulletY_change, bullet_state, bulletImg):
running = True
while running:
playerX = 370
playerY = 480
player_change = 0
Initialize playerX, playerY and player_change before the loop:
def game_loop(playerX, playerY, player_change, bulletX, bulletY, bulletX_change, bulletY_change, bullet_state, bulletImg):
running = True
player_change = 0
playerX = 370
playerY = 480
while running:
playerX += player_change
# [...]
the bullet won't shoot
If you want to fire a bullet, then you have to set the initial position of the bullet bulletX, bulletY = playerX, playerY and set bullet_state = 'fire':
def game_loop(playerX, playerY, player_change, bulletX, bulletY, bulletX_change, bulletY_change, bullet_state, bulletImg):
# [...]
while running:
playerX += player_change
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
# If keystroke is pressed check whether its left or right
if event.type == pygame.KEYDOWN:
# [...]
if event.key == pygame.K_SPACE:
if bullet_state is 'ready':
#bullet_sound = mixer.Sound('laser.wav')
#bullet_sound.play()
# Get the current x coordinate of the spaceship
bulletX, bulletY = playerX, playerY
bullet_state = 'fire'
Note, the global variable bullet_state
def fire_bullet(x, y):
global bullet_state
bullet_state = 'fire'
is different to the local variable bullet_state in game_loop, because bullet_state is an argument to game_loop and thus a completely different variable in a different scope, which has casually the same name:
def game_loop(playerX, playerY, player_change, bulletX, bulletY,
bulletX_change, bulletY_change,
bullet_state, # <--- that is a new variable in local scope
# and not the "global" bullet_state
bulletImg):
# [...]
player_change = 0
playerX += player_change
Try swapping the order of these two lines. Otherwise the change will always be zero when the X location is updated.
I was confused about how to make the user's car be visible on top of the background. At the moment, when you move the car the track and car move as they should, but the car is under the racetrack. I have tried different blitting orders and i attempted the LayeredUpdates function but it didn't help. I may have been doing it wrong as i am very new to python/pygame. So i would like to know how to get the car to be driving on the track.
Thank you
import math
import random
import pygame
pygame.mixer.pre_init(44100,16,2,4096)
pygame.init()
screen = pygame.display.set_mode((1280, 800))
rect = screen.get_rect()
clock = pygame.time.Clock()
#music
pygame.mixer.music.load("Wice.mp3")
pygame.mixer.music.set_volume(0.5)
pygame.mixer.music.play(-1)
WHITE = pygame.Color('white')
VEHICLE1 = pygame.Surface((40, 70), pygame.SRCALPHA)
VEHICLE1.fill((130, 180, 20))
#blitting car onto 'rectangle car'
VEHICLE1 = pygame.image.load("YellowLambo.png")
screen.blit(VEHICLE1,(0,0))
pygame.display.update()
VEHICLE2 = pygame.Surface((40, 70), pygame.SRCALPHA)
VEHICLE2.fill((200, 120, 20))
#blitting computer's car
VEHICLE2 = pygame.image.load("RedLambo.png")
screen.blit(VEHICLE2,(0,0))
BACKGROUND = pygame.Surface((1280, 800))
BACKGROUND.fill((127, 69, 2))
BACKGROUND = pygame.image.load("track1.png").convert()
screen.blit(BACKGROUND,(0,0))
pygame.display.update()
class Entity(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
class VehicleSprite(Entity):
MAX_FORWARD_SPEED = 10
MAX_REVERSE_SPEED = 2
ACCELERATION = 0.05
TURN_SPEED = 0.000000000001
def __init__(self, image, position):
Entity.__init__(self)
self.src_image = image
self.image = image
self.rect = self.image.get_rect(center=position)
self.position = pygame.math.Vector2(position)
self.velocity = pygame.math.Vector2(0, 0)
self.speed = self.direction = 0
self.k_left = self.k_right = self.k_down = self.k_up = 0
def update(self, time):
# SIMULATION
self.speed += self.k_up + self.k_down
# To clamp the speed.
self.speed = max(-self.MAX_REVERSE_SPEED,
min(self.speed, self.MAX_FORWARD_SPEED))
# Degrees sprite is facing (direction)
self.direction += (self.k_right + self.k_left)
rad = math.radians(self.direction)
self.velocity.x = -self.speed*math.sin(rad)
self.velocity.y = -self.speed*math.cos(rad)
self.position += self.velocity
self.image = pygame.transform.rotate(self.src_image, self.direction)
self.rect = self.image.get_rect(center=self.position)
class Background(pygame.sprite.Sprite):
def __init__(self, image, location):
pygame.sprite.Sprite.__init__(self)
self.image = image
self.rect = self.image.get_rect(topleft=location)
def game_loop():
bike = VehicleSprite(VEHICLE1, rect.center)
pygame.sprite.LayeredUpdates.move_to_front
ball = VehicleSprite(VEHICLE2, rect.center)
bike_group = pygame.sprite.Group(bike)
ball_group = pygame.sprite.Group(ball)
all_sprites = pygame.sprite.Group(bike_group, ball_group)
background = Background(BACKGROUND, [0, 0])
camera = pygame.math.Vector2(0, 0)
done = False
while not done:
time = clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
elif event.type == pygame.KEYDOWN:
# Bike Input (Player 1)
if event.key == pygame.K_d:
bike.k_right = -5
elif event.key == pygame.K_a:
bike.k_left = 5
elif event.key == pygame.K_w:
bike.k_up = 2
elif event.key == pygame.K_s:
bike.k_down = -2
elif event.key == pygame.K_ESCAPE:
done = True
elif event.type == pygame.KEYUP:
if event.key == pygame.K_d:
bike.k_right = 0
elif event.key == pygame.K_a:
bike.k_left = 0
elif event.key == pygame.K_w:
bike.k_up = 0
elif event.key == pygame.K_s:
bike.k_down = 0
camera -= bike.velocity
all_sprites.update(time)
screen.fill(WHITE)
screen.blit(background.image, background.rect)
for sprite in all_sprites:
screen.blit(background.image, background.rect.topleft+camera)
screen.blit(sprite.image, sprite.rect.topleft+camera)
pygame.display.flip()
game_loop()
pygame.quit()
Look at these lines:
screen.blit(background.image, background.rect)
for sprite in all_sprites:
screen.blit(background.image, background.rect.topleft+camera)
screen.blit(sprite.image, sprite.rect.topleft+camera)
For each sprite you blit to the screen, you blit the background image again.
I guess you want something like:
screen.blit(background.image, background.rect.topleft+camera)
for sprite in all_sprites:
screen.blit(sprite.image, sprite.rect.topleft+camera)
drawing the background only once.
Not sure if it makes a difference but have you tried to replace:
for sprite in all_sprites:
screen.blit(background.image, background.rect.topleft+camera)
screen.blit(sprite.image, sprite.rect.topleft+camera)
with
all_sprites.draw(screen)
I am trying to detect when two of my sprites collide. The first thing I did was create a rectangle around my player (called player.img) then another around the trees that I want to detect (called background.treesrect). I set the coordinates of the players rectangle equal to the coordinates that update when the player moves by the user pressing keys but the players rectangle doesnt move. Then I used the sprite.colliderect(sprite) function to detect if they collide and it doesnt detect. Can someone show my why my player rectangle isnt updating and anything else that may be wrong?
EDIT I just figured out the collision by putting the function that draws the rectangle into the game loop instead of the player class but I ran into another weird problem. The rectangle moves faster than the player sprite for some reason and I cant figure out how to make the player sprite on top of the background and not show the player rectangle.
import pygame
import sys
from pygame.locals import *
#starts the program
pygame.init()
white = (255, 255, 255)
black = (0, 0, 0)
red = (255, 0, 0)
blue = (0, 0, 255)
green = (0, 255, 0)
yellow = (255, 255, 153)
#creates a window of 800x600
setDisplay = pygame.display.set_mode((800, 600))
pygame.display.set_caption('Menu')
img = pygame.image.load('C:\\Users\\Ben\\Documents\\sprite.png')
class Player(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.img = pygame.image.load('C:\\Users\\Ben\\Documents\\sprite.png').convert()
self.imgx = 10
self.imgy = 10
self.setDisplay = pygame.display.get_surface()
self.x = self.imgx
self.y = self.imgy
self.rect = pygame.draw.rect(setDisplay, pygame.Color(0, 0, 255), pygame.Rect(self.x, self.y, 32, 32))
def draw(self):
self.setDisplay.blit(self.img)
def load(self, filename):
self.img = pygame.image.load('C:\\Users\\Ben\\Documents\\sprite.png').convert_alpha()
class Background(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.img = pygame.image.load('C:\\Users\\Ben\\Documents\\background.png').convert()
self.img2 = pygame.image.load('C:\\Users\\Ben\\Documents\\trees1.png').convert()
self.treesx = 0
self.treesy = 70
self.treesrect = pygame.draw.rect(setDisplay, pygame.Color(0, 0, 255),pygame.Rect(self.treesx, self.treesy, 376, 100))
def draw(self):
self.setDisplay.blit(self.img)
self.setDisplay.blit(self.img2)
def load(self, filename):
self.img = pygame.image.load('C:\\Users\\Ben\\Documents\\background.png').convert_alpha()
self.img2 = pygame.image.load('C:\\Users\\Ben\\Documents\\trees1.png').convert_alpha()
def detectCollision(sprite1, sprite2):
if sprite1.colliderect(sprite2):
print("worked")
player = Player()
background = Background()
def gameLoop():
imgx = 10
imgy = 10
lead_x_change = 0
lead_y_change = 0
move_variable = 5
while True:
pygame.display.flip()
for event in pygame.event.get():
#print (event)
if event.type == QUIT:
pygame.quit()
sys.exit()
setDisplay.blit(background.img, [0, 0])
setDisplay.blit(background.img2, [0, 0])
setDisplay.blit(player.img, [player.imgx, player.imgy])
if player.rect.colliderect(background.treesrect):
print("collided")
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
lead_x_change = -move_variable
player.x -= 10
elif event.key == pygame.K_UP:
lead_y_change = -move_variable
elif event.key == pygame.K_RIGHT:
player.imgx += 10
player.x += 10
elif event.key == pygame.K_DOWN:
lead_y_change = move_variable
player.y += 10
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT:
lead_x_change = 0
elif event.key == pygame.K_UP:
lead_y_change = 0
elif event.key == pygame.K_RIGHT:
lead_x_change = 0
elif event.key == pygame.K_DOWN:
lead_y_change = 0
print(player.x, player.y)
player.imgx += lead_x_change
player.imgy += lead_y_change
pygame.display.flip()
pygame.display.update()
gameLoop()
#start (0, 71)
#length (376, 71)
#width (0, 168)
I think this may be due to the fact that, in the class Player, self.rect isn't right. Instead try:
self.rect = self.img.get_rect()
also, in your main loop, why are you blit-ing stuff in the event for loop?
Only put the key presses in for event in pygame.event.get()
There are other things that are very wrong in the code.
May I recommend this excellent tutorial for making games with sprites in pygame.