I've been trying to develop a small shooting game and i'd like the window to shake eveytime the hero gets hit or looses a life, i was thinkingto maybe reposition the window 3 times in a very shot time but im not sure how to implement this and still keep the game running.
Here is my code for my main game loop:
def game():
#set screen
width = 800
height = 600
pygame.init()
screen = pygame.display.set_mode((width, height))
pygame.display.set_caption('UoN Invaders: Game')
background = pygame.Surface(screen.get_size())
background = background.convert()
background.fill((000, 000, 000))
screen.blit(background, (0, 0))
pygame.display.flip()
#load music with help of helpers.py
music = pygame.mixer.music.load ("data/spacequest.mp3")
pygame.mixer.music.play(-1)
global clock, player, playerSprite, enemySprites, enemiestocreat
global enemiesset, lvl2, laserSprites, enemyExplosion, playerExplosion, explosionSprites
clock = pygame.time.Clock()
i = 0 #setting i that define if the game is just starting of in the middle of the game
space1 = Space1(i)
space2 = Space2()
player = Player()
space1 = pygame.sprite.RenderPlain((space1))
space2 = pygame.sprite.RenderPlain((space2))
playerSprite = pygame.sprite.RenderPlain((player))
enemySprites = pygame.sprite.RenderPlain(())
if lvl2 == False:
enemiestocreat = int(float(enemiesset))
while enemiestocreat != 0:
enemySprites.add(Enemy(enemiestocreat*50))
enemiestocreat -= 1
elif lvl2 == True:
enemiesset = int(float(enemiesset)) * 2
enemiestocreat = enemiesset
while enemiestocreat != 0:
enemySprites.add(Enemy(enemiestocreat*50))
enemiestocreat -= 1
laserSprites = pygame.sprite.RenderPlain(())
enemyExplosion = pygame.sprite.RenderPlain(())
playerExplosion = pygame.sprite.RenderPlain(())
explosionSprites = pygame.sprite.RenderPlain(())
# Main Loop
global gameover, enemydead
while gameover == False:
clock.tick(60)
global lives
font = pygame.font.Font(None,36)
text1 = font.render("Lives:" + str(lives + 1), 1, (250,250,250))
textpos1 = text1.get_rect()
textpos1.centerx = 750
textpos1.centery = 590
global enemieskilled
text2 = font.render("Score: " + str(enemieskilled), 1, (250,250,250))
textpos2 = text2.get_rect()
textpos2.centerx = 55
textpos2.centery = 590
if int(float(enemiesset)) == enemydead:
lvl2 = True
enemydead = 0
lvl2src()
for event in pygame.event.get():
if event.type == KEYDOWN and event.key == K_ESCAPE:
main()
# Update
i += 1
space1.update(i)
space2.update()
player.update()
enemySprites.update()
laserSprites.update()
enemyExplosion.update()
playerExplosion.update()
explosionSprites.update()
screen.blit(background, (0, 0))
# Draw
space1.draw(screen)
space2.draw(screen)
playerSprite.draw(screen)
enemySprites.draw(screen)
laserSprites.draw(screen)
enemyExplosion.draw(screen)
playerExplosion.draw(screen)
explosionSprites.draw(screen)
screen.blit(text1, textpos1)
screen.blit(text2, textpos2)
pygame.display.flip()
while gameover == True:
gameoversrc()
And here is my function where i detect if the hero gets hit:
class Enemy(pygame.sprite.Sprite):
def __init__(self, centerx):
global level
if level%2: #choosing which lecturer depending on the modulus of the level
pygame.sprite.Sprite.__init__(self)
self.image, self.rect = load_image("fse.png", -1)
self.rect = self.image.get_rect()
self.dy = 8
self.reset()
elif level%3:
pygame.sprite.Sprite.__init__(self)
self.image, self.rect = load_image("aps.png", -1)
self.rect = self.image.get_rect()
self.dy = 8
self.reset()
else:
pygame.sprite.Sprite.__init__(self)
self.image, self.rect = load_image("ust.png", -1)
self.rect = self.image.get_rect()
self.dy = 8
self.reset()
def update(self):
self.rect.centerx += self.dx
self.rect.centery += self.dy
#checking if enemies are outside scrren
if self.rect.top > 600:
self.reset()
# Laser Collisions
if pygame.sprite.groupcollide(enemySprites, laserSprites, 1, 1):
explosionSprites.add(EnemyExplosion(self.rect.center))
# Ship Collisions
if pygame.sprite.groupcollide(playerSprite, enemySprites, 0, 1):
global lives
if lives == 0:
explosionSprites.add(PlayerExplosion(self.rect.center))
elif lives != 0:
explosionSprites.add(EnemyExplosion(self.rect.center))
lives -= 1
#randome movement of enemies
def reset(self):
self.rect.bottom = 0
self.rect.centerx = random.randrange(0, 800)
self.dy = random.randrange(5, 10)
self.dx = random.randrange(-2, 2)
A simple solution is to not draw to the screen Surface directly, but to a temporary Surface. Then blit that temporary Surface to the screen Surface.
If you want to shake the screen, simply apply an offset to the position of the temporary Surface while blitting.
To generate that offset, you can make use of a generator function.
Here's a complete example. Note how the screen shakes if the player is hit by a falling rock.
import pygame
from random import randint
from itertools import repeat
pygame.init()
org_screen = pygame.display.set_mode((400, 400))
screen = org_screen.copy()
screen_rect = screen.get_rect()
player = pygame.Rect(180, 180, 20, 20)
def get_rock():
return pygame.Rect(randint(0, 340), 0, 60, 60)
falling = get_rock()
clock = pygame.time.Clock()
# 'offset' will be our generator that produces the offset
# in the beginning, we start with a generator that
# yields (0, 0) forever
offset = repeat((0, 0))
# this function creates our shake-generator
# it "moves" the screen to the left and right
# three times by yielding (-5, 0), (-10, 0),
# ... (-20, 0), (-15, 0) ... (20, 0) three times,
# then keeps yieling (0, 0)
def shake():
s = -1
for _ in xrange(0, 3):
for x in range(0, 20, 5):
yield (x*s, 0)
for x in range(20, 0, 5):
yield (x*s, 0)
s *= -1
while True:
yield (0, 0)
while True:
if pygame.event.get(pygame.QUIT): break
pygame.event.pump()
keys = pygame.key.get_pressed()
if keys[pygame.K_w]: player.move_ip(0, -2)
if keys[pygame.K_a]: player.move_ip(-2, 0)
if keys[pygame.K_s]: player.move_ip(0, 2)
if keys[pygame.K_d]: player.move_ip(2, 0)
player.clamp_ip(screen_rect)
falling.move_ip(0, 4)
org_screen.fill((0, 0, 0))
screen.fill((255,255,255))
pygame.draw.rect(screen, (0,0,0), player)
pygame.draw.rect(screen, (255,0,0), falling)
if player.colliderect(falling):
# if the player is hit by the rock,
# we create a new shake-generator
offset = shake()
falling = get_rock()
if not screen_rect.contains(falling):
falling = get_rock()
clock.tick(100)
# here we draw our temporary surface to the
# screen using the offsets created by the
# generators.
org_screen.blit(screen, next(offset))
pygame.display.flip()
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With