How do I easily change the functionality of my code? - python

I want to make my game "go back" to the main menu and I was wondering If I can use the gamewindow function "inside" its own so that it would create a "reset". Basically, If my sprite were to collide and it says "game over" I would like to press the "back" button and If I were to press play again it would show a "reseted" game where the "timer", the "asteroid", the "ship", goes back to the beginning as If I were playing a new game again.
I was also wondering if any of the errors given to me mean anything to my problem now??
The code/game is mostly working. It just doesn't have that "reset" purpose.
Here's the errors:
"C:\Users\Myke Sustento\AppData\Local\Programs\Python\Python38-32\python.exe" "B:/PROGRAMMING RELATED/PYTHON PROJECTS/FINAL.py"
B:/PROGRAMMING RELATED/PYTHON PROJECTS/FINAL.py:261: SyntaxWarning: "is" with a literal. Did you mean "=="?
if bullet_state is "fire":
B:/PROGRAMMING RELATED/PYTHON PROJECTS/FINAL.py:322: SyntaxWarning: "is" with a literal. Did you mean "=="?
if bullet_state is "ready":
pygame 1.9.6
Hello from the pygame community. https://www.pygame.org/contribute.html
B:/PROGRAMMING RELATED/PYTHON PROJECTS/FINAL.py:171: DeprecationWarning: an integer is required (got type float). Implicit conversion to integers using __int__ is deprecated, and may be removed in a future version of Python.
display.blit(ammoboximg,(x,y))
Traceback (most recent call last):
File "B:/PROGRAMMING RELATED/PYTHON PROJECTS/FINAL.py", line 374, in <module>
gamewindow()
File "B:/PROGRAMMING RELATED/PYTHON PROJECTS/FINAL.py", line 315, in gamewindow
gamewindow()
File "B:/PROGRAMMING RELATED/PYTHON PROJECTS/FINAL.py", line 315, in gamewindow
gamewindow()
File "B:/PROGRAMMING RELATED/PYTHON PROJECTS/FINAL.py", line 315, in gamewindow
gamewindow()
File "B:/PROGRAMMING RELATED/PYTHON PROJECTS/FINAL.py", line 330, in gamewindow
keys = pygame.key.get_pressed()
pygame.error: video system not initialized
Process finished with exit code 1
Here's the whole code:
# initialization of pygame
import pygame
import random
import math
pygame.init()
# creating the display
display = pygame.display.set_mode((500, 500))
# title & icon
spaceship = pygame.image.load("Space Blitz Sprites/spaceship.png")
pygame.display.set_icon(spaceship)
pygame.display.set_caption("SpaceBlitz")
# main menu sprites
spaceblitz = pygame.image.load("Space Blitz Sprites/spaceblitz.png")
play = pygame.image.load("Space Blitz Sprites/play.png")
howtoplay = pygame.image.load("Space Blitz Sprites/howtoplay.png")
about = pygame.image.load("Space Blitz Sprites/about.png")
quit = pygame.image.load("Space Blitz Sprites/quit.png")
# inside main menu
instruction = pygame.image.load("Space Blitz Sprites/instruction.png")
back = pygame.image.load("Space Blitz Sprites/back.png")
aboutdev = pygame.image.load("Space Blitz Sprites/aboutdev.png")
# main menu music
music = pygame.mixer.music.load("Space Blitz Sprites/mountaintrails.mp3")
# PlayerSpriteMovement
playerimg = pygame.image.load("Space Blitz Sprites/spaceship.png")
playerX = 250
playerY = 400
velocity = 3
clock = pygame.time.Clock()
# Bullet
bulletimg = pygame.image.load("Space Blitz Sprites/bullet.png")
bulletX = 0
bulletY = playerY
bulletx_change = 0
bulletY_change = 8
bullet_state = "ready"
bullet_ammo = 5
bulletfont = pygame.font.Font('freesansbold.ttf', 16)
# Ammo Box
ammoboximg = pygame.image.load('Space Blitz Sprites/ammo.png')
ammoboxX = random.randint(0,468)
ammoboxY = random.randint(-1000,-800)
ammoboxY_change = -1.5
# Asteroid
asteroidimg = []
asteroidX = []
asteroidY = []
asteroidX_change = []
asteroidY_change = []
no_of_enemies = 40
def mainmenu():
global menuselect
global spaceblitz
menu = True
pygame.mixer.music.play(50)
pygame.mixer.music.set_volume(0.2)
while menu:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
if event.type == pygame.MOUSEBUTTONDOWN:
if event.button == 1:
pos = pygame.mouse.get_pos()
if start.collidepoint(pos):
menu = False
menuselect = 1
pygame.mixer.music.stop()
if controls.collidepoint(pos):
menu = False
menuselect = 2
pygame.mixer.music.stop()
if developer.collidepoint(pos):
menu = False
menuselect = 3
pygame.mixer.music.stop()
if exit.collidepoint(pos):
menu = False
menuselect = 4
display.fill((0, 0, 0))
display.blit(spaceblitz, (170,150))
start = display.blit(play, (170,250))
controls = display.blit(howtoplay, (170,300))
developer = display.blit(about, (170,350))
exit = display.blit(quit, (170,400))
pygame.display.flip()
pygame.display.update()
def controls():
global menuselect
global menu
controls = True
while controls:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
if event.type == pygame.MOUSEBUTTONDOWN:
if event.button == 1:
pos = pygame.mouse.get_pos()
if balik.collidepoint(pos):
controls = False
menu = True
menuselect = 0
balik = display.blit(back, (0,450))
display.blit(instruction, (0,0))
pygame.display.flip()
pygame.display.update()
display.fill((0, 0, 0))
def developers():
global menuselect
global menu
dev = True
while dev:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
if event.type == pygame.MOUSEBUTTONDOWN:
if event.button == 1:
pos = pygame.mouse.get_pos()
if balik.collidepoint(pos):
dev = False
menu = True
menuselect = 0
balik = display.blit(back, (0, 450))
display.blit(aboutdev, (0, 0))
pygame.display.flip()
pygame.display.update()
display.fill((0, 0, 0))
# Asteroid
for r in range(no_of_enemies):
asteroidimg.append(pygame.image.load("Space Blitz Sprites/asteroid.png"))
asteroidX.append(random.randint(-100, 500))
asteroidY.append(random.randint(-300, -30))
asteroidX_change.append(0)
asteroidY_change.append(2)
# Game Over Text
overfont = pygame.font.Font('freesansbold.ttf',32)
# Sprite image
def player(x, y):
display.blit(playerimg, (x, y))
def fire_bullet(x, y):
global bullet_state
if bullet_ammo > -1:
bullet_state = "fire"
display.blit(bulletimg, (x + 9, y + -7))
else:
bullet_state = "ready"
def ammobox(x,y):
display.blit(ammoboximg,(x,y))
def AmBoxCollision(ammoboxX,ammoboxY,playerX,playerY):
ammoboxdistance = math.sqrt((math.pow(ammoboxX - playerX, 2)) + (math.pow(ammoboxY - playerY, 2)))
if ammoboxdistance < 27:
return True
else:
return False
def ammo():
global bullet_ammo
global ammo_decrease
ammo_decrease = 1
bullet_ammo -= ammo_decrease
def asteroid(x, y, r):
display.blit(asteroidimg[r], (x, y))
def BulCollision(asteroidX, asteroidY, bulletX, bulletY):
buldistance = math.sqrt((math.pow(bulletX - asteroidX, 2)) + (math.pow(bulletY - asteroidY, 2)))
if buldistance < 27:
return True
else:
return False
def PlayCollision(asteroidX, asteroidY, playerX, playerY):
playdistance = math.sqrt((math.pow(playerX - asteroidX, 2)) + (math.pow(playerY - asteroidY, 2)))
if playdistance < 27:
return True
else:
return False
def gameover_screen():
overtext = overfont.render("GAME OVER",True,(255,255,255))
display.blit(overtext, (150,250))
# mainloop
def gamewindow():
global menuselect
global playerX
global playerY
global velocity
global clock
global bulletX
global bulletY
global bulletY_change
global bullet_state
global asteroidX
global asteroidY
global asteroidY_change
global no_of_enemies
global ammoboxX
global ammoboxY
global ammoboxY_change
global dev
global menu
global bullet_ammo
global ammo_decrease
global passed_time
font = pygame.font.Font(None, 54)
font_color = pygame.Color('white')
start_time = pygame.time.get_ticks()
run_timer = True
running = True
while running:
clock.tick(60)
display.fill((0, 0, 0))
AmmoBoxCollision = AmBoxCollision(ammoboxX,ammoboxY,playerX,playerY)
if AmmoBoxCollision:
ammoboxY = random.randint(-1000, -800)
ammoboxX = random.randint(0, 468)
if bullet_ammo <= 4 and bullet_ammo > -1:
bullet_ammo += 1
if bullet_ammo == -1:
bullet_ammo +=2
if bullet_ammo == -1 or bullet_ammo == 0:
bullet_text = bulletfont.render("Ammo:%d" % bullet_ammo, True, (0, 0, 0))
display.blit(bullet_text, (10, 468))
noammo = bulletfont.render("NO AMMO",True,(255,255,255))
display.blit(noammo,(10,468))
else:
bullet_text = bulletfont.render("Ammo:%d" % bullet_ammo, True, (255, 255, 255))
display.blit(bullet_text, (10, 468))
if bullet_state is "fire":
fire_bullet(bulletX, bulletY)
bulletY -= bulletY_change
if bulletY <= 0:
bulletY = playerY
bullet_state = "ready"
for r in range(no_of_enemies):
asteroid(asteroidX[r], asteroidY[r], r)
asteroidY[r] += asteroidY_change[r]
if asteroidY[r] >= 500:
asteroidY[r] = random.randint(-300, -30)
asteroidX[r] = random.randint(-100, 500)
Bulletcollision = BulCollision(asteroidX[r], asteroidY[r], bulletX, bulletY)
if Bulletcollision:
bulletY = playerY
bullet_state = "ready"
asteroidX[r] = random.randint(-100, 500)
asteroidY[r] = random.randint(-300, -30)
# Game over
PlayerCollision = PlayCollision(asteroidX[r], asteroidY[r], playerX, playerY)
if PlayerCollision:
for j in range(no_of_enemies):
asteroidY_change[j] = 0
asteroidY[j] = random.randint(-300, -30)
asteroidX[j] = random.randint(-100, 500)
asteroidY_change[j] = 2
velocity = 0
bulletY_change = 0
bulletY = 600
ammoboxY_change = 0
run_timer = False
gameover_screen()
playerX = 250
playerY = 400
velocity = 3
# movement
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
if event.type == pygame.MOUSEBUTTONDOWN:
if event.button == 1:
pos = pygame.mouse.get_pos()
if balik.collidepoint(pos):
running = False
menu = True
menuselect = 0
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
if bullet_ammo <= 5 and bullet_ammo > -1:
if bullet_state is "ready":
bulletX = playerX
bulletY = playerY
fire_bullet(bulletX, bulletY)
ammo()
# player movement
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT]:
playerX -= velocity
if keys[pygame.K_RIGHT]:
playerX += velocity
if keys[pygame.K_DOWN]:
playerY += velocity
if keys[pygame.K_UP]:
playerY -= velocity
# Border
if playerX <= 0:
playerX = 0
elif playerX >= 468:
playerX = 468
if playerY <= 0:
playerY = 0
elif playerY >= 468:
playerY = 468
if ammoboxY > 500:
ammoboxY = random.randint(-1000,-800)
ammoboxX = random.randint(0,468)
ammobox(ammoboxX,ammoboxY)
ammoboxY -= ammoboxY_change
if run_timer:
current_time = pygame.time.get_ticks()
passed_time = current_time - start_time
text = font.render(str(passed_time / 1000), True, font_color)
display.blit(text, (50, 50))
balik = display.blit(back, (350, 450))
player(playerX, playerY)
pygame.display.update()
mainmenu()
while True:
if menuselect == 0:
mainmenu()
elif menuselect == 1:
gamewindow()
elif menuselect == 2:
controls()
elif menuselect == 3:
developers()
elif menuselect == 4:
pygame.quit()
Here's where I would like to put my reset button (in either the PlayerCollision or balik.collidepoint(pos))
if PlayerCollision:
for j in range(no_of_enemies):
asteroidY_change[j] = 0
asteroidY[j] = random.randint(-300, -30)
asteroidX[j] = random.randint(-100, 500)
asteroidY_change[j] = 2
velocity = 0
bulletY_change = 0
bulletY = 600
ammoboxY_change = 0
run_timer = False
gameover_screen()
playerX = 250
playerY = 400
velocity = 3
# movement
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
if event.type == pygame.MOUSEBUTTONDOWN:
if event.button == 1:
pos = pygame.mouse.get_pos()
if balik.collidepoint(pos):
running = False
menu = True
menuselect = 0
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
if bullet_ammo <= 5 and bullet_ammo > -1:
if bullet_state is "ready":
bulletX = playerX
bulletY = playerY
fire_bullet(bulletX, bulletY)
ammo()
I'm sorry if I'm asking a lot of question. This is my first ever code in python (or programming in general) so I don't really know how most of the stuff works. Plus, the code is a mixture of my code and my group-mate's code so half of the code in this program is unfamiliar to me. Tips for future coding practice is highly appreciated but I just want to finish my game right now so I would like to finish the current (and last) problem that I encountered.

As you say, you've just started and are learning. Very good! You've just run into a problem that you can learn a lot from: adding new features. Generally, this question would be better suited on the code review stack exchange but I think it's also suited here.
So what's the problem exactly? You say you want to have your game "go back" to the main menu. You suggest an implementation that (I find) difficult to follow and follow up with a bunch of code that I'm sure that works but is difficult (for me) to read. I honestly find it very impressive how much you've been able to write, especially since it's your first time coding!
In my opinion, your real problem isn't how to "go back", rather, it is how to make your code fixeable/updateable. A very good lesson to learn. There's a couple reasons why your current code is difficult to update:
All your code is in one file, making it hard to navigate
You have global variables, which can be hard to track
You use many hard coded values which are hard to change/keep track of
Why is this a problem? If you want to change something you cannot find where to change what because you cannot find anything because there's so much code everywhere. Then, once you find it, you cannot really know what everything is because of the global variables. Lastly, the hard coded values make it impossible to know if you've fixed everything, or forgot a number causing a bug (for instance, you want to make the screen twice as big, change all the picture sizes, but forget to update the speed).
So how do you change this?
Well, first try splitting up your code so it's easier to find things. I like to put things in folders like this:
my_project/
main.py
.gitignore
core/
game_mechanics/
player.py
bullet.py
asteroid.py
game_setup/
main_menu.py
run_game.py
config/
config.yaml
utils/
read_config.py
tests/
test1.py
test2.py
This may seem daunting, so let's run past what everything is:
Main.py: your main file which you run. It looks something like this:
from example_file import example_function
def main(config):
while True:
settings = main_menu()
play_game(settings)
if __name__ == '__main__':
config = load_config()
main(config)
When you run main.py it will load the config, and then run the main components. This file should be very short so it's easy to understand what is happening. Here for instance, you get the settings from running main_menu() and then play the game using those settings. When the game quits, the main menu is shown again.
Next is the .gitignore file that you'll need if you use git. If you don't know what this is/does you should google it, it will make your life much easier.
In your core folder you have all the main functions specific to the game. This is where you put most of your code. It is important to split it up into logical files so you can easily find what goes where.
In your utils folder you have utility functions you'll want to share between projects.
In your config folder you can store the settings. This should contain all the "number or letter values" you use, this way you don't have to go through your code manually changing number everywhere (and maybe forgetting one), but instead pass it along.
This solves your problem of having to find where what is. Everything is ordered nicely and you can easily find it. If you want to change large functionalities (like adding a new menu) you can do this in the main file which is easy to do.
The next problem is the use of global variables. You have quite a number of them and this makes it hard to track which value is what. It may be clear to you know, but imagine when you come back in a year and values change 'randomly', how do you find where what changes?
Instead, try to pass things to your functions like this:
def square_n(n):
return n * n
a = 5
a_squared = square_n(a)
This makes it much easier to read what happens where.
Lastly, as mentioned before the hard coded values make everything very difficult to update. Take the example with doubling the screen size. You make everything twice as large, but forget to double one speed component (because you overlooked it). This could be a "weird bug" that takes some time to fix. Instead try to save all these values in your config, and pass them along as shown above. This would look something like this:
def print_hello_world_n_times(n):
for i in range(n):
print("hello world")
config = load_config()
# config = {'a': 5, 'b': 10}
a = config['a']
print_hello_world_n_times(a)
I'm sorry I won't be giving you a copy-paste solution to your problem. I think it's much more useful for you to restructure your code yourself and then see how much easier it is to change its functionality.
Success!

Related

How do I make sprites in pygame not move through eachother?

I'm making a game in pygame and I'm having some trouble with object collisions.
import pygame, sys
from pygame.math import Vector2
pygame.init()
screen = pygame.display.set_mode((500,500))
clock = pygame.time.Clock()
#Environment Variables
gravity = -1
jumpForce = 20
moveSpeed = 10
#Game Objects
playerPos = Vector2(230,230)
playerVelo = Vector2(0,0)
player = pygame.Rect(playerPos.x,playerPos.y, 20, 20)
boxPos = Vector2(350,480)
box = pygame.Rect(boxPos.x, boxPos.y, 20,20)
def Clamp(var, minClamp, maxClamp):
if minClamp > maxClamp:
raise Exception("minClamp must be less than maxClamp")
if var < minClamp:
var = minClamp
if var > maxClamp:
var = maxClamp
return var
def Draw():
global player,box
screen.fill((255,255,25))
player = pygame.Rect(playerPos.x,playerPos.y, 20, 20)
pygame.draw.rect(screen,(0,100,255),player)
box = pygame.Rect(boxPos.x, boxPos.y, 20,20)
pygame.draw.rect(screen,(10,200,20),box)
def PlayerVelocity():
global playerPos,playerVelo,player,box,boxPos
if player.colliderect(box):
playerPos = Vector2(boxPos.x,boxPos.y-20)
print("balls")
if playerPos.y < 499:
playerVelo.y += gravity
#if not pygame.Rect(playerPos.x+playerVelo.x,playerPos.y+playerVelo.y,20,20).colliderect(box):
playerPos -= playerVelo
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE or event.key == pygame.K_UP:
playerVelo.y = jumpForce
print(playerVelo)
keys = pygame.key.get_pressed()
if keys[pygame.K_a] or keys[pygame.K_LEFT]:
playerVelo.x = 1*moveSpeed
elif keys[pygame.K_d] or keys[pygame.K_RIGHT]:
playerVelo.x = -1*moveSpeed
else:
playerVelo.x = 0
#Draw things to the screen
Draw()
PlayerVelocity()
playerPos.x = Clamp(playerPos.x, 0, 480)
playerPos.y = Clamp(playerPos.y,0,480)
pygame.display.update()
clock.tick(30)
I've tried looking this up and the other solutions either don't work with the movement system I've implemented or I just plain don't understand them.
It is not enough to change the position of the player when the player hits the obstacle. You need to constrain the player's box (pygame.Rect object) with the obstacle rectangle and update the player's position. Clamp and calculate the position of the player before checking for collision:
def PlayerVelocity():
global playerPos,playerVelo,player,box,boxPos
prev_y = playerPos.y
if playerPos.y < 499:
playerVelo.y += gravity
playerPos -= playerVelo
playerPos.x = Clamp(playerPos.x, 0, 480)
playerPos.y = Clamp(playerPos.y, 0, 480)
player = pygame.Rect(playerPos.x, playerPos.y, 20, 20)
box = pygame.Rect(boxPos.x, boxPos.y, 20,20)
if player.colliderect(box):
if prev_y+20 <= box.top:
player.bottom = box.top
elif player.left < box.left:
player.right = box.left
else:
player.left = box.right
playerPos = Vector2(player.topleft)
print("balls")

Timing the blit of an enemy list in Pygame

Outside of my game loop, I have created a function that creates a list of 200 enemies with random coordinates. These enemies are suppose to start at the top of the screen and then drop down at random speeds. Inside the loop, I use a "for" loop to blit the enemies on screen. It works, but all 200 hundred are spawned and fall at the same time, albeit, at different speeds. So I know I need a timer and herein lies the problem; nothing I do works. Ive tried clock.tick(), pygame.delay(), import time and do the time.time() method. Everything either strobes or the system just crashes. What's causing the problem?
[Code]
import pygame
import sys
import random
import time
pygame.init()
#MAIN GAME
game_screen = pygame.display.set_mode((600, 600))
pygame.display.set_caption("Beer Goggles")
bg = pygame.image.load("bg.png")
bg_image = pygame.transform.scale(bg, (600, 600))
class Object:
def __init__(self, image_path, width, height, x, y):
self.image_path = image_path
self.width = width
self.height = height
self.x = x
self.y = y
player = pygame.image.load(image_path)
self.player_main = pygame.transform.scale(player, (width,height))
def draw(self, background):
background.blit(self.player_main, (self.x, self.y))
#enemies
def enemy():
enemy_list = []
for e in range(200):
x_cor = random.randint(25, 361)
e = Object("enemy.png", 70, 70, x_cor, 25)
enemy_list.append(e)
return enemy_list
#Main Objects
player1 = Object("crate.png", 70, 70, 25, 500)
list1 = enemy()
#ladies
fat_lady = Object("fat_lady.png", 300, 300, 360, 180)
# Main Loop
direction = 0
game_on = True
while game_on:
clock = pygame.time.Clock()
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
game_on = False
pygame.quit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_RIGHT:
direction = 1
elif event.key == pygame.K_LEFT:
direction = -1
elif event.type == pygame.KEYUP:
if event.key == pygame.K_RIGHT or event.key == pygame.K_LEFT:
direction = 0
game_screen.fill((0,0,0))
game_screen.blit(bg_image, (0,0))
#title.draw(game_screen)
player1.draw(game_screen)
fat_lady.draw(game_screen)
#move
if direction > 0:
player1.x = player1.x + 10
elif direction < 0:
player1.x = player1.x - 10
#boundaries
if player1.x <= 25:
player1.x = 25
elif player1.x >= 360:
player1.x = 360
#for enemy in list1:
for enemy in list1:
a = random.randint(1, 30)
enemy.draw(game_screen)
enemy.y += a
#collisions
#scoring
pygame.display.update()
quit()
In the code where you create the enemy list you could add a drop start time. Just like you create a random x co-ordinate you could create a time to start dropping it. Then later when you start changing the y position for them (dropping them), you would not start it dropping until after that time had passed.
By the way You have a method enemy() and later you have a loop iterator enemy which will override hide the method by that name. After that point if you tried to call the method enemy() it would fail and you would access the loop iterator instead. It does not affect your code here because you do not try to access the method after creating the loop iterator variable, but it is not a great idea and could cause problems if you later changed the code and did try to access that method. You should be careful about name choices.

How do i add lives into this python 3.0 game

I am quite new to python just trying to learn it. I've followed a tutorial on how to make this game and added my own stuff but I cant seem to add lives. I've tried all I know (not a lot). Anyway, all the tutorials I have watched have not worked either and I have been pulling my hair out over it for like 2 days now, so if anyone can help it would be very appreciated.
import math
import random
import pygame
from pygame import mixer
# Intialize the pygame
pygame.init( )
# create the screen
screen = pygame.display.set_mode((800, 600))
# Background
background = pygame.image.load('editor.jpg')
opensound = mixer.Sound("ftw.wav")
opensound.play( )
# Sound
mixer.music.load("bg noise.wav")
mixer.music.play(-1)
# Caption and Icon
pygame.display.set_caption("Virus Invader")
icon = pygame.image.load('virus.png')
pygame.display.set_icon(icon)
# Player
playerImg = pygame.image.load('people.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('virus.png'))
enemyX.append(random.randint(0, 736))
enemyY.append(random.randint(50, 150))
enemyX_change.append(1)
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('ligature.png')
bulletX = 0
bulletY = 480
bulletX_change = 0
bulletY_change = 2
bullet_state = "ready"
# Score
score_value = 0
font = pygame.font.Font('freesansbold.ttf', 32)
textX = 10
testY = 10
# Game Over
over_font = pygame.font.Font('freesansbold.ttf', 64)
def Game_start_text():
over_text = over_font.render("Let the games begin!", True, (64, 64, 64))
screen.blit(over_text, (200, 250))
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 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
# 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 if its right or left
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
playerX_change = -2
if event.key == pygame.K_RIGHT:
playerX_change = 2
if event.key == pygame.K_SPACE:
if bullet_state is "ready":
bulletSound = mixer.Sound("stab.wav")
bulletSound.play( )
# Get the current x cordinate of the charctar
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):
# 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] = 1
enemyY[i] += enemyY_change[i]
elif enemyX[i] >= 736:
enemyX_change[i] = -1
enemyY[i] += enemyY_change[i]
# Collision
collision = isCollision(enemyX[i], enemyY[i], bulletX, bulletY)
if collision:
explosionSound = mixer.Sound("street fighter die.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(textX, testY)
pygame.display.update( )
The reason adding this to your code is so difficult is because there's a whole bunch of extra code that's in the way.
When this happens, take a step back, and try to write a skeleton to do just what you need. When working on a huge system, say tracking down a complex bug, normally you would comment out sections of the code to pair the problem-space back to something manageable. Your code is pretty small, so maybe you can just ignore a lot of it.
In any event, take a backup of your code, then start adding the changes bit by bit, testing as you go.
First add a life-counter:
# Player
playerLives = 3 # <<-- HERE
playerImg = pygame.image.load('people.png')
playerX = 370
playerY = 480
playerX_change = 0
Then some way to test life-loss:
# if keystroke is pressed check if its right or left
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
playerX_change = -2
elif event.key == pygame.K_RIGHT:
playerX_change = 2
elif event.key == pygame.K_d: # TEST CODE - Die on 'd' <<-- HERE
print( "Player Dies" )
playerLives -= 1
Now test this? Did it print "Player Dies" when you press d?
So... what should happen when the lives is zero? Maybe the player can't move any more:
# Has the player run out of lives?
if ( playerLives <= 0 ):
game_over_text()
else:
# Player still alive, allow controls, draw player
playerX += playerX_change
if playerX <= 0:
playerX = 0
elif playerX >= 736:
playerX = 736
player(playerX, playerY)
Add these next changes in, test them. Does pressing d three times print "Player Dies" every time, and result in the game_over_text() function being called?
Then change the show_score() function to also draw the lives left:
def show_score(x, y):
score = font.render("Score : " + str(score_value), True, (255, 255, 255))
screen.blit(score, (x, y))
# Write the Lives-left to the right of the score
lives = font.render("Lives : " + str(playerLives), True, (255, 255, 255))
screen.blit(lives, (x+200, y))
Test that. Does the on-screen score work? No? Make some small changes, test again, keep tweaking, keep fixing. If it all goes to hell-in-a-handcart you only need small changes to undo it.
Now that the losing-lives mechanism is working, find where it should actually take away lives, and add the changes in:
# Game Over
if enemyY[i] > 440:
for j in range(num_of_enemies):
enemyY[j] = 2000
playerLives -= 1 # <<-- lose a life
#game_over_text( )
reset_enemy_positions() # <<-- move enemies back to top, TODO!
break
Of course if you leave your enemies below line 440, the lose-a-life condition is still true. Thus the player will continue to lose many lives per second, every frame update. The enemies need to move back to start-position (or some suchlike).
Anyway I hope this gives you a nudge in the right direction. Maybe it would help you to try to write something yourself from scratch. Even just opening a window. Then adding key handling. Then drawing something... Incrementally add to your knowledge, I think you'll learn much faster this way. There's a reason every programming book starts with "Hello World".

Pyganim Help in Sidescroller Game

I know how to use Pyganim, it's fairly straightforward. But my problem lies with how I build my game, it starts pyganim's animation 60 times a second, therefore it never animates at all (according to the human eye). I need help in terms of how do I tell if an animation is currently playing or not, then call the play or not afterwards?
My code:
class gameStart(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.background = pygame.image.load("BG" + str(level) + ".png")
self.player = pygame.image.load("2_scaled.png")
self.icon = pygame.image.load("1_scaled.png")
self.background_S = pygame.transform.scale(self.background, (width, height)) #Scale the background to match the screen resolution
screen.blit(self.background_S, (0,0))
screen.blit(self.player, (0, height/2))
screen.blit(self.icon, (0,0))
self.position = self.player.get_rect()
self.health = 100
#Setup the players Idle, Attack, Attack 2 and Death Animations
self.PlayerIdleAnim = pyganim.PygAnimation([('2_scaled.png', 1), ('3_scaled.png', 1), ('4_scaled.png', 1), ('5_scaled.png', 1), ('6_scaled.png', 1)])
updateDisplay()
def move(self):
global rightPressed
global leftPressed
global facing
global frame
leftPressed = False
rightPressed = False
if keyPressed(K_a):
leftPressed = True
elif keyPressed(K_d):
rightPressed = True
elif not keyPressed(K_a):
leftPressed = False
elif not keyPressed(K_d):
rightPressed = False
if rightPressed and (self.position.x < width - 200):
self.position.x += moveSpeed
screen.blit(self.background_S, (0,0))
self.PlayerIdleAnim.stop()
screen.blit(self.player, (self.position.x, height/2))
if not facing:
self.player = pygame.transform.flip(self.player, True, False)
facing = True
updateDisplay()
elif leftPressed and (self.position.x > 20):
self.position.x += -moveSpeed
screen.blit(self.background_S, (0,0))
self.PlayerIdleAnim.stop()
if facing:
self.player = pygame.transform.flip(self.player, True, False)
facing = False
screen.blit(self.player, (self.position.x, height/2))
updateDisplay()
elif not leftPressed and not rightPressed:
if not facing:
self.PlayerIdleAnim.flip(True, False)
self.PlayerIdleAnim.play()
else:
self.PlayerIdleAnim.play()
"""elif rightPressed and not (self.position.x < width - 200):
rightPressed = False
elif leftPressed and not (self.position.x > 200):
leftPressed = False"""
game = gameStart()
while not gameQuit:
for event in pygame.event.get():
if event.type == QUIT:
gameQuit = True
elif event.type == KEYDOWN:
if event.key == K_ESCAPE:
gameQuit = True
game.move()
updateDisplay()
fpsClock.tick(fps)
The animation will never technically run, because it is always stuck on the first frame. But if you do want to find out if it will run if you give it time to switch frames just make a loop activated only when a key is pressed that lets the animation run. something like ...
def anim_test():
clock = pg.time.Clock()
while run == true:
pg.display.update()
clock.tick(60)

How to make a character move while key is held down

I'm trying to create a "player" - black square - which moves when you hold down WASD. I tried looking around here, on google and on youtube on how to make this work, but every solution I've tried has the same problem: instead of moving it while I hold down the key, I have to tap the key constantly to make it move in small bits. I've no clue what I'm doing wrong. Here's the code (using python 3.3 - pygame 1.9):
import pygame
from pygame.locals import *
from pygame.time import *
import sys
pygame.init()
velX = 0
velY = 0
running = True
clock = pygame.time.Clock()
def draw():
global velX
global velY
playerx = 20
playery = 20
screen = pygame.display.set_mode((700,300))
pygame.display.set_caption('something')
background = pygame.Surface(screen.get_size())
background = background.convert()
background.fill((255,255,255))
screen.blit(background, (0,0))
playerx = playerx + velX
playery = playery + velY
player_filename = 'player.png'
player = pygame.image.load(player_filename)
screen.blit(player, (playerx,playery))
pygame.display.flip()
def main():
global velX
global velY
global running
while running:
keys_down = pygame.key.get_pressed()
pygame.key.set_repeat(1, 50)
time = 50/1000
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
running=False
if keys_down[K_d]:
velX += 50*time
if keys_down[K_w]:
velY -= 50*time
if keys_down[K_s]:
velY += 50*time
if keys_down[K_a]:
velX -= 50*time
clock.tick(50)
draw()
if __name__ == '__main__':
main()
I already tried the set repeat command, but it didn't seem to do much anything. I also tried directly copying from a few solutions I found here on stackoverflow, but none of them worked. I suppose there is something else wrong in the code.
There are two problems with your code. First to your question. The reason the player never moves more than one step is that you reset the player position in every call to draw() when you do
playerx = 20
playery = 20
Instead, you should put that code above the draw()function and add
global playerx
global playery
at the top of draw(). Now, the player position is not reset every frame.
The second problem is that you create a new screen in every call to draw() when you do
screen = pygame.display.set_mode((700,300))
pygame.display.set_caption('something')
instead you should move those to lines above draw() and just use the same screen for every draw.
Also, like elyase points out, what you probably want is to set the velocities to fixed values, not increase them. Like so
velX = 0
velY = 0
if keys_down[K_d]:
velX = 10
if keys_down[K_w]:
velY = -10
if keys_down[K_s]:
velY = 10
if keys_down[K_a]:
velX = -10
This way the player will move around with a constant speed in the direction you steer it.
Hope that clear some stuff up. :)
You are resetting the position inside draw(). Also you should put the code that changes the direction, inside the event.type == pygame.KEYDOWN condition. Something like this:
if event.type == KEYDOWN:
if event.key == K_d:
velX += 50*time
elif event.key == K_w:
velY -= 50*time
...
if event.type == KEYUP:
# set velocity to 0

Categories