So i created space invaders with pygame and wanted to create a Quit and play again button when the player died. The quit button works but the play again button isn't working. I have not used a def for the button instead i have made it inside the code.This is my code:
import pygame
import random
import math
pygame.init()
screen = pygame.display.set_mode((800, 600)) # CREATING SCREEN
background = pygame.image.load('background.jpg')
pygame.display.set_caption("Space invaders") # Title of the game
icon = pygame.image.load('spaceship.png') # A variable for the icon of the game
pygame.display.set_icon(icon) # to display the icon
player_icon = pygame.image.load('space-invaders.png') # A variable for player's icon
playerX = 365 # X coordinate
playerY = 500 # Y coordinate
playerX_change = 0
def player(x, y):
screen.blit(player_icon,(x, y)) # Function to display player_icon {there is supposed to be a comma after image name}
enemy_icon = []
enemyX = []
enemyY = []
enemyX_change = []
enemyY_change =[]
num_of_enemies = 5
for i in range(num_of_enemies):
enemy_icon.append(pygame.image.load('alien.png')) # A variable for enemy's's icon
enemyX.append(random.randint(0,736)) # X coordinate
enemyY.append(random.randint(50 ,150)) # Y coordinate
enemyX_change.append(2)
enemyY_change.append(40)
def enemy(x, y, i):
screen.blit(enemy_icon[i], (x, y)) # Function to display enemy_icon {there is supposed to be a comma after image name}
bullet_icon = pygame.image.load('bullet.png') # A variable for enemy's's icon
bulletX = 0 # X coordinate
bulletY = 480 # Y coordinate
bulletX_change = 0
bulletY_change = 5
bullet_state = "ready"
score_value = 0
font = pygame.font.Font('freesansbold.ttf',32)
textX = 10
textY = 10
red = (200, 0, 0)
brigth_red = (255,0 ,0)
green = (0, 200, 0)
brigth_green = (0, 255, 0)
blue = (0, 0, 255)
white = (255,255,255)
black = (0, 0 ,0)
def show_score(x,y):
score = font.render('Score: ' + str(score_value), True, (255, 255, 255))
screen.blit(score, (x, y))
over_text = pygame.font.Font('freesansbold.ttf',128)
def game_over_text():
over_text = font.render('GAME OVER !!' , True, (255, 255, 255))
screen.blit(over_text, (300, 150))
def on_button(x,y,text =''):
button_text = pygame.font.Font('freesansbold.ttf', 5)
button_text = font.render(text, True, (black))
screen.blit(button_text, ((x + 5), (y + 5)))
def bullet(x, y):
screen.blit(bullet_icon, (x, y)) # Function to display enemy_icon {there is supposed to be a comma after image name}
def fire_bullet(x,y):
global bullet_state
bullet_state = "fire"
screen.blit(bullet_icon, (x+19, y+10))
def iscoalision(bulletX,bulletY,enemyX,enemyY):
distance = math.sqrt(math.pow(enemyX - bulletX,2) + math.pow(enemyY-bulletY,2))
if distance < 25:
return True
else:
return False
running = True
game_state = "not working"
while running :
screen.fill((0, 0, 0)) # to fill the screen with some color RGB = (red,green,blue)
screen.blit(background, (0,0))
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
round = 11
if event.type == pygame.KEYDOWN: # If arrow key is pressed change value of playerX_change
if event.key == pygame.K_LEFT:
playerX_change = -3
if event.key == pygame.K_RIGHT:
playerX_change = 3
if event.key == pygame.K_SPACE:
if bullet_state is "ready":
bulletX = playerX
fire_bullet(bulletX,bulletY)
if event.type == pygame.KEYUP: # If arrow key is released stop changing value of playerX_change
if event.key == pygame.K_LEFT or event.key == pygame.K_RIGHT:
playerX_change = 0
playerX += playerX_change #player movement
if playerX <= 0: #(The boundary)
playerX = 0
elif playerX >= 736: #( " )
playerX = 736
for i in range(num_of_enemies):
if enemyY[i] > 440:
for j in range(num_of_enemies):
enemyY[j] = 2000
game_over_text()
mouse = pygame.mouse.get_pos()
click = pygame.mouse.get_pressed()
if 100 + 200 > mouse[0] > 100 and 300 + 50 > mouse[1] > 300: # This is where i try to make play again button
pygame.draw.rect(screen, brigth_green, (100, 300, 200, 50)) # inside the bracket(x-axis , y-axis , width, hieght)
if click[0] == 1: #the tuple for clicks is (0,0,0) [0] = left click ,[1]= middle click. if clicked [0] or [1] or [2] = 1
pass
else:
pygame.draw.rect(screen, green, (100, 300, 200, 50))
on_button(100,300,'play again?')
if 500+ 200 >mouse[0] > 500 and 300 +50 >mouse[1] > 300:
pygame.draw.rect(screen, brigth_red, (500, 300, 200, 50))
if click[0] == 1:
running = False
break
else:
pygame.draw.rect(screen, red, (500, 300, 200, 50))
on_button((500 + 50),(300 + 5),"I QUIT")
enemyX[i] += enemyX_change[i] #enemy movement
if enemyX[i] <= 0: #(The boundary two and fro movement)
enemyX_change[i] = 2
enemyY[i] += enemyY_change[i]
elif enemyX[i] >= 736: #( " )
enemyX_change[i] = -2
enemyY[i] += enemyY_change[i]
coalision = iscoalision(bulletX, bulletY, enemyX[i], enemyY[i])
if coalision:
bullet_state = "ready"
bulletY = 480
score_value += 1
enemyX[i] = random.randint(0, 736)
enemyY[i] = random.randint(50, 150)
enemy(enemyX[i], enemyY[i], i)
if bulletY <= 0:
bullet_state = "ready"
bulletY = 480
if bullet_state is "fire":
fire_bullet(bulletX,bulletY)
bulletY -= bulletY_change
player(playerX, playerY)
show_score(textX, textY)
pygame.display.update()
Till now i have tried to put the entire while loop i an if condition that if condition is satisfied then run the while loop but that isn't working. I've also tried to put the entire code in a def and call out the def when i needed to play again and that worked but that made the bullets bug which i couldn't fix. Here is the play agin button and function.
for i in range(num_of_enemies):
if enemyY[i] > 440:
for j in range(num_of_enemies):
enemyY[j] = 2000
game_over_text()
mouse = pygame.mouse.get_pos()
click = pygame.mouse.get_pressed()
if 100 + 200 > mouse[0] > 100 and 300 + 50 > mouse[1] > 300:
pygame.draw.rect(screen, brigth_green, (100, 300, 200, 50))
if click[0] == 1:
pass
for now i filled the place for the button function with a pass. Hope this much info helps.
Firstly, make your code object oriented. If you don't know what that is, there are plenty of tutorials on youtube, but just looking at your code, I can see that you are going to run into a bunch of headache in the future if you continue without any type of classes and objects. You should make a class for player, enemy and bullets and then define their attributes and call methods on them such as move() or draw().
To answer you question, you can create a simple button class:
class Buttons(object):
def __init__(self, x, y, width, height, colour1, text='', func=None, arg=None): # pink buttons
self.x = x
self.y = y
self.width = width
self.height = height
self.colour1 = colour1
self.text = text
self.func = func
self.arg = arg
def draw(self, win): # draws centralised buttons and text
font = pygame.font.SysFont('comicsans', 30, True)
text = font.render(self.text, 1, colours["black"])
pygame.draw.rect(win, self.colour1,
(int(self.x - self.width // 2), int(self.y - self.height // 2), int(self.width), int(self.height)))
win.blit(text, (int(self.x - text.get_width() // 2), int(self.y - text.get_height() // 2)))
def isover(self, pos): # detects if mouse positions is above buttons'
if self.x < pos[0] < (self.x + self.width) and self.y < pos[1] < (self.y + self.height):
return True
return False
def isclicked(self, pos): # pos here is mouse position
if self.isover(pos):
if self.arg is not None:
self.func(*self.arg):
else:
self.func():
def quit(your_quit_args):
# this is your quit function. You might want to close any files, etc before quitting
def play_again(your_play_again_args):
# here, you should reset all values, clear queues, lists etc
With that then, to create a button, all you would need to do is just create a new button object:
# use the x, y, width, height, colour and text you want
btn_play_again = Button(x, y, width, height, colour, text=your_text, func=quit, args=your_quit_args)
btn_quit = Button(x, y, width, height, colour, text=your_text, func=play_again, args=your_play_again_args)
the above will create the button objects, but you have to actually draw them and check if they are clicked, which you should do in your main loop:
while running:
# everything else
btn_quit.draw(screen)
btn_play_again.draw(screen)
pos = pygame.mouse.get_pos()
btn_quit.isclicked(pos)
btn_play_Again.draw(pos)
pygame.display.update()
Note, if you have many buttons, it may be worth to put them all in a button list and iterate through it to avoid repeating code.
Related
I'm a beginner and have needed a lot of help to get this far. I'm trying to add more enemies when my score reaches certain values such as 10, 20, etc. Ive tried something along the lines of if score_value >= 10: num_of_enemies = num_of_enemies + 10 but have been failing to produce results. I feel like it should be simple but i am missing how to add values to this list.
import pygame
import random
import math
from pygame import mixer
# initialize game
pygame.init()
# create screen, set height and weight (())
screen = pygame.display.set_mode((800, 600))
# Background
background = pygame.image.load('background1.png')
pygame.display.set_icon(background)
# Background sound
mixer.music.load('troubador.wav')
mixer.music.play(-1)
# Title and Icon
pygame.display.set_caption("Beasts of Cthulu")
icon = pygame.image.load('knight.png')
pygame.display.set_icon(icon)
# Player
playerImg = pygame.image.load('wizard.png')
playerX = 370
playerY = 500
playerX_change = 0
# Enemy
enemyImg = []
enemyX = []
enemyY = []
enemyX_change = []
enemyY_change = []
num_of_enemies = 5
max_enemies = 100
for i in range(num_of_enemies):
enemyImg.append(pygame.image.load('cthulhu.png'))
enemyX.append(random.randint(0, 735))
enemyY.append(random.randint(10, 150))
enemyX_change.append(3)
enemyY_change.append(40)
# Fireball
# ready - you cannot see fireball on screen
# fire - fireball is currently moving
fireballImg = pygame.image.load('fireball.png')
fireballX = 0
fireballY = 370
fireballX_change = 0
fireballY_change = 8
fireball_state = "ready"
# Score
score_value = 0
previous_score = score_value
font = pygame.font.Font('Enchanted_Land.otf', 32)
textX = 10
textY = 10
# Game over text
over_font = pygame.font.Font('Enchanted_Land.otf', 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))
screen.blit(over_text, (250, 200))
def player(x, y):
screen.blit(playerImg, (x, y))
def enemy(x, y, i):
screen.blit(enemyImg[i], (x, y))
def fire_fireball(x, y):
global fireball_state
fireball_state = "fire"
screen.blit(fireballImg, (x + 16, y + 10))
def isCollision(enemyX, enemyY, fireballX, fireballY):
distance = math.sqrt(math.pow(enemyX - fireballX, 2) + (math.pow(enemyY - fireballY, 2)))
if distance < 27:
return True
else:
return False
# Game Loop
running = True
while running:
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
# Keyboard actions
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
playerX_change = -4
if event.key == pygame.K_RIGHT:
playerX_change = 4
if event.key == pygame.K_SPACE:
if fireball_state == "ready":
fireball_Sound = mixer.Sound('fireball-1.wav')
fireball_Sound.play()
fireballX = playerX
fire_fireball(fireballX, fireballY)
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT or event.key == pygame.K_RIGHT:
playerX_change = 0
# checking for boundaries
playerX += playerX_change
if playerX <= 0:
playerX = 0
elif playerX >= 736:
playerX = 736
# Fireball movement
if fireballY <= 0:
fireballY = 480
fireball_state = "ready"
if fireball_state == "fire":
fire_fireball(fireballX, fireballY)
fireballY -= fireballY_change
# Enemy movement
enemyX += enemyX_change
for i in range(num_of_enemies):
# Game Over
if enemyY[1] > 370:
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] = 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], fireballX, fireballY)
if collision:
explosion_Sound = mixer.Sound('fireball-explosion.wav')
explosion_Sound.play()
fireballY = 480
fireball_state = "ready"
score_value += 1
enemyX[i] = random.randint(0, 735)
enemyY[i] = random.randint(10, 150)
enemy(enemyX[i], enemyY[i], i)
player(playerX, playerY)
show_score(textX, textY)
pygame.display.update()
That's a lot of code and we can't run it, because we don't have the assets. What you need is a threshold, which increases once it was reached.
You can implement it like this:
import random
threshold = 10
score = 0
while score < 1000:
score += random.randint(1,4) # wherever points come from
print (f"Score {score}")
if score > threshold:
print (f"You have more than {threshold}. Adding enemies ...")
threshold += 10
See how the score can increase but enemies will only be added every 10 points and it needn't hit the value exactly.
The idea of #ThomasWeller is nice (+1). However, you will have difficulty adding it to your code.
Write a function that adds an enemy and use the function in the loop that creates the initial enemies:
enemySurf = pygame.image.load('cthulhu.png')
def addNewEnemy():
enemyImg.append(enemySurf)
enemyX.append(random.randint(0, 735))
enemyY.append(random.randint(10, 150))
enemyX_change.append(3)
enemyY_change.append(40)
for i in range(num_of_enemies):
addNewEnemy()
Use the idea of #ThomasWeller and add a new enemy when the scooter reaches a certain threshold:
threshold = 10
running = True
while running:
if score_value >= threshold:
addNewEnemy()
num_of_enemies += 1
threshold += 10
print(len(enemyX))
# [...]
I am working on a pong game. When either of the scores hit 10, it is supposed to put up some text on the screen and say the right player has won or left player has won. However, in my program, it isn't working. When it has to show the text that the right or left player has won, it doesn't show it. But it works for everything else. Here is the code:
# Importing libraries
import pygame
import random
import time
# Initializing PyGame
pygame.init()
# Setting a window name
pygame.display.set_caption("Ping Pong")
# Creating a font
pygame.font.init()
font = pygame.font.SysFont(None, 30)
pong_font = pygame.font.SysFont("comicsansms", 75)
# Set the height and width of the screen
window_width = 700
window_height = 500
size = [window_width, window_height]
game_win = pygame.display.set_mode(size)
game_win2 = pygame.display.set_mode(size)
# Creating a messaging system
def message(sentence, color, x, y, font_type, display):
sentence = font_type.render(sentence, True, color)
display.blit(sentence, [x, y])
# Creating colors
white = (225, 225, 225)
black = (0, 0, 0)
gray = (100, 100, 100)
# Setting up ball
ball_size = 25
class Ball:
"""
Class to keep track of a ball's location and vector.
"""
def __init__(self):
self.x = 0
self.y = 0
self.change_x = 0
self.change_y = 0
def make_ball():
ball = Ball()
# Starting position of the ball.
ball.x = 350
ball.y = 250
# Speed and direction of rectangle
ball.change_x = 5
ball.change_y = 5
return ball
def main():
# Scores
left_score = 0
right_score = 0
pygame.init()
# Loop until the user clicks the close button.
done = False
ball_list = []
ball = make_ball()
ball_list.append(ball)
# Right paddle coordinates
y = 200
y_change = 0
x = 50
# Left paddle coordinates
y1 = 200
y1_change = 0
x1 = 650
while not done:
# --- Event Processing
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_w:
y_change = -7
elif event.key == pygame.K_s:
y_change = 7
elif event.key == pygame.K_UP:
y1_change = -7
elif event.key == pygame.K_DOWN:
y1_change = 7
elif event.type == pygame.KEYUP:
y_change = 0
y1_change = 0
y += y_change
y1 += y1_change
# Preventing from letting the paddle go off screen
if y > window_height - 100:
y -= 10
if y < 50:
y += 10
if y1 > window_height - 100:
y1 -= 10
if y1 < 50:
y1 += 10
# Logic
for ball in ball_list:
# Move the ball's center
ball.x += ball.change_x
ball.y += ball.change_y
# Bounce the ball if needed
if ball.y > 500 - ball_size or ball.y < ball_size:
ball.change_y *= -1
if ball.x > window_width - ball_size:
ball.change_x *= -1
left_score += 1
if ball.x < ball_size:
ball.change_x *= -1
right_score += 1
ball_rect = pygame.Rect(ball.x - ball_size, ball.y - ball_size, ball_size * 2, ball_size * 2)
left_paddle_rect = pygame.Rect(x, y, 25, 75)
if ball.change_x < 0 and ball_rect.colliderect(left_paddle_rect):
ball.change_x = abs(ball.change_x)
right_paddle_rect = pygame.Rect(x1, y1, 25, 75)
if ball.change_x > 0 and ball_rect.colliderect(right_paddle_rect):
ball.change_x = -abs(ball.change_x)
# Here is the where the messaging system doesn't work, I don't know why! It works fine for everything else
if right_score == 10:
message("RIGHT PLAYER HAS WON!!", white, 300, 200, font, game_win)
time.sleep(5)
pygame.quit()
quit()
elif left_score == 10:
message("LEFT PLAYER HAS WON!!", white, 300, 200, font, game_win)
time.sleep(5)
pygame.quit()
quit()
# Drawing
# Set the screen background
game_win.fill(black)
# Draw the balls
for ball in ball_list:
pygame.draw.circle(game_win, white, [ball.x, ball.y], ball_size)
# Creating Scoreboard
message("Left player score: " + str(left_score), white, 10, 10, font, game_win)
message("Right player score: " + str(right_score), white, 490, 10, font, game_win)
# Drawing a left paddle
pygame.draw.rect(game_win, white, [x, y, 25, 100])
# Drawing a right paddle
pygame.draw.rect(game_win, white, [x1, y1, 25, 100])
# Setting FPS
FPS = pygame.time.Clock()
FPS.tick(60)
# Updating so actions take place
pygame.display.flip()
while True:
game_win2.fill(black)
pygame.event.get()
mouse = pygame.mouse.get_pos()
click = pygame.mouse.get_pressed()
message("Pong", white, 280, 100, pong_font, game_win2)
if 150 + 100 > mouse[0] > 150 and 350 + 50 > mouse[1] > 350:
pygame.draw.rect(game_win, gray, [150, 350, 100, 50])
if click[0] == 1:
break
else:
pygame.draw.rect(game_win, white, [150, 350, 100, 50])
if 450 + 100 > mouse[0] > 450 and 350 + 50 > mouse[1] > 350:
pygame.draw.rect(game_win, gray, [450, 350, 100, 50])
if click[0] == 1:
pygame.quit()
quit()
else:
pygame.draw.rect(game_win, white, [450, 350, 100, 50])
message("Start", black, 175, 367, font, game_win2)
message("Quit", black, 475, 367, font, game_win2)
# Go ahead and update the screen with what we've drawn.
pygame.display.flip()
# Wrap-up
# Limit to 60 frames per second
clock = pygame.time.Clock()
clock.tick(60)
if __name__ == "__main__":
main()
I have added a little comment, it is: "# Here is the where the messaging system doesn't work, I don't know why! It works fine for everything else". Now when someone scores 10 points, Nothing happens. Its= wait for a couple of seconds. That is so you can read the "Left player has won" or "Right player has won" before the program closes. But it simply doesn't show up! I don't know why! Can someone help with this?
The display is updated only if either pygame.display.update() or pygame.display.flip()
is called. See pygame.display.flip():
This will update the contents of the entire display.
Further you've to handles the events with pygame.event.pump(), before the update of the display becomes visible in the window.
See pygame.event.pump():
For each frame of your game, you will need to make some sort of call to the event queue. This ensures your program can internally interact with the rest of the operating system.
If you want to display a text and delay the game, then you've to update the display and handle the events.
Write a function which delays the game and updates the display. I recommend to use the pygame.time module to implement the delay (e.g. pygame.time.delay())
def update_and_wait(delay):
pygame.display.flip()
pygame.event.pump()
pygame.time.delay(delay * 1000) # 1 second == 1000 milliseconds
Or even implement a function which its own event loop to keep the application responding. Measure the time by pygame.time.get_ticks():
def update_and_wait(delay):
start_time = pygame.time.get_ticks()
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
print("auit")
pygame.quit()
return False
if pygame.time.get_ticks() >= start_time + delay * 1000:
break
return True
Use the function in the application:
def main():
# [...]
while not done:
# [...]
for ball in ball_list:
# [...]
if right_score == 0:
message_wait("RIGHT PLAYER HAS WON!!", white, 300, 200, font, game_win)
update_and_wait(5)
quit()
elif left_score == 0:
message_wait("LEFT PLAYER HAS WON!!", white, 300, 200, font, game_win)
update_and_wait(5)
quit()
so here is my code:
import math
import random
import time
import pygame
from pygame import mixer
import pygame_functions
from pygame_functions import *
# Initialises pygame
pygame.init()
pygame.display.init()
#Difficulty
num_of_enemies = 0
set_positive_enemyX_change = 0
set_negative_enemyX_change = 0
#Menu
def menu(num_of_enemies, set_positive_enemyX_change, set_negative_enemyX_change):
screenSize(1000, 1000)
# text, fontSize, xpos, ypos, fontColour='black', font='Arial', background='clear'
difficultyLabel = makeLabel("Which level of difficulty would you like to play on ?<br>The types are :<br>- easy<br>- medium<br>- hard<br>- insane", 40, 10, 10, "blue", "Agency FB", "yellow")
showLabel(difficultyLabel)
# x, y, width, case, text, max length, fontsize
inputBox = makeTextBox(10, 270, 300, 0, "Enter difficulty level here", 0, 24)
showTextBox(inputBox)
difficultyInput = textBoxInput(inputBox)
easyLabel = makeLabel("easy settings applied", 40, 20, 310, "white", "Agency FB", )
mediumLabel = makeLabel("medium settings applied", 40, 20, 310, "white", "Agency FB",)
hardLabel = makeLabel("hard settings applied", 40, 20, 310, "white", "Agency FB", )
insaneLabel = makeLabel("insane settings applied", 40, 20, 310, "white", "Agency FB")
startingLabel = makeLabel("Starting game", 40, 40, 310, "red", "Agency FB")
if difficultyInput == "easy":
showLabel(easyLabel)
num_of_enemies = 4
set_positive_enemyX_change = 1
set_negative_enemyX_change = -1
end()
if difficultyInput == "medium":
showLabel(mediumLabel)
num_of_enemies = 6
set_positive_enemyX_change = 1.5
set_negative_enemyX_change = -1.5
end()
showLabel(startingLabel)
if difficultyInput == "hard":
showLabel(hardLabel)
num_of_enemies = 7
set_positive_enemyX_change = 2
set_negative_enemyX_change = -2
end()
if difficultyInput == "insane":
showLabel(insaneLabel)
num_of_enemies = 8
set_positive_enemyX_change = 3.5
set_negative_enemyX_change = -3.5
end()
else:
menu(num_of_enemies, set_positive_enemyX_change, set_negative_enemyX_change)
menu(num_of_enemies, set_positive_enemyX_change, set_negative_enemyX_change)
# Creates the screen
screen = pygame.display.set_mode((800, 600))
# Background
background = pygame.image.load('hyperspace.png')
# Sound
mixer.music.load("background.wav")
mixer.music.play(-1)
global deathSound
global liveLossSound
liveLossSound = mixer.Sound("Death sound in Minecraft.wav")
deathSound = mixer.Sound("Pacman-death.wav")
liveLossSoundBoolean = True
deathSoundBoolean = True
# Caption and Icon
pygame.display.set_caption("Space Invader")
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 = []
for i in range(num_of_enemies):
enemyImg.append(pygame.image.load('enemy.png'))
enemyX.append(random.randint(0, 736))
enemyY.append(random.randint(50, 150))
enemyX_change.append(2)
enemyY_change.append(20)
# 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 = 5
bullet_state = "ready"
# Score
score_value = 0
font = pygame.font.Font('freesansbold.ttf', 32)
textSX = 10
textSY = 10
# Lives
lives_value = 3
textLX = 650
textLY = 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 show_lives(x, y):
lives = font.render("Lives : " + str(lives_value), True, (255, 255, 255))
screen.blit(lives, (x, y))
def game_over_text():
over_text = over_font.render("GAME OVER", True, (255, 255, 255))
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 play_liveLossSound():
liveLossSound.play()
liveLossSoundBoolean = False
def play_deathSound(deathSound):
deathSound.play()
deathSoundBoolean = False
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
# Game Loop
running = True
while running:
# RGB = Red, Green, Blue
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 right or left
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_SPACE:
if bullet_state is "ready":
bulletSound = mixer.Sound("laser.wav")
bulletSound.play()
# Gets the current x co-ordinate 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:
playerX_change = 0
# 5 = 5 + -0.1 -> 5 = 5 - 0.1
# 5 = 5 + 0.1
playerX += playerX_change
if playerX <= 0:
playerX = 0
elif playerX >= 736:
playerX = 736
# Enemy Movement
for i in range(num_of_enemies):
if enemyY[i] > 200: # was 440
lives_value -= 1
show_lives(textLX, textLY)
pygame.display.update()
if lives_value < 1:
for j in range(num_of_enemies):
enemyY[j] = -2000
if deathSoundBoolean:
play_deathSound(deathSound)
game_over_text()
time.sleep(5)
running = False
elif lives_value >= 1:
if liveLossSoundBoolean:
play_liveLossSound()
enemyX[i] = random.randint(0, 736)
enemyY[i] = random.randint(50, 150)
# Bouncing enemies off of edge of window // enemy speed
enemyX[i] += enemyX_change[i]
if enemyX[i] <= 0:
enemyX_change[i] = set_positive_enemyX_change
enemyY[i] += enemyY_change[i]
elif enemyX[i] >= 736:
enemyX_change[i] = set_negative_enemyX_change
enemyY[i] += enemyY_change[i]
# Collision
collision = isCollision(enemyX[i], enemyY[i], bulletX, bulletY)
if collision:
explosionSound = mixer.Sound("explosion.wav")
explosionSound.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(textSX, textSY)
show_lives(textLX, textLY)
pygame.display.update()
I am using this library from github https://github.com/StevePaget/Pygame_Functions/wiki ( i only used methods from this library from lines 18-63 )
I am trying to load the pygame window for my actual game after ( lines 66+) after the menu() function has finished
The problem is that I am getting these errors for no apparent reason, I am most concerned with the video initialisation error as it seems irrelevant to my program, the other errors I just do not understand as my program should logically work, as far as I understand.
You get the error video system not initialized because you called pygame.quit() beforehand (it's called by the end() function).
It even says so in the wiki of the library you use:
end()
Note: Any graphical commands which appear after the window has closed will raise an error.
There's usually no reason to call pygame.quit() at all, so I suggest to just remove it.
If you really want to close a window and open a new one, you can initialze the pygame module again (pygame.init()) and create a new window (pygame.display.set_mode(...)). But usually you're better of to restructure your code.
I want to know if my enemy is within 200 pixels of a defense tower so that I can start taking lives of the enemy. The enemy is moving and the defense is still FYI. if anyone can give me advice on how to do this that would be amazing. If I put my code up it will just confuse everyone because my code is very messy so just give me advice on how to do it thanks. Nick. I have added my code because I know I have done something wrong if anyone has the time to read through it and tell me what I am doing wrong which is probably everything that would be much appreciated.
import pygame
import math
from pygame.locals import *
def text():
font = pygame.font.SysFont("monospace", 14)
text = font.render("Start Round", True, black)
textpos = text.get_rect()
textpos.center = (790,675)
Background.blit(text, textpos)
def newRound():
pos = pygame.mouse.get_pos()
click = pygame.mouse.get_pressed()
if 730 < pos[0] < 850 and 650 < pos[1] < 800:
pygame.draw.rect(Background, (150,150,150), (730,650,120,50))
if click[0] == 1:
startGame()
else:
pygame.draw.rect(Background, (100,100,100), (730,650,120,50))
def startGame():
global startRound, endRound, intro
intro = 0
createRound()
intro = 1
startRound = True
endRound = False
def lifeText(lifes):
font = pygame.font.SysFont("monospace", 20)
text = font.render("Lives %s" % (lifes) , True, black)
textpos = text.get_rect()
textpos.center = (60,30)
Background.blit(text, textpos)
def life(self):
global hit, endRound, startRound, noEnemies, lifes
if noEnemies == 0 and lifes > 0:
startRound = False
endRound = True
if self.rect.x == 960:
hit = hit + 1
lifes = lifes - 1
if lifes == 0:
print("You have 0 lives Game Over")
pygame.quit()
if hit == 4:
startRound = False
endRound = True
hit = 0
noEnemies = noEnemies + 1
def createRound():
global enemies, noEnemies
enemies = []
x = -40
y = 210
for e in range(noEnemies):
x = x - 80
enemies.append(yellowEnemy(x, y, Background))
noEnemies = len(enemies)
def displayTower():
for tower in towers:
Background.blit(redtower, (tower))
class yellowEnemy(object):
image1 = pygame.image.load("enemySpriteFullHealth.jpg")
image2 = pygame.image.load("enemySpriteHalfHealth.jpg")
image3 = pygame.image.load("enemySpriteDead.jpg")
def __init__(self, x, y, Background):
self.Background = Background
self.Background_rect = Background.get_rect()
self.rect = self.image1.get_rect()
self.rect = self.image2.get_rect()
self.rect = self.image3.get_rect()
self.rect.x = x
self.rect.y = y
self.health = 20
self.dist_x = 2
self.dist_y = 0
def update(self):
self.rect.x += self.dist_x
self.rect.y += self.dist_y
def draw(self, Background):
timeDead = 0
if self.health > 9 and self.health < 21:
Background.blit(self.image1, self.rect)
elif self.health < 10 and self.health > 1:
Background.blit(self.image2, self.rect)
elif self.health < 1:
Background.blit(self.image3, self.rect)
self.dist_x = 0
life(self)
pygame.init()
width = 960
height = 720
black = (0,0,0)
lifes = 10
hit = 0
intro = 1
FPS = 200
noEnemies = 4
bx = 1000
by = 1000
towers = []
endRound = True
startRound = False
clicked = False
mx, my = pygame.mouse.get_pos()
clock = pygame.time.Clock()
test= False
mapImg = pygame.image.load("mapimage.jpg")
redtower = pygame.image.load("redTower.jpg")
Background = pygame.display.set_mode((width, height))
Background_rect = Background.get_rect()
while intro == 1:
mousePos = pygame.mouse.get_pos()
mousePressed = pygame.mouse.get_pressed()
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
if 530 < mousePos[0] < 590 and 650 < mousePos[1] < 710:
if mousePressed[0] == 1:
clicked = True
if clicked == True:
mx, my = pygame.mouse.get_pos()
pygame.display.update()
bx = 30
by = 30
if mousePressed[0] == 0:
clicked = False
tx = mx - bx
ty = my - by
towerCords = tx, ty
towers.append(towerCords)
if endRound == True:
Background.blit(mapImg, (0,0))
newRound()
text()
if startRound == True:
for enemy in enemies:
enemy.update()
Background.blit(mapImg, (0,0))
for enemy in enemies:
enemy.draw(Background)
Background.blit(redtower, (mx-bx, my-by))
if clicked == True:
pygame.draw.circle(Background, (220, 0, 0), (mx, my), 200, 4)
displayTower()
lifeText(lifes)
Background.blit(redtower, (530,650))
pygame.display.update()
clock.tick(FPS)
To find the distance between 2 points, you can use this code:
def get_dist(pos1, pos2):
return math.hypot(pos1[0] - pos2[0], pos1[1] - pos2[1])
This also requires you to import math at the beginning of your program.
If they are sprites, you can simply do:
import math
defense_rect = defense.get_rect()
if math.abs(enemy.rect.center - defense_rect.rect.center) <= 200:
# *do something*
The logic is to see if the enemy's center is 200 pixels from the defense's center from any position (hence the usage of math.abs() which is absolute value). When it is, you replace the comment with your code. Why does this work?
Check here.
Pygame has pygame.Rect() to keep object position and size.
Tower 200x200 with top left corner in point (0,0)
tower_rect = pygame.Rect(0,0, 300, 300)
or you can move it to have (0,0) in center
tower_rect = pygame.Rect(0,0, 300, 300)
tower_rect.center = (0, 0)
To check if other Rect() is fully inside tower
enemy_rect = pygame.Rect(10, 10, 50, 50)
if tower_rect.contains(enemy_rect):
or if it fully or only partially in tower (it coollides with tower)
if tower_rect.colliderect(enemy_rect):
You can event test with list of enemies
if tower_rect.collidelistall(list_of_enemies_rect):
or check one enemy with all towers
if enemy_rect.collidelistall(list_of_towers_rect):
So while working on my engine, I wanted to add an enemy in there, sounded simple enough. Even though my enemy is in the game, not violating the laws of physics (for the most part), the weird part is that I gave him 0 control over movement, but the enemy keeps following the player sprite as I move along.
Now playing around for a bit I've noticed the enemy latches on to the scrolling viewbox while the player is moving, hence the enemy slightly jumps when the player jumps as he hit the down viewbox.
I'm not trying to give him any AI at the moment, the enemy just needs to spawn along with the player, drop to a platform and stand still as the player moves away.
The whole code:
from pygame import *
import time
import pygame
# from colours import *
# from textObjects import small, medium, large
###########################################################################
# COLOURS AND TEXT OBJECTS #
###########################################################################
black = pygame.Color(0, 0, 0)
grey = pygame.Color(128, 128, 128)
white = pygame.Color(255, 255, 255)
red = pygame.Color(255, 0, 0)
green = pygame.Color(0, 255, 0)
light_blue = pygame.Color(201, 242, 255)
blue = pygame.Color(0, 0, 255)
green_yellow = pygame.Color(212, 255, 0)
yellow = pygame.Color(255, 251, 0)
orange = pygame.Color(255, 166, 0)
orange_red = pygame.Color(255, 85, 0)
pygame.font.init()
small = pygame.font.SysFont(None, 25)
medium = pygame.font.SysFont(None, 50)
large = pygame.font.SysFont(None, 80)
###########################################################################
# CLASSES #
###########################################################################
class Player(pygame.sprite.Sprite):
# Initialise function
def __init__(self, color=blue, width=32, height=48, health=100):
# I assume super() inherits everything from the block class
super(Player, self).__init__()
# Set the image to a Surface of size width and height
self.image = pygame.Surface((width, height))
# Fill the image with the default color of blue
self.image.fill(color)
# Use the Surface of the image to get the rectangular co-ordinates
self.set_properties()
# Create speed for x and y
self.speed_x = 0
self.speed_y = 0
# Create health
self.health = 100
self.level = None
def set_properties(self):
self.rect = self.image.get_rect()
# Create an x and y origin position (Centered the mouse on the sprite)
self.origin_x = self.rect.centerx
self.origin_y = self.rect.centery
self.speed = 5
# Create total travel distance to check the player's position on the map
self.travel_distance_x = 0
self.travel_distance_y = 0
# Function to easily set the position of any block object on the center
def set_position(self, x, y):
self.rect.x = x - self.origin_x
self.rect.y = y - self.origin_y
# Function made to print the position on the map
def print_position(self):
self.travel_distance_x += self.speed_x
self.travel_distance_y += self.speed_y
# print self.travel_distance_x, self.travel_distance_y
def set_level(self, level):
self.level = level
self.set_position(level.player_start_x, level.player_start_y)
def set_image(self, filename=None):
if filename != None:
self.image = pygame.image.load(filename).convert()
self.set_properties()
def update(self, collidable=pygame.sprite.Group(), event=True):
self.experience_gravity()
self.event = True
self.rect.x += self.speed_x
collision_list = pygame.sprite.spritecollide(self, collidable, False)
for collided_object in collision_list:
# Right direction
if self.speed_x > 0:
self.rect.right = collided_object.rect.left
# Left direction
elif self.speed_x < 0:
self.rect.left = collided_object.rect.right
self.rect.y += self.speed_y
collision_list = pygame.sprite.spritecollide(self, collidable, False)
for collided_object in collision_list:
# Down direction
if self.speed_y > 0:
self.rect.bottom = collided_object.rect.top
self.speed_y = 0
# Up direction
elif self.speed_y < 0:
self.rect.top = collided_object.rect.bottom
self.speed_y = 0
if not event == None:
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT or event.key == pygame.K_a:
self.speed_x = -self.speed
# self.change_speed(-self.speed, 0)
if event.key == pygame.K_RIGHT or event.key == pygame.K_d:
self.speed_x = self.speed
# self.change_speed(self.speed, 0)
if event.key == pygame.K_UP or event.key == pygame.K_w:
if len(collision_list) >= 1:
self.speed_y = -(self.speed) * 2
# self.change_speed(0, -self.speed * 2)
if event.key == pygame.K_DOWN:
# self.change_speed(0, self.speed)
pass
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT or event.key == pygame.K_a:
if self.speed_x < 0:
self.speed_x = 0
if event.key == pygame.K_RIGHT or event.key == pygame.K_d:
if self.speed_x > 0:
self.speed_x = 0
def experience_gravity(self, gravity=0.35):
if self.speed_y == 0:
self.speed_y = 1
else:
self.speed_y += gravity
class Enemy(pygame.sprite.Sprite):
# Initialise function
def __init__(self, color=red, width=32, height=48, health=100):
# I assume super() inherits everything from the block class
super(Enemy, self).__init__()
# Set the image to a Surface of size width and height
self.image = pygame.Surface((width, height))
# Fill the image with the default color of blue
self.image.fill(color)
# Use the Surface of the image to get the rectangular co-ordinates
self.set_properties()
# Create speed for x and y
self.speed_x = 0
self.speed_y = 0
# Create health
self.health = 100
self.level = None
def set_properties(self):
self.rect = self.image.get_rect()
# Create an x and y origin position (Centered the mouse on the sprite)
self.origin_x = self.rect.centerx
self.origin_y = self.rect.centery
self.speed = 5
# Create total travel distance to check the player's position on the map
self.travel_distance_x = 0
self.travel_distance_y = 0
# Function to easily set the position of any block object on the center
def set_position(self, x, y):
self.rect.x = x - self.origin_x
self.rect.y = y - self.origin_y
# Function made to print the position on the map
def print_position(self):
self.travel_distance_x += self.speed_x
self.travel_distance_y += self.speed_y
print self.travel_distance_x, self.travel_distance_y
def set_level(self, level):
self.level = level
self.set_position(level.enemy_start_x, level.enemy_start_y)
def set_image(self, filename=None):
if filename != None:
self.image = pygame.image.load(filename).convert()
self.set_properties()
def update(self, collidable=pygame.sprite.Group(), event=True):
self.experience_gravity()
self.event = True
self.rect.x += self.speed_x
collision_list = pygame.sprite.spritecollide(self, collidable, False)
for collided_object in collision_list:
# Right direction
if self.speed_x > 0:
self.rect.right = collided_object.rect.left
# Left direction
elif self.speed_x < 0:
self.rect.left = collided_object.rect.right
self.rect.y += self.speed_y
collision_list = pygame.sprite.spritecollide(self, collidable, False)
for collided_object in collision_list:
# Down direction
if self.speed_y > 0:
self.rect.bottom = collided_object.rect.top
self.speed_y = 0
# Up direction
elif self.speed_y < 0:
self.rect.top = collided_object.rect.bottom
self.speed_y = 0
if not event == None:
pass
def experience_gravity(self, gravity=0.35):
if self.speed_y == 0:
self.speed_y = 1
else:
self.speed_y += gravity
class Block(pygame.sprite.Sprite):
def __init__(self, x, y, width, height, color=blue):
# I assume super() inherits everything from the block class
super(Block, self).__init__()
# Set the image to a Surface of size width and height
self.image = pygame.Surface((width, height))
# Fill the image with the default color of blue
self.image.fill(color)
# Get rectangle object of the block
self.rect = self.image.get_rect()
# Assign x and y co-ordinates of the block
self.rect.x = x
self.rect.y = y
def experience_gravity(self, gravity=0.35):
if self.speed_y == 0:
self.speed_y = 1
else:
self.speed_y += gravity
class Level(object):
def __init__(self, player_object):
self.object_list = pygame.sprite.Group()
self.player_object = player_object
self.player_start = self.player_start_x, self.player_start_y = 80, 150
self.enemy_start = self.enemy_start_x, self.enemy_start_y = 300, 200
self.world_shift_x = 0
self.world_shift_y = 0
self.left_viewbox = screen_width / 2 - screen_width / 8
self.right_viewbox = screen_width / 2 + screen_width / 8
self.up_viewbox = screen_height / 3
self.down_viewbox = screen_height / 2 # + screen_height / 12
def update(self):
self.object_list.update()
def draw(self, screen):
screen.fill(white)
self.object_list.draw(screen)
def shift_world(self, shift_x, shift_y):
self.world_shift_x += shift_x
self.world_shift_y += shift_y
for each_object in self.object_list:
each_object.rect.x += shift_x
each_object.rect.y += shift_y
def scroll(self):
if self.player_object.rect.x <= self.left_viewbox:
view_difference = self.left_viewbox - self.player_object.rect.x
self.player_object.rect.x = self.left_viewbox
self.shift_world(view_difference, 0)
if self.player_object.rect.x >= self.right_viewbox:
view_difference = self.right_viewbox - self.player_object.rect.x
self.player_object.rect.x = self.right_viewbox
self.shift_world(view_difference, 0)
if self.player_object.rect.y <= self.up_viewbox:
view_difference = self.up_viewbox - self.player_object.rect.y
self.player_object.rect.y = self.up_viewbox
self.shift_world(0, view_difference)
if self.player_object.rect.y >= self.down_viewbox:
view_difference = self.down_viewbox - self.player_object.rect.y
self.player_object.rect.y = self.down_viewbox
self.shift_world(0, view_difference)
class Level_01(Level):
def __init__(self, player_object):
super(Level_01, self).__init__(player_object)
level = [
#[x, y, width, height, color]
[0, 0, 38, 899, black],
[7, 874, 1592, 25, black],
[1564, 0, 35, 887, black],
[0, 0, 1593, 40, black],
[330, 731, 282, 31, black],
[898, 678, 307, 28, black],
[603, 528, 280, 28, black],
[1279, 616, 301, 32, black],
[1046, 468, 194, 35, black],
[208, 348, 306, 28, black],
[708, 294, 335, 24, black],
[22, 487, 170, 26, black]
]
for block in level:
block = Block(block[0], block[1], block[2], block[3], block[4])
self.object_list.add(block)
class Camera(object):
def __init__(self, camera_function, width, height):
self.camera_function = camera_function
self.state = Rect(0, 0, width, height)
def apply(self, target):
return target.rect.move(self.state.topleft)
def update(self, target):
self.state = self.camera_function(self.state, target.rect)
###########################################################################
# TEXT AND UI FUNCTIONS #
###########################################################################
def set_message(text):
global message, previous_message
message = font.render(text, True, black, white)
previous_message = message
def text_objects(text, color, size):
if size == 'small':
textSurface = small.render(text, True, color)
if size == 'medium':
textSurface = medium.render(text, True, color)
if size == 'large':
textSurface = large.render(text, True, color)
return textSurface, textSurface.get_rect()
def display_message(text, color, y_displacement=0, size='small'):
textSurface, textRectangle = text_objects(text, color, size)
textRectangle.center = (screen_width / 2), (screen_height / 2) + y_displacement
screen.blit(textSurface, textRectangle)
def health_bar(player_health):
if player_health > 85:
health_color = green
elif player_health > 70:
health_color = green_yellow
elif player_health > 55:
health_color = yellow
elif player_health > 40:
health_color = orange
elif player_health > 25:
health_color = orange_red
else:
health_color = red
if player_health < 0:
player_health = 0
pygame.draw.rect(screen, health_color, (50, screen_height / 20, player_health, 25))
###########################################################################
# INITIALISATION, SCREEN PROPERTIES, FPS #
###########################################################################
# Initialise pygame module
pygame.init()
# Initialise pygame font
pygame.font.init()
# Defining the screen size
screen_size = screen_width, screen_height = 800, 600
# Setting the display and getting the Surface object
screen = pygame.display.set_mode(screen_size)
# Getting the Clock object
clock = pygame.time.Clock()
# Setting a title to the window
pygame.display.set_caption("TODO make title")
# Defining variable for FPS
fps_limit = 60
# Clear the screen
screen.fill(white)
# Setting the FPS at which the game will run
clock.tick(fps_limit)
###########################################################################
# MAIN LOOP, PAUSE AND DEATH FUNCTIONS #
###########################################################################
def death():
death = True
while death:
display_message("YOU DIED", red, size='large')
pygame.display.update()
time.sleep(1)
death = False
over = True
game_exit = True
def pause():
paused = True
display_message("Paused", black)
pygame.display.update()
while paused:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_p:
paused = False
elif event.key == pygame.K_q:
pygame.quit()
quit()
def game_intro():
intro = True
while intro:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_RETURN:
run=True
intro=False
if event.key == pygame.K_ESCAPE:
pygame.quit()
quit()
screen.fill(light_blue)
display_message("Physics Engine v0.1", black, - screen_height / 5, 'large' )
display_message("pre-alpha stage", grey, - screen_height / 10, 'small')
display_message("Press ENTER to start or ESCAPE to close", black, screen_height / 8, 'small')
pygame.display.update()
def main_loop():
# Group all the currently active objects
active_object_list = pygame.sprite.Group()
# Set variable player to the Player() class
player = Player()
# Set variable enemy to the Enemy() class
enemy = Enemy()
# Add player to the active object list
active_object_list.add(player, enemy)
# Make a list for the levels and append Level_01 to that list with player as the handler (being the character in focus)
level_list = []
level_list.append(Level_01(player))
current_level_number = 0
current_level = level_list[current_level_number]
# Set the starting co-ordinates
player.set_level(current_level)
enemy.set_level(current_level)
# run = True
over = False
game_exit = False
while not game_exit:
if over == True:
while over:
for event in pygame.event.get():
if event.type == pygame.QUIT:
game_exit = True
over = False
if event.type == pygame.KEYDOWN:
if event.key == K_RETURN:
main_loop()
if event.key == K_ESCAPE:
pygame.quit()
quit()
screen.fill(light_blue)
display_message("Do you want to start over?", black, -screen_height / 8, size='large')
display_message("Press RETURN to start over or ESCAPE to quit", black, screen_height / 8)
pygame.display.update()
current_events = pygame.event.get()
if current_events:
for event in current_events:
if event.type == pygame.QUIT:
pygame.quit()
quit()
run = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_p:
pause()
if event.key == pygame.K_k:
player.health -= 5
# Update functions
player.update(current_level.object_list, event)
enemy.update(current_level.object_list, event)
current_level.update()
else:
player.update(current_level.object_list, None)
enemy.update(current_level.object_list, None)
current_level.update()
# Logic testing
current_level.scroll()
if player.health <= 0:
player.health = 0
over = True
death()
if player.travel_distance_y > 900:
player.health = 0
over = True
death()
# Draw everything
current_level.draw(screen)
active_object_list.draw(screen)
health_bar(player.health)
# Delay fps
clock.tick(fps_limit)
# Update screen
pygame.display.update()
game_intro()
main_loop()
The viewbox located in the Level class works in a way that checks if the player is hitting the box, if it is, the world is shifted around the player instead of the player moving in it.
Scroll function
def shift_world(self, shift_x, shift_y):
self.world_shift_x += shift_x
self.world_shift_y += shift_y
for each_object in self.object_list:
each_object.rect.x += shift_x
each_object.rect.y += shift_y
def scroll(self):
if self.player_object.rect.x <= self.left_viewbox:
view_difference = self.left_viewbox - self.player_object.rect.x
self.player_object.rect.x = self.left_viewbox
self.shift_world(view_difference, 0)
if self.player_object.rect.x >= self.right_viewbox:
view_difference = self.right_viewbox - self.player_object.rect.x
self.player_object.rect.x = self.right_viewbox
self.shift_world(view_difference, 0)
if self.player_object.rect.y <= self.up_viewbox:
view_difference = self.up_viewbox - self.player_object.rect.y
self.player_object.rect.y = self.up_viewbox
self.shift_world(0, view_difference)
if self.player_object.rect.y >= self.down_viewbox:
view_difference = self.down_viewbox - self.player_object.rect.y
self.player_object.rect.y = self.down_viewbox
self.shift_world(0, view_difference)
A thing to note is that Level and Level_01 takes "player_object" as an input, which I think is called when player.update() and enemy.update() are called in the main loop.
Main loop
if current_events:
for event in current_events:
if event.type == pygame.QUIT:
pygame.quit()
quit()
run = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_p:
pause()
if event.key == pygame.K_k:
player.health -= 5
# Update functions
player.update(current_level.object_list, event)
enemy.update(current_level.object_list, event)
current_level.update()
else:
player.update(current_level.object_list, None)
enemy.update(current_level.object_list, None)
current_level.update()
So despite the fact that player is used as a handler for the level in line 477:
level_list.append(Level_01(player))
I think the enemy is influenced by the viewbox because he is also treated as the "player_object" in the scrolling function.
If anyone can give me a few tips on what I'm doing wrong would be very helpful, thanks.
The problem is in your scroll, or rather your shift_world function. You shift every object in self.object_list. For Level01, this list only contains the block objects. In scroll, you then shift every block and the player, but not the enemy. This means the enemy sprite stays at its place and is not shifted with the world as it should be. It therefore appears to move, because its position relative to the world changes. In truth, it stays blitted at the same position on the canvas as it was.
When the player jumps, the enemy ends up in the air once the world has shifted down, and then gravity pulls him back to the platform. When the player moves right, the enemy seems to follow because the world shifts left and the enemy doesn't shift with it.
Add the enemy to your object_list and it should work as expected.