So basically what I've tried to code here is a game of Pong using the Python programming language and the Pygame module.
My problems are as follows:
The game sometimes gets stuck in a loop in which the AI paddle sits there while over and over again it loses
The ball jumps up and down sometimes? I have no clue as to why...
The ball just goes back and forth? I can't figure out why it isn't following along a random line like I want...
And my biggest problem, it seems that when the ball hits the top or bottom, it just disappears and the game just continues as if it was still bouncing around.
My Code
# Pong
import random, pygame, sys
from pygame.locals import *
FPS = 300
WINWID = 640
WINHEI = 480
BROWN = (102, 51, 0)
LIGHTBLUE = (0, 204, 204)
GREEN = (0, 153, 0)
PADDLECOLOR = (255, 255, 255)
BALLCOLOR = PADDLECOLOR
BACKGROUNDCOLOR = (0, 0, 0)
def main():
global FPSCLOCK, DISPLAYSURF
SPEED = 1
DIFF = 1.0 # AI paddle speed handicap
ball_speed = 1
AISIGHT = WINWID/6
FONT = "Times New Roman"
pygame.init()
DEFAULTFONT = pygame.font.SysFont(FONT, 16)
BIGGERFONT = pygame.font.SysFont(FONT, 32)
FPSCLOCK = pygame.time.Clock()
DISPLAYSURF = pygame.display.set_mode((WINWID, WINHEI))
DISPLAYSURF.fill(BACKGROUNDCOLOR)
BACKGROUND = pygame.Rect(0, 0, WINWID, WINHEI)
pygame.display.set_caption('Pong')
paddleUP, paddleDOWN = False, False
ballpos = (WINWID/2, WINHEI/2)
AIpoint, PLAYERpoint = 0, 0
score = "Player:%2f || Computer:%2f" % (AIpoint, PLAYERpoint)
paddle = WINHEI/2
AIpaddle = paddle
pygame.draw.rect(DISPLAYSURF, BACKGROUNDCOLOR, BACKGROUND)
pygame.draw.line(DISPLAYSURF, PADDLECOLOR, (9, paddle-20), (9, paddle+20), 3)
pygame.draw.line(DISPLAYSURF, PADDLECOLOR, (629, AIpaddle-20), (629, AIpaddle+20), 3)
pygame.draw.circle(DISPLAYSURF, BALLCOLOR, ballpos, 5)
slope, y_int = ballpath(None, ballpos[0], ballpos[1])
while True:
for event in pygame.event.get():
direction = None
if event.type == QUIT:
terminate()
elif event.type == KEYDOWN:
if (event.key == K_UP or event.key == K_w):
paddleUP = True
elif (event.key == K_DOWN or event.key == K_s):
paddleDOWN = True
elif event.type == KEYUP:
if (event.key == K_UP or event.key == K_w):
paddleUP = False
elif (event.key == K_DOWN or event.key == K_s):
paddleDOWN = False
# move player paddle
if paddleUP and paddle >= 20:
paddle-=SPEED
elif paddleDOWN and paddle <= 460:
paddle+=SPEED
# move AI paddle
if ballpos[0] > (AISIGHT):
if AIpaddle-20 < ballpos[1] and AIpaddle <= 460:
AIpaddle+=SPEED/DIFF
elif AIpaddle+20 > ballpos[1] and AIpaddle >= 20:
AIpaddle-=SPEED/DIFF
# move ball
x = ballpos[0] + ball_speed
y = (slope*x) + y_int
ballpos = (x, y)
# if it hits a paddle
if 9 < ballpos[0] < 11:
if paddle-20 < ballpos[1] < paddle+20:
slope, y_int = ballpath(None, ballpos[0], ballpos[1])
ball_speed*=-1
elif 629 < ballpos[0] < 631:
if AIpaddle-20 < ballpos[1] < AIpaddle+20:
slope, y_int = ballpath(None, ballpos[0], ballpos[1])
ball_speed*=-1
# if it hits the top or bottom
if WINHEI-5 > ballpos[1] or ballpos[1] < 5:
slope, y_int = ballpath(slope, ballpos[0], ballpos[1])
# if paddle misses ball
if ballpos[0] < 5:
AIpoint+=1
score = "Player:%2f || Computer:%2f" % (PLAYERpoint, AIpoint)
ballpos = (WINWID/2, WINHEI/2)
pygame.draw.rect(DISPLAYSURF, (0, 0, 0, 100), pygame.Rect(0, 0, 640, 480))
DISPLAYSURF.blit(BIGGERFONT.render("Point: Computer", 1, PADDLECOLOR), (WINWID/3, WINHEI/3))
paddle, AIpaddle = WINWID/2, WINWID/2
for i in range(5):
FPSCLOCK.tick(FPS)
elif ballpos[0] > 635 and AIpaddle-20 < ballpos[1] < AIpaddle+20:
PLAYERpoint+=1
score = "Player:%2f || Computer:%2f" % (PLAYERpoint, AIpoint)
ballpos = (WINWID/2, WINHEI/2)
pygame.draw.rect(DISPLAYSURF, (0, 0, 0, 100), pygame.Rect(0, 0, 640, 480))
DISPLAYSURF.blit(BIGGERFONT.render("Point: Player", 1, PADDLECOLOR), (WINWID/3, WINHEI/3))
for i in range(5):
FPSCLOCK.tick(FPS)
pygame.draw.rect(DISPLAYSURF, BACKGROUNDCOLOR, BACKGROUND)
pygame.draw.line(DISPLAYSURF, PADDLECOLOR, (9, paddle-20), (9, paddle+20), 3)
pygame.draw.line(DISPLAYSURF, PADDLECOLOR, (629, AIpaddle-20), (629, AIpaddle+20), 3)
pygame.draw.circle(DISPLAYSURF, BALLCOLOR, ballpos, 5)
DISPLAYSURF.blit(DEFAULTFONT.render(score, 1, PADDLECOLOR), (WINWID/3, 20))
pygame.display.update()
FPSCLOCK.tick(FPS)
def ballpath(old_slope, ball_x, ball_y):
if old_slope == None:
slope = int(random.random() * 2)
else:
slope = old_slope * -1
y_int = ball_y - (slope * ball_x)
return slope, y_int
def terminate():
pygame.quit()
sys.exit()
if __name__ == '__main__':
main()
I cleaned up your code quite a bit. It should help a bit with how to use the classes. http://pastebin.com/rZF3Gr0D
Things to note:
prints when score event happens
paddle movement using keystate vs "on events". It makes that kind of input easier.
Sprite group's let you 'draw' or check collisions in batches.
removed global keyword. Game owns most things.
Using Rect functions and properties all over the place. Such as ball.rect.center = screen.get_rect().center .
random angle for ball spawns via trig.
caps framerate. Next you would move onto time-based movement. I left that out for simplicity.
Color() lets you do many things, including Color("red"), Color("gray40") , etc...
Related
This question already has answers here:
Updating text in pygame
(1 answer)
Creating a self-updating score
(1 answer)
Closed 23 days ago.
I made a surface for the player health and drew it on the screen. Then I made an if statement checking to see if the player X position was == to the enemy X position and if it was the player health would continuously decrease. I know it was decreasing because I was having it print out the player health afterwards in the console and everything was good but the health on the screen would not change. What am I doing wrong?
I am a newbie at pygame and a beginner in python therefore my code is not written in the best way...
Sorry the code is very long but the # should show everything...
import pygame
from sys import exit
from time import sleep
pygame.init()
clock = pygame.time.Clock()
screen = pygame.display.set_mode((1200, 535))
background = pygame.image.load("background1.jpg")
background = pygame.transform.rotozoom(background, 0, 2)
# Player
player_surf = pygame.image.load("player_sprites/player_right.png").convert_alpha()
player_rect = player_surf.get_rect(bottomright = (575, 470))
player_surf = pygame.transform.rotozoom(player_surf, 0, 2.5).convert_alpha()
# Health...
health = 50
health_font = pygame.font.Font('Pixeltype.ttf', 50)
health_display = health_font.render(f"Health {health}", True, (0, 0, 0))
# Enemy #1
enemy1_surf = pygame.image.load("enemy1sprites/enemy1_right.png").convert_alpha()
enemy1_rect = enemy1_surf.get_rect(bottomleft = (1100, 462))
enemy1_surf = pygame.transform.rotozoom(enemy1_surf, 0, 2.5).convert_alpha()
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
exit()
screen.blit(background, (0, 0))
screen.blit(player_surf, player_rect)
screen.blit(enemy1_surf, enemy1_rect)
screen.blit(health_display, (550, 75))
# Player Movement
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
player_surf = pygame.image.load("player_sprites/player_left.png")
player_surf = pygame.transform.rotozoom(player_surf, 0, 2.5)
player_rect.x -= 4
if event.key == pygame.K_RIGHT:
player_surf = pygame.image.load("player_sprites/player_right.png")
player_surf = pygame.transform.rotozoom(player_surf, 0, 2.5)
player_rect.x += 4
if player_rect.x >= 1075:
player_rect.x = 1075
elif player_rect.x <= 0:
player_rect.x = 0
wave_one = True
# Enemy 1 AI
if player_rect.x != enemy1_rect.x:
if player_rect.x > enemy1_rect.x:
enemy1_surf = pygame.image.load("enemy1sprites/enemy1_right.png")
enemy1_surf = pygame.transform.rotozoom(enemy1_surf, 0, 2.5)
enemy1_rect.x += 1
elif player_rect.x < enemy1_rect.x:
enemy1_surf = pygame.image.load("enemy1sprites/enemy1_left.png")
enemy1_surf = pygame.transform.rotozoom(enemy1_surf, 0, 2.5)
enemy1_rect.x -= 1
# Collision with enemy
if player_rect.x == enemy1_rect.x:
health -= 0.005
print(health)
pygame.display.update()
clock.tick(60)
I expected it to continuously update the health_display but It did not.
Have you tried updating / re-rendering the text on screen? From your code, it appears that the health is only printed when updated, not shown in the game.
Am trying to show the 'You loose like the looser you are looser' text after the small moving rectangle hits the bounderies...
but instead, the rectangle is moving past the bounderies and the 'You loose' text only shows up after i hit a random button...
the code is below
import pygame
import time
#initialize
pygame.init()
#colors
red = (255, 0, 0)
green = (0, 255, 0)
blue = (0, 0, 255)
cyan = (0, 255, 255)
black = (0, 0, 0)
grey = (92, 92, 92)
whiteish = (192, 192, 192)
#dimensions
width = 800
height = 600
#display surface
window = pygame.display.set_mode((width, height))
window.fill(whiteish)
pygame.display.set_caption('Slither')
#some constant variables
my_font = pygame.font.SysFont(None, 25)
clock = pygame.time.Clock()
def message(msg, color):
txt = my_font.render(msg, True, color )
window.blit(txt, [0, 0])
def loop():
#some variables
x = int(width/2)
y = int(height/2)
delta_x = 0
delta_y = 0
#misc vars
block_size = 10
apple_x = random.randint(0, height-block_size)
apple_y = random.randint(0, width - block_size)
fps = 13
run = True
while run:
for event in pygame.event.get():
if event.type ==pygame.QUIT:
run = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
delta_x = -block_size
delta_y = 0
if event.key == pygame.K_RIGHT:
delta_x = block_size
delta_y = 0
if event.key == pygame.K_UP:
delta_x = 0
delta_y = -block_size
if event.key == pygame.K_DOWN:
delta_x = 0
delta_y = block_size
if x < 0 or x > width - block_size or y < 0 or y > height - block_size:
run = False
x = x + delta_x
y = y + delta_y
window.fill(whiteish)
pygame.draw.rect(window, (0, 192, 0), (x, y, block_size, block_size), 2)
clock.tick(fps)
pygame.display.update()
message('You loose like the loose you are , LOOSER!', red)
pygame.display.update()
time.sleep(2)
pygame.quit()
loop()
As you can see, the above code is supposed to have a small square that moves around the screen upon clicking an arrow button and continues moving in the direction in which it is moving untill a different arrow is pressed.
Now, when the square hits the bounderies, a red piece of text is suppposed to appear and the program closes automatically 2 seconds later.
the code am using to handele the boundary collision is this...
if x < 0 or x > width - block_size or y < 0 or y > height - block_size:
run = False
the above code breaks out of the infinite 'while run' loop and jumps to this part
message('You loose like the loose you are , LOOSER!', red)
pygame.display.update()
time.sleep(2)
pygame.quit()
however, the text doesn't show immediately after the square runs into the walls, instead the text shows after a random button is pressed
Right now you are only executing your collision code if there is a certain event because it is indented inside of the event loop, so it only happens if there is an event, in your case key press.
for event in pygame.event.get():
# other code
if x < 0 or x > width - block_size or y < 0 or y > height - block_size:
run = False
To solve the problem simply un-indent that block of code.
while run:
for event in pygame.event.get():
if event.type ==pygame.QUIT:
run = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
delta_x = -block_size
delta_y = 0
if event.key == pygame.K_RIGHT:
delta_x = block_size
delta_y = 0
if event.key == pygame.K_UP:
delta_x = 0
delta_y = -block_size
if event.key == pygame.K_DOWN:
delta_x = 0
delta_y = block_size
if x < 0 or x > width - block_size or y < 0 or y > height - block_size:
run = False
I'm writing code for a one paddle pong game in pygame where the ball will bounce off of the 3 walls the paddle is not on, and when it does hit the paddle's wall instead of the paddle, it makes you lose a life. My problem is that I cannot figure out the collision detection to do this. Here is what I've done so far:
import pygame, sys
from pygame.locals import *
pygame.init()
screen_width = 640
screen_height = 480
Display = pygame.display.set_mode((screen_width, screen_height), 0, 32)
pygame.display.set_caption('Lonely Pong')
back = pygame.Surface((screen_width, screen_height))
background = back.convert()
background.fill((255, 255, 255))
paddle = pygame.Surface((80, 20))
_paddle = paddle.convert()
_paddle.fill((128, 0, 0))
ball = pygame.Surface((15, 15))
circle = pygame.draw.circle(ball, (0, 0, 0), (7, 7), 7)
_ball = ball.convert()
_ball.set_colorkey((0, 0, 0))
_paddle_x = (screen_width / 2) - 40
_paddle_y = screen_height - 20
_paddlemove = 0
_ball_x, _ball_y = 8, 8
speed_x, speed_y, speed_circle = 250, 250, 250
Lives = 5
clock = pygame.time.Clock()
font = pygame.font.SysFont("verdana", 20)
paddle_spd = 5
while True:
for event in pygame.event.get():
if event.type == QUIT:
sys.exit()
if event.type == KEYDOWN:
if event.key == K_RIGHT:
_paddlemove = paddle_spd
elif event.key == K_LEFT:
_paddlemove = -paddle_spd
elif event.type == KEYUP:
if event.key == K_RIGHT:
_paddlemove = 0
elif event.key == K_LEFT:
_paddlemove = 0
Livespr = font.render(str(Lives), True, (0, 0, 0))
Display.blit(background, (0, 0))
Display.blit(_paddle, (_paddle_x, _paddle_y))
Display.blit(_ball, (_ball_x, _ball_y))
Display.blit(Livespr, ((screen_width / 2), 5))
_paddle_x += _paddlemove
passed = clock.tick(30)
sec = passed / 1000
_ball_x += speed_x * sec
_ball_y += speed_y * sec
pygame.display.update()
Another problem I've been having is that when I start it up, the ball doesn't appear at all. Could somebody please point me in the right direction?
first things first, the ball doesn't appear because you are not filling the surface, you are setting the color_key:
_ball.set_colorkey((0, 0, 0))
should be
_ball.fill((0, 0, 0))
Second, for collision detection, pygame offers some functions such as collidepoint and colliderect.
https://www.pygame.org/docs/ref/rect.html#pygame.Rect.collidepoint
which means you will need the rectangles of the surfaces. do this by:
my_surface.get_rect()
https://www.pygame.org/docs/ref/surface.html#pygame.Surface.get_rect
In order to collide with the edges of the screen, you can always do
if _ball_x <= 0 or _ball_y <= 0 or _ball_x >= 640 or _ball_y >= 480:
# collision detected
I am currently building a mockup of space invaders.
I want to make the user shoot stuff and the invaders will die (1hit kill), but I can't seem to figure out how to do that. I have tried drawing a small rectangle, but then the background paints over it. Thanks for your help!
import pygame, sys, random
from pygame.locals import *
# set up pygame
pygame.init()
mainClock = pygame.time.Clock()
# set up the window
windowwidth = 800
windowheight = 700
windowSurface = pygame.display.set_mode((windowwidth, windowheight), 0, 32)
pygame.display.set_caption('Sp#c3 inv#d3r5')
# set up movement variables
moveLeft = False
moveRight = False
moveUp = False
moveDown = False
# set up direction variables
DOWNLEFT = 1
DOWNRIGHT = 3
UPLEFT = 7
UPRIGHT = 9
LEFT = 4
RIGHT = 6
UP = 8
DOWN = 2
MOVESPEED = 10
MOVE = 2
# set up counting
score = 0
# set up the colors
BLACK = (0, 0, 0)
GREEN = (0, 255, 0)
WHITE = (255, 255, 255)
RED = (255, 0, 0)
BLUE = (135, 206, 250)
# set up font
font = pygame.font.SysFont(None, 50)
def makeship(windowwidth): # set up the bouncer and food data structures
user = pygame.Rect(350, 600, 100, 25)
return user
def drawwalls(walls):
for i in range(6):
wall = pygame.Rect(0,i+1,100,25)
pygame.draw.rect(windowSurface,GREEN,wall)
walls.append(wall)
def makeinvaders(invaders):
y = 0
for i in invaders: # each row
x = 0
for j in range(10):
# create invader
invader = pygame.Rect(75+x, 100+y, 40, 25)
# append invader to invaders[row]
i.append(invader)
# increase invader's x attribute by 50
x += 60
# increase invaders y by 35
y += 45
return invaders
def movepaddle(user):
# move the paddle
if moveLeft and user.left > 0:
user.left -= MOVESPEED
if moveRight and user.right < windowwidth:
user.right += MOVESPEED
return user
def moveinvaders(invaders, invdir):
# move the invaders
for row in invaders:
for invader in row:
if invdir == RIGHT and invaders[1][9].right < windowwidth:
invader.right += MOVE
elif invaders[1][9].right > windowwidth:
invader.left -= MOVE
invdir = LEFT
if invdir == LEFT and invaders[0][0].left > 0:
invader.left -= MOVE
elif invaders[0][0].left < 0:
invader.right += MOVE
invdir = RIGHT
return invdir
def shootbullets(windowSurface,blue2):
x = pygame.Rect(400,595,2,5)
pygame.draw.rect(windowSurface,GREEN,x)
def movebullets(bullets):
for bullet in bullets:
pass
def drawstuff(user, invaders):
# draw the user onto the surface
pygame.draw.rect(windowSurface, BLACK, user)
for i in invaders:
for invader in i:
if invader in invaders[0]:
pygame.draw.rect(windowSurface, BLACK, invader)
elif invader in invaders[1]:
pygame.draw.rect(windowSurface, BLACK, invader)
elif invader in invaders[2]:
pygame.draw.rect(windowSurface, BLACK, invader)
elif invader in invaders[3]:
pygame.draw.rect(windowSurface, BLACK, invader)
elif invader in invaders[4]:
pygame.draw.rect(windowSurface, BLACK, invader)
invaders = [[],[],[],[],[]]
invdir = LEFT
walls = []
drawwalls(walls)
# make the figures
user = makeship(windowwidth)
# make invaders
invaders = makeinvaders(invaders)
# run the game loop
while True:
# draw the black background onto the surface
windowSurface.fill(WHITE)
# check for the QUIT event
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
if event.type == KEYDOWN:
# change the keyboard variables
if event.key == K_LEFT or event.key == ord('a'):
moveRight = False
moveLeft = True
if event.key == K_RIGHT or event.key == ord('d'):
moveLeft = False
moveRight = True
if event.key == K_SPACE:
shootbullets(windowSurface,RED)
if event.type == KEYUP:
if event.key == K_ESCAPE:
pygame.quit()
sys.exit()
if event.key == K_LEFT or event.key == ord('a'):
moveLeft = False
if event.key == K_RIGHT or event.key == ord('d'):
moveRight = False
# draw stuff
drawstuff(user, invaders)
# move invaders
invdir = moveinvaders(invaders, invdir)
# paddle movement
user = movepaddle(user)
# draw the window onto the screen
pygame.display.update()
mainClock.tick(80)
Take a look at this minimal space invaders-like game I've written for another question:
import pygame
# you'll be able to shoot every 450ms
RELOAD_SPEED = 450
# the foes move every 1000ms sideways and every 3500ms down
MOVE_SIDE = 1000
MOVE_DOWN = 3500
screen = pygame.display.set_mode((300, 200))
clock = pygame.time.Clock()
pygame.display.set_caption("Micro Invader")
# create a bunch of events
move_side_event = pygame.USEREVENT + 1
move_down_event = pygame.USEREVENT + 2
reloaded_event = pygame.USEREVENT + 3
move_left, reloaded = True, True
invaders, colors, shots = [], [] ,[]
for x in range(15, 300, 15):
for y in range(10, 100, 15):
invaders.append(pygame.Rect(x, y, 7, 7))
colors.append(((x * 0.7) % 256, (y * 2.4) % 256))
# set timer for the movement events
pygame.time.set_timer(move_side_event, MOVE_SIDE)
pygame.time.set_timer(move_down_event, MOVE_DOWN)
player = pygame.Rect(150, 180, 10, 7)
while True:
clock.tick(40)
if pygame.event.get(pygame.QUIT): break
for e in pygame.event.get():
if e.type == move_side_event:
for invader in invaders:
invader.move_ip((-10 if move_left else 10, 0))
move_left = not move_left
elif e.type == move_down_event:
for invader in invaders:
invader.move_ip(0, 10)
elif e.type == reloaded_event:
# when the reload timer runs out, reset it
reloaded = True
pygame.time.set_timer(reloaded_event, 0)
for shot in shots[:]:
shot.move_ip((0, -4))
if not screen.get_rect().contains(shot):
shots.remove(shot)
else:
hit = False
for invader in invaders[:]:
if invader.colliderect(shot):
hit = True
i = invaders.index(invader)
del colors[i]
del invaders[i]
if hit:
shots.remove(shot)
pressed = pygame.key.get_pressed()
if pressed[pygame.K_LEFT]: player.move_ip((-4, 0))
if pressed[pygame.K_RIGHT]: player.move_ip((4, 0))
if pressed[pygame.K_SPACE]:
if reloaded:
shots.append(player.copy())
reloaded = False
# when shooting, create a timeout of RELOAD_SPEED
pygame.time.set_timer(reloaded_event, RELOAD_SPEED)
player.clamp_ip(screen.get_rect())
screen.fill((0, 0, 0))
for invader, (a, b) in zip(invaders, colors):
pygame.draw.rect(screen, (150, a, b), invader)
for shot in shots:
pygame.draw.rect(screen, (255, 180, 0), shot)
pygame.draw.rect(screen, (180, 180, 180), player)
pygame.display.flip()
It uses colliderect to detect collisions, which your code is missing.
Also, the code in general and especially the movement code is a lot simpler than yours; so maybe it can serve as an inspiration for you.
I am trying to add in random drops from enemy deaths to a game I am making in Python and wondering how to implement it. the drops I am wanting to add currently are shield and health, with shield having a lower drop chance. The main code for Drops are here:
import pygame
class HealthDrop(pygame.sprite.Sprite):
def __init__(self, x, y):
self.image = pygame.image.load('images/Sprites/health.png')
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
self.on_ground = False
self.gravity = 0.5
def update(self):
def render(self, surface):
surface.blit(self.image, self.rect)
class ShieldDrop(pygame.sprite.Sprite):
def __init__(self, x, y):
self.image = pygame.image.load('images/Sprites/shield.png')
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
self.on_ground = False
self.gravity = 0.5
def update(self):
def render(self, surface):
surface.blit(self.image, self.rect)
Then the code for the main file is here:
import pygame, sys
import random
import pygame.mixer
import Funk
from time import sleep
from player import *
from zombie import *
from level import *
from bullet import *
from constants import *
from Drops import *
import menu as dm
class Game():
def __init__(self):
pygame.init()
pygame.mixer.init()
#pygame.mixer.music.load('sounds/menugame.ogg')
#pygame.mixer.music.play(-1)
# A few variables
self.gravity = .50
self.ground = pygame.Rect(0, 640, 1280, 80)
self.red = (255, 0, 0)
self.darkred = (200, 0, 0)
self.darkblue = (0, 0, 200)
self.darkgreen = (0, 200, 0)
self.gameover = pygame.image.load('images/gameover.png')
self.victory = pygame.image.load('images/victory.png')
# Bullets
self.bullets = []
# Screen
size = (1280, 720)
self.screen = pygame.display.set_mode(size)
pygame.display.set_caption('Moon Survival!')
# Moon / Background
self.moon = Background()
self.text1 = pygame.image.load('images/TextSlides/Text1.jpg')
self.text2 = pygame.image.load('images/TextSlides/Text2.jpg')
# Zombies
self.zombies = []
for i in range(15):
self.zombies.append( Zombie(random.randint(0,1280), random.randint(0,720)) )
self.zombieskilled = 0
# Player
self.player = Player(25, 320, self.gravity)
# Font for text
self.font = pygame.font.SysFont(None, 72)
# game over
self.gameover_text = self.font.render("The Aliens Are Too Good", -1, (255, 0, 0))
self.gameover_rect = self.gameover_text.get_rect(center=self.screen.get_rect().center)
# game state
self.game_state = STATE_INGAME
def run(self):
clock = pygame.time.Clock()
# "state machine"
RUNNING = True
PAUSED = False
GAME_OVER = False
# Game loop
while RUNNING:
# (all) Events
if self.game_state == STATE_INGAME:
for event in pygame.event.get():
if event.type == pygame.QUIT:
RUNNING = False
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_s:
self.bullets.append(Bullet(self.player.rect.x + 30, self.player.rect.y + 30, self.player.direction))
if event.key == pygame.K_ESCAPE:
RUNNING = False
elif event.key == pygame.K_p:
# set state to paused
self.game_state = STATE_PAUSED
# Player/Zomies events
self.player.handle_events(event)
# (all) Movements / Updates
self.player_move()
self.player.update()
for z in self.zombies:
self.zombie_move(z)
z.update(self.screen.get_rect())
for b in self.bullets:
b.update()
for tile in self.moon.get_surrounding_blocks(b):
if tile is not None:
if pygame.sprite.collide_rect(b, tile):
# Destroy block
x = tile.rect.x / tile.rect.width
y = tile.rect.y / tile.rect.height
self.moon.levelStructure[x][y] = None
self.bullets.remove(b)
# (all) Display updating
self.moon.render(self.screen)
for z in self.zombies:
z.render(self.screen)
for b in self.bullets:
b.render(self.screen)
self.player.render(self.screen)
Funk.text_to_screen(self.screen, 'Level 1', 5, 675)
Funk.text_to_screen(self.screen, 'Health: {0}'.format(self.player.health), 5, 0)
Funk.text_to_screen(self.screen, 'Score: {0}'.format(self.player.score), 400, 0)
Funk.text_to_screen(self.screen, 'Time: {0}'.format(self.player.alivetime), 750, 0)
Funk.text_to_screen(self.screen, 'Kills: {0}'.format(self.zombieskilled), 5, 50)
Funk.text_to_screen(self.screen, 'Lives: {0}'.format(self.player.lives), 300, 50)
elif self.game_state == STATE_PAUSED:
# (all) Display updating
if self.game_state == STATE_INGAME:
if event.type == pygame.QUIT:
RUNNING = False
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
RUNNING = False
choose = dm.dumbmenu(self.screen, [
'Resume Game',
'Menu',
'Quit Game'], 200, 200,'orecrusherexpanded',100,0.75,self.darkred,self.red)
if choose == 0:
print "You choose 'Start Game'."
# set state to ingame
self.game_state = STATE_INGAME
elif choose == 1:
print "You choose 'Controls'."
if choose == 2:
print "You choose 'Quit Game'."
pygame.quit()
sys.exit()
#for event in pygame.event.get():
self.moon.render(self.screen)
for z in self.zombies:
z.render(self.screen)
for b in self.bullets:
b.render(self.screen)
self.player.render(self.screen)
Funk.text_to_screen(self.screen, 'Level 1', 5, 675)
Funk.text_to_screen(self.screen, 'Health: {0}'.format(self.player.health), 5, 0)
Funk.text_to_screen(self.screen, 'Score: {0}'.format(self.player.score), 400, 0)
Funk.text_to_screen(self.screen, 'Time: {0}'.format(self.player.alivetime), 750, 0)
Funk.text_to_screen(self.screen, 'Kills: {0}'.format(self.zombieskilled), 850, 0)
elif self.game_state == STATE_GAMEOVER:
self.screen.blit(self.gameover, (0, 0))
pygame.display.update()
choose = dm.dumbmenu(self.screen, [
'New Game',
' Menu ',
'Quit Game'], 200, 300,'orecrusherexpanded',100,0.75,self.darkred,self.red)
if choose == 0:
print "You choose 'Start Game'."
# set state to ingame
self.game_state = STATE_INGAME
execfile('MoonSurvival.py')
if choose == 1:
print "You choose 'Start Game'."
execfile('run_game.py')
if choose == 2:
print "You choose 'Start Game'."
pygame.quit()
sys.exit()
pygame.display.update()
# FTP
clock.tick(100)
# --- the end ---
pygame.quit()
def player_move(self):
# add gravity
self.player.do_jump()
# simulate gravity
self.player.on_ground = False
if not self.player.on_ground and not self.player.jumping:
self.player.velY = 4
# Health
for zombie in self.zombies:
if pygame.sprite.collide_rect(self.player, zombie):
self.player.health -= 5
# check if we die
if self.player.health <= 0:
self.player.lives -= 1
self.player.rect.x = 320
self.player.rect.y = 320
self.player.health += 200
if self.player.lives <= 0:
sleep(2)
self.game_state = STATE_GAMEOVER
# move player and check for collision at the same time
self.player.rect.x += self.player.velX
self.check_collision(self.player, self.player.velX, 0)
self.player.rect.y += self.player.velY
self.check_collision(self.player, 0, self.player.velY)
def zombie_move(self, zombie_sprite):
# add gravity
zombie_sprite.do_jump()
# simualte gravity
zombie_sprite.on_ground = False
if not zombie_sprite.on_ground and not zombie_sprite.jumping:
zombie_sprite.velY = 4
# Zombie damage
for zombie in self.zombies:
for b in self.bullets:
if pygame.sprite.collide_rect(b, zombie):
#The same bullet cannot be used to kill
#multiple zombies and as the bullet was
#no longer in Bullet.List error was raised
zombie.health -= 10
self.bullets.remove(b)
if zombie.health <= 0:
self.zombieskilled += 1
self.player.score += 20
self.zombies.remove(zombie)
break
# move zombie and check for collision
zombie_sprite.rect.x += zombie_sprite.velX
self.check_collision(zombie_sprite, zombie_sprite.velX, 0)
zombie_sprite.rect.y += zombie_sprite.velY
self.check_collision(zombie_sprite, 0, zombie_sprite.velY)
def check_collision(self, sprite, x_vel, y_vel):
# for every tile in Background.levelStructure, check for collision
for block in self.moon.get_surrounding_blocks(sprite):
if block is not None:
if pygame.sprite.collide_rect(sprite, block):
# we've collided! now we must move the collided sprite a step back
if x_vel < 0:
sprite.rect.x = block.rect.x + block.rect.w
if type(sprite) is Zombie:
# the sprite is a zombie, let's make it jump
if not sprite.jumping:
sprite.jumping = True
sprite.on_ground = False
if x_vel > 0:
sprite.rect.x = block.rect.x - sprite.rect.w
if type(sprite) is Zombie:
# the sprite is a zombie, let's make it jump
if not sprite.jumping:
sprite.jumping = True
sprite.on_ground = False
if y_vel < 0:
sprite.rect.y = block.rect.y + block.rect.h
if y_vel > 0 and not sprite.on_ground:
sprite.on_ground = True
sprite.rect.y = block.rect.y - sprite.rect.h
#---------------------------------------------------------------------
Game().run()
you need to edit this:
def zombie_move(self, zombie_sprite):
for zombie in self.zombies:
for b in self.bullets:
if pygame.sprite.collide_rect(b, zombie):
zombie.health -= 10
self.bullets.remove(b)
if zombie.health <= 0:
self.zombieskilled += 1
self.player.score += 20
#You need some code here (before removing the zombie)
self.zombies.remove(zombie)
break
I'm sorry I forgot how to do it in Python, but the logic is like that: In place of the comment inside the code add something like HealthDrop.append(x, y) or ShieldDrop.append(x, y) where x and y should be zombie's values (that's why you should do it before removing the zombie).
If you want random chance just add import random then do it like that:
percentage = random.randint(1, 100)
if (percentage >= 1) and (percentage < 10)
healthDrop.append(zombie.x, zombie.y)
else
if (percentage >= 10) and (percentage < 20)
shieldDrop.append(zombie.x, zombie.y)
In this example I set 10% for each "item" to drop (they can't both drop), it randomizes a number from 1 to 100 , if it's a number from 1 to 9 its healthDrop, if it's a number from 10 to 19 its shieldDrop, feel free to experiment with what percentages makes your game balanced
Also don't forget to add collision (I see you already have some code for collision so I guess you know how to do it). The rest of the code should be easy for you to do (like increasing health on pick up etc etc.
I'm sorry I don't remember python really well, but you can use them similar to the bullet class, I hope you have the idea, if there's anything troubling you please tell me and I'll help more :)