Pygame: Bullets Won't Shoot Above 45 Degrees - python

Well In a game I am working on I have recently allowed mouse click to shoot wherever the mouse is. But the bullets will only shoot at either a 0 degree angle or 45 degree angle. I am wanting to try and make this to be 360 degrees. Here is the code for my main game file:
import pygame, sys
import random
import pygame.mixer
import Funk, math
from time import sleep
from player import *
from zombie import *
from level import *
from bullet import *
from constants import *
from Drops import *
from menus import *
from meteors import *
import menu as dm
class Game():
def __init__(self):
pygame.init()
pygame.mixer.init()
pygame.mixer.music.load('data/sounds/menugame.ogg')
pygame.mixer.music.set_volume(0.5)
pygame.mixer.music.play(-1)
# A few variables
self.gravity = .50
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('data/images/gameover.png')
self.victory = pygame.image.load('data/images/victory.png')
# Bullets and Drops
self.bullets = []
self.gameDrops = []
# Screen
icon = pygame.image.load('data/icons/moonsurvival.bmp')
size = SCREEN_WIDTH, SCREEN_HEIGHT
self.screen = pygame.display.set_mode(size)
pygame.display.set_caption('Moon Survival!')
pygame.display.set_icon(icon)
self.screen_rect = self.screen.get_rect()
# Moon / Background
self.moon = Background()
self.text1 = pygame.image.load('data/images/TextSlides/Text1.jpg')
self.text2 = pygame.image.load('data/images/TextSlides/Text2.jpg')
# Zombies and boss
self.zombies = []
self.bosses = []
#for i in range(15):
# self.zombies.append( Zombie(random.randint(0,1280), random.randint(0,0)) )
self.zombieskilled = 0
# Spawn time
self.last_spawn_time = 0
# Meteors
self.meteors = []
# Menus
self.menuStartGame = MenuStartGame(self.screen, self)
self.menuAbout = MenuAbout(self.screen, self)
#self.menuSettings = MenuSettings(self.screen, self)
self.menuScene = MenuScene(self.screen, self)
self.menuGameOver = MenuGameOver(self.screen, self)
#self.menuGameFinish = MenuGameFinish(self.screen, self)
# Player
self.player = Player(25, 320, self.gravity)
# Font for text
self.font = pygame.font.SysFont(None, 72)
self.point = self.player.rect.x, self.player.rect.y
self.max_radius = math.hypot(self.screen_rect.w, self.screen_rect.h)
self.mouse_angle = (0, 0)
# 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_MENU
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:
print(self.mouse_angle)
for event in pygame.event.get():
if event.type == pygame.QUIT:
RUNNING = False
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_s:
if self.player.power == POWER_TRIBULLETS:
self.bullets.append(Bullet(self.player.rect.x + 35, self.player.rect.y + 35, self.mouse_angle))
self.bullets.append(Bullet(self.player.rect.x + 30, self.player.rect.y + 30, self.mouse_angle))
self.bullets.append(Bullet(self.player.rect.x + 35, self.player.rect.y + 25, self.mouse_angle))
else:
self.bullets.append(Bullet(self.player.rect.x + 30, self.player.rect.y + 30, self.mouse_angle))
if event.key == pygame.K_ESCAPE:
RUNNING = False
elif event.key == pygame.K_p:
# set state to paused
self.game_state = STATE_PAUSED
elif event.type == pygame.MOUSEBUTTONDOWN:
if event.button == 1:
if self.player.power == POWER_TRIBULLETS:
self.bullets.append(Bullet(self.player.rect.x + 35, self.player.rect.y + 35, self.mouse_angle))
self.bullets.append(Bullet(self.player.rect.x + 30, self.player.rect.y + 30, self.mouse_angle))
self.bullets.append(Bullet(self.player.rect.x + 35, self.player.rect.y + 25, self.mouse_angle))
else:
self.bullets.append(Bullet(self.player.rect.x + 30, self.player.rect.y + 30, self.mouse_angle))
# Player/Zombies 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 boss in self.bosses:
self.boss_move(boss)
boss.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
try:
self.bullets.remove(b)
except:
continue
for m in self.meteors:
m.update()
for tile in self.moon.get_surrounding_blocks(m):
if tile is not None:
if pygame.sprite.collide_rect(m, tile):
# Destroy block
x = tile.rect.x / tile.rect.width
y = tile.rect.y / tile.rect.height
self.moon.levelStructure[x][y] = None
self.moon.levelStructure[x + 1][y + 1] = None
self.moon.levelStructure[x - 1][y - 1] = None
self.moon.levelStructure[x + 2][y + 2] = None
self.moon.levelStructure[x - 2][y - 2] = None
try:
self.meteors.remove(m)
except:
continue
self.check_game_state()
# (all) Display updating
self.moon.render(self.screen)
for z in self.zombies:
z.render(self.screen)
for boss in self.bosses:
boss.render(self.screen)
for b in self.bullets:
b.render(self.screen)
for m in self.meteors:
m.render(self.screen)
for drop in self.gameDrops:
drop.render(self.screen)
self.player.render(self.screen)
self.updateMousePosition(self.screen, pygame.mouse.get_pos())
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_GAMEOVER:
self.menuGameOver.draw()
self.menuGameOver.update()
elif self.game_state == STATE_SETTINGS:
self.menuSettings.draw()
self.menuSettings.update()
elif self.game_state == STATE_ABOUT:
self.menuAbout.draw()
self.menuAbout.update()
elif self.game_state == STATE_SCENE:
self.menuScene.draw()
self.menuScene.update()
elif self.game_state == STATE_MENU:
self.menuStartGame.draw()
self.menuStartGame.update()
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 boss in self.bosses:
boss.render(self.screen)
for b in self.bullets:
b.render(self.screen)
for m in self.meteors:
m.render(self.screen)
self.player.render(self.screen)
pygame.display.update()
# FTP
clock.tick(100)
# --- the end ---
pygame.quit()
def updateMousePosition(self, surface, mouse):
x_comp, y_comp = mouse[0] - self.point[0], mouse[1] - self.point[1]
self.mouse_angle = math.atan2(y_comp, x_comp)
x = self.max_radius * math.cos(self.mouse_angle) + self.point[0]
y = self.max_radius * math.sin(self.mouse_angle) + self.point[1]
pygame.draw.line(surface, pygame.Color("white"), self.point, (x, y))
def check_game_state(self):
elapsed_time = pygame.time.get_ticks()
if elapsed_time > self.last_spawn_time + 10:
# Spawn aliens
if len(self.zombies) <= 10:
self.zombies.append(Zombie(random.randint(0,1280), random.randint(0,0)))
# Spawned! Change last spawn time!
self.last_spawn_time = elapsed_time
meteor_time = pygame.time.get_ticks()
if meteor_time > self.last_spawn_time + random.randint(1000, 3000):
# Spawn meteors
if len(self.meteors) <= 1:
self.meteors.append(Meteor(random.randint(0,1280), random.randint(-100,0)))
# Spawned! Change last spawn time!
self.last_spawn_time = meteor_time
def player_move(self):
# Line start
self.point = self.player.rect.x + 30, self.player.rect.y + 30
# 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
# Drops
for drop in self.gameDrops:
if pygame.sprite.collide_rect(self.player, drop):
if type(drop) == HealthDrop:
self.player.health += 50
self.gameDrops.remove(drop)
elif type(drop) == SuperHealthDrop:
self.player.health += 1000
self.gameDrops.remove(drop)
elif type(drop) == TriBullets:
self.player.power = POWER_TRIBULLETS
self.gameDrops.remove(drop)
elif type(drop) == ShieldDrop:
self.player.power = POWER_SHIELD
self.gameDrops.remove(drop)
# Health
for zombie in self.zombies:
if pygame.sprite.collide_rect(self.player, zombie):
if self.player.power == POWER_SHIELD:
self.player.health -= 1
else:
self.player.health -= 5
# check if we die
if self.player.health <= 0:
self.player.power = POWER_NONE
self.player.lives -= 1
self.player.rect.x = 320
self.player.rect.y = 320
self.player.health += 200
if self.player.lives <= 0:
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()
percentage = random.randint(0, 100)
# 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:
if (percentage >= 0) and (percentage < 40):
self.gameDrops.append(HealthDrop(zombie.rect.x + 10, zombie.rect.y + 30))
elif (percentage >= 0) and (percentage < 1):
self.gameDrops.append(SuperHealthDrop(zombie.rect.x + 20, zombie.rect.y + 30))
elif (percentage >= 1) and (percentage < 20):
self.gameDrops.append(TriBullets(zombie.rect.x + 30, zombie.rect.y + 30, self.player.direction))
elif (percentage >= 1) and (percentage < 50):
self.gameDrops.append(ShieldDrop(zombie.rect.x + 40, zombie.rect.y + 30))
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()
Here is the code for the bullets:
import pygame, math
class Bullet(pygame.sprite.Sprite):
def __init__(self, x, y, angle):
self.image = pygame.image.load('data/images/Sprites/laser.png')
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
self.velX = math.cos(angle * math.pi / 180) * 8
self.velY = math.sin(angle * math.pi / 180) * 8
# self.velX = 8
# self.velX = -8
# Bullet updates
def update(self):
# Velocity
self.rect.x += self.velX
self.rect.y += self.velY
def render(self, surface):
surface.blit(self.image, self.rect)

self.mouse_angle is already in radians. If you multiply it again by math.pi / 180, as you do in Bullet.__init__(), it will always give a value very close to zero.

Related

Pygame ValueError: subsurface rectangle outside surface area [duplicate]

This question already has answers here:
Subsurface ValueError: 'subsurface rectangle outside surface area'
(1 answer)
Subsurface rect outside of surface area when using get_clip() in Pygame?
(1 answer)
How can I crop an image with Pygame?
(4 answers)
Closed 2 months ago.
I am currently working on a game on Pygame in Python. It is a player vs player battle game. When the program is run the value error subsurface rectangle outside surface area is shown. I searched about the error but could not understand about it as I am new to Pygame.
My program-
import pygame
from Players import Characters
pygame.init()
#Game window
swidth = 1000
sheight= 600
s=pygame.display.set_mode((swidth, sheight))
pygame.display.set_caption("Brawler")
#Framerate
clock = pygame.time.Clock()
FPS = 60
#Game variables
count=3
last_count_update=pygame.time.get_ticks()
score = [0, 0]#player scores. [P1, P2]
round_over = False
round_cooldown = 2000
#Player variables
Knight_size = 278
Knight_scale = 4
Knight_offset = [72, 56]
Knight_data = [Knight_size, Knight_scale, Knight_offset]
Assassin_size = 288
Assassin_scale = 3
Assassin_offset = [112, 107]
Assassin_data =[ Assassin_size, Assassin_scale, Assassin_offset]
#load background image
bg_image = pygame.image.load("G1/Assets/Bg.png").convert_alpha()
#load spritesheets
Knight_sheet = pygame.image.load("G1/Assets/Knight/Sprites.png").convert_alpha()
Assassin_sheet = pygame.image.load("G1/Assets/Assassin/Sprites.png").convert_alpha()
#load vicory image
victory_img = pygame.image.load("G1/Assets/victory.png").convert_alpha()
#define number of steps in each animation
Knight_steps=[8, 8, 20, 8, 11, 19, 10, 6, 13]
Assassin_steps=[8, 8, 6, 6, 8, 18, 7, 6, 19]
#Font
count_font = pygame.font.Font("G1/assets/fonts/turok.ttf", 80)
score_font = pygame.font.Font("G1/assets/fonts/turok.ttf", 30)
#Text
def draw_text(text, font, text_col, x, y):
img = font.render(text, True, text_col)
s.blit(img, (x, y))
#Background
def draw_bg():
scaled_bg = pygame.transform.scale(bg_image, (swidth, sheight))
s.blit(scaled_bg, (0, 0))
#Health bars
red=(255, 0, 0)
yellow=(255, 255, 0)
white=(255, 255, 255)
def draw_health_bar(health, x, y):
ratio = health / 100
pygame.draw.rect(s, white, (x - 2, y - 2, 404, 34))
pygame.draw.rect(s, red, (x, y, 400, 30))
pygame.draw.rect(s, yellow, (x, y, 400 * ratio, 30))
#Player avatars
Knight=Characters(1, 200, 310, False, Knight_data, Knight_sheet, Knight_steps)
Assassin=Characters(2, 700, 310, True, Assassin_data, Assassin_sheet, Assassin_steps)
#game loop
run = True
while run:
clock.tick(FPS)
#Display background
draw_bg()
#Display health bar
draw_health_bar(Knight.health, 20, 20)
draw_health_bar(Assassin.health, 580, 20)
draw_text("P1: " + str(score[0]), score_font, red, 20, 60)
draw_text("P2: " + str(score[1]), score_font, red, 580, 60)
#countdown
if intro_count <= 0:
#Move fighters
Knight.move(swidth, sheight, s, Assassin, round_over)
Assassin.move(swidth, sheight, s, Knight, round_over)
else:
#Display count timer
draw_text(str(intro_count), count_font, red, swidth/2, sheight/3)
#update count timer
if (pygame.time.get_ticks()-last_count_update)>= 1000:
intro_count -= 1
last_count_update = pygame.time.get_ticks()
#Update fighters
Knight.update()
Assassin.update()
#Display fighters
Knight.draw(s)
Assassin.draw(s)
#check for player defeat
if round_over == False:
if Knight.alive == False:
score[1] += 1
round_over = True
round_over_time = pygame.time.get_ticks()
elif Assassin.alive == False:
score[0] += 1
round_over = True
round_over_time = pygame.time.get_ticks()
else:
#display victory image
s.blit(victory_img, (360, 150))
if pygame.time.get_ticks()-round_over_time>round_cooldown:
round_over = False
intro_count = 3
Knight= Knight(1, 200, 310, False, Knight_data, Knight_sheet, Knight_steps)
Assassin= Assassin(2, 700, 310, True, Assassin_data, Assassin_sheet, Assassin_steps)
#event handler
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
#update display
pygame.display.update()
#exit pygame
pygame.quit()`
My Module-
import pygame
class Characters():
def __init__(self, player, x, y, flip, data, sheet, steps):
self.player = player
self.size = data[0]
self.image_scale = data[1]
self.offset = data[2]
self.flip = flip
self.animation_list = self.load_images(sheet, steps)
self.action = 0#0:idle #1:run #2:jump #3:attack1 #4: attack2 #5:hit #6:death
self.frame_index = 0
self.image = self.animation_list[self.action][self.frame_index]
self.update_time = pygame.time.get_ticks()
self.rect = pygame.Rect((x, y, 80, 180))
self.vel_y = 0
self.running = False
self.jump = False
self.attacking = False
self.attack_type = 0
self.attack_cooldown = 0
self.hit = False
self.health = 100
self.alive = True
def load_images(self, sheet, steps):
#extract images from spritesheet
animation_list = []
for y, animation in enumerate(steps):
temp_img_list = []
for x in range(animation):
temp_img = sheet.subsurface(x * self.size, y * self.size, self.size, self.size)
temp_img_list.append(pygame.transform.scale(temp_img, (self.size * self.image_scale, self.size * self.image_scale)))
animation_list.append(temp_img_list)
return animation_list
def move(self, screen_width, screen_height, surface, target, round_over):
SPEED = 10
GRAVITY = 2
dx = 0
dy = 0
self.running = False
self.attack_type = 0
#get keypresses
key = pygame.key.get_pressed()
#can only perform other actions if not currently attacking
if self.attacking == False and self.alive == True and round_over == False:
#check player 1 controls
if self.player == 1:
#movement
if key[pygame.K_a]:
dx = -SPEED
self.running = True
if key[pygame.K_d]:
dx = SPEED
self.running = True
#jump
if key[pygame.K_w] and self.jump == False:
self.vel_y = -30
self.jump = True
#attack
if key[pygame.K_r] or key[pygame.K_t]:
self.attack(target)
#determine which attack type was used
if key[pygame.K_r]:
self.attack_type = 1
if key[pygame.K_t]:
self.attack_type = 2
#check player 2 controls
if self.player == 2:
#movement
if key[pygame.K_LEFT]:
dx = -SPEED
self.running = True
if key[pygame.K_RIGHT]:
dx = SPEED
self.running = True
#jump
if key[pygame.K_UP] and self.jump == False:
self.vel_y = -30
self.jump = True
#attack
if key[pygame.K_KP1] or key[pygame.K_KP2]:
self.attack(target)
#determine which attack type was used
if key[pygame.K_KP1]:
self.attack_type = 1
if key[pygame.K_KP2]:
self.attack_type = 2
#apply gravity
self.vel_y += GRAVITY
dy += self.vel_y
#ensure player stays on screen
if self.rect.left + dx < 0:
dx = -self.rect.left
if self.rect.right + dx > screen_width:
dx = screen_width - self.rect.right
if self.rect.bottom + dy > screen_height - 220:
self.vel_y = 0
self.jump = False
dy = screen_height - 220 - self.rect.bottom
#ensure players face each other
if target.rect.centerx > self.rect.centerx:
self.flip = False
else:
self.flip = True
#apply attack cooldown
if self.attack_cooldown > 0:
self.attack_cooldown -= 1
#update player position
self.rect.x += dx
self.rect.y += dy
#handle animation updates
def update(self):
#check what action the player is performing
if self.health <= 0:
self.health = 0
self.alive = False
self.update_action(6)#6:death
elif self.hit == True:
self.update_action(5)#5:hit
elif self.attacking == True:
if self.attack_type == 1:
self.update_action(3)#3:attack1
elif self.attack_type == 2:
self.update_action(4)#4:attack2
elif self.jump == True:
self.update_action(2)#2:jump
elif self.running == True:
self.update_action(1)#1:run
else:
self.update_action(0)#0:idle
animation_cooldown = 50
#update image
self.image = self.animation_list[self.action][self.frame_index]
#check if enough time has passed since the last update
if pygame.time.get_ticks() - self.update_time > animation_cooldown:
self.frame_index += 1
self.update_time = pygame.time.get_ticks()
#check if the animation has finished
if self.frame_index >= len(self.animation_list[self.action]):
#if the player is dead then end the animation
if self.alive == False:
self.frame_index = len(self.animation_list[self.action]) - 1
else:
self.frame_index = 0
#check if an attack was executed
if self.action == 3 or self.action == 4:
self.attacking = False
self.attack_cooldown = 20
#check if damage was taken
if self.action == 5:
self.hit = False
#if the player was in the middle of an attack, then the attack is stopped
self.attacking = False
self.attack_cooldown = 20
def attack(self, target):
if self.attack_cooldown == 0:
#execute attack
self.attacking = True
self.attack_sound.play()
attacking_rect = pygame.Rect(self.rect.centerx - (2 * self.rect.width * self.flip), self.rect.y, 2 * self.rect.width, self.rect.height)
if attacking_rect.colliderect(target.rect):
target.health -= 10
target.hit = True
def update_action(self, new_action):
#check if the new action is different to the previous one
if new_action != self.action:
self.action = new_action
#update the animation settings
self.frame_index = 0
self.update_time = pygame.time.get_ticks()
def draw(self, surface):
img = pygame.transform.flip(self.image, self.flip, False)
surface.blit(img, (self.rect.x - (self.offset[0] * self.image_scale), self.rect.y - (self.offset[1] * self.image_scale)))
The error occurred-
File "c:\Users\User\Desktop\G1\Battle game V1.py", line 73, in <module>
Knight=Characters(1, 200, 310, False, Knight_data, Knight_sheet, Knight_steps)
File "c:\Users\User\Desktop\G1\Players.py", line 10, in __init__
self.animation_list = self.load_images(sheet, steps)
File "c:\Users\User\Desktop\G1\Players.py", line 33, in load_images
temp_img = sheet.subsurface(x * self.size, y * self.size, self.size, self.size)
ValueError: subsurface rectangle outside surface area

Attempting to bring gravity into a Mario like platform game in pygame

I am working on creating a donkey kong like game in which I will have Mario try to reach the top platform. To do this, I need Mario to have the ability to jump and fall with gravity.
I have been working on implementing gravity, but when I tried something that I thought would work, the gravity element worked, but the player avatar began to glitch erratically. I believe this is because he is moving up and down several times per second. Any help as to how resolve this issue, and get my gravity mechanism functioning would be greatly appreciated.
Here is my code so far:
from pygame.locals import *
import itertools
global moves
pygame.init()
screen_height = 800
screen_width = 600
screen = pygame.display.set_mode((screen_width, screen_height))
pygame.display.set_caption('Donkey Kong')
FPS = 30
player = pygame.image.load('mario.bmp') #facing right
player_rect = player.get_rect()
player_rect.center = (80, 700)
move_rate = 3
move_left = False
move_right = False
move_up = False
move_down = False
touch_ladder = True
ladder_move_up = False
ladder_move_down = False
gravity = 4
gravity_check = True
jump = False
jump_moves = 0
platform = pygame.image.load('platform.bmp')
platforms = []
platform_x = [60,120,180,240,300,360,420,480]
platform_y = [120,240,360,480,600,720]
ladders = []
ladder_x = [300, 480, 240, 300, 180, 420, 240, 120, 60, 420, 300, 480]
ladder_y = []
class Platform():
def __init__(self, y, x, x_index, y_index):
self.platform = platform
self.rect = self.platform.get_rect()
self.x_index = x_index
self.y_index = y_index
if (self.y_index % 2) != 0 :
self.rect.y = y + (2 * self.x_index)
else:
self.rect.y = y - (2 * self.x_index)
self.rect.x = x
def draw_platform(self):
if (self.rect.y % 240) != 0:
screen.blit(self.platform, (self.rect.x, self.rect.y )) #up
else:
screen.blit(self.platform, (self.rect.x, self.rect.y)) #down
class Ladder():
def __init__(self, y, x, y_index, x_index):
self.y_index = y_index
self.x_index = x_index
if (y % 240) != 0:
self.height = abs(((platform_y[self.y_index - 1] + (2 *(2 * self.x_index)))) - y)
self.rect = pygame.Rect(x, y - self.height, 20, self.height)
self.rect.y -= (2 * self.x_index)
else:
self.height = abs(((platform_y[self.y_index - 1] - (2 * (2 * self.x_index)))) - y)
self.rect = pygame.Rect(x, y - self.height, 20, self.height)
self.rect.y += (2 * self.x_index)
self.rungs = 0
def draw_ladder(self):
#pygame.draw.rect(screen, (255,0,0), self.rect)
pygame.draw.rect(screen, (255, 255, 255), (self.rect.x, self.rect.y , 4, self.height))
pygame.draw.rect(screen, (255, 255, 255), (self.rect.x + 16, self.rect.y, 4, self.height))
def draw_rungs(self):
pygame.draw.line(screen, (255, 255, 255), (self.rect.x, self.rect.y+self.rungs),(self.rect.x + 19, self.rect.y+self.rungs), 4)
self.rungs += 14
y_multiplied = platform_y.copy()
y_multiplied.extend(platform_y)
y_multiplied.sort()
print(y_multiplied)
print(ladder_x)
for y in platform_y:
if platform_y.index(y) < 6:
for x in platform_x:
platforms.append(Platform(y, x, platform_x.index(x), platform_y.index(y)))
for y, x in zip(y_multiplied, ladder_x):
ladders.append(Ladder(y, x, platform_y.index(y), platform_x.index(x)))
while True:
gravity_check = True
screen.fill((105, 105, 255))
screen.blit(player, player_rect)
for p in platforms:
p.draw_platform()
if player_rect.colliderect(p.rect):
player_rect.bottom = p.rect.top
gravity_check = False
for l in ladders:
if player_rect.colliderect(l.rect):
touch_ladder = True
gravity_check = False
if gravity_check == True:
player_rect.y += gravity
for l in ladders:
if l.y_index > 0:
l.draw_ladder()
for i in range(l.height // 14):
l.draw_rungs()
l.rungs = 0
for event in pygame.event.get():
if event.type == QUIT:
sys.exit()
pygame.quit()
if event.type == KEYDOWN:
if event.key == K_LEFT:
player = pygame.transform.flip(player, True, False)
move_left = True
if event.key == K_RIGHT:
move_right = True
player = pygame.image.load('mario.bmp')
if event.key == K_UP:
jump = True
if event.key == K_DOWN:
player_rect.y += move_rate
if event.type == KEYUP:
if event.key == K_LEFT:
move_left = False
if event.key == K_RIGHT:
move_right = False
if move_left == True:
player_rect.x -= move_rate
if move_right == True:
player_rect.x += move_rate
if ladder_move_up == True:
player_rect.y -= move_rate
if jump == True:
gravity_check = True
if jump_moves <= 60:
player_rect.y -= 10
jump_moves += 10
else:
jump_moves = 0
jump = False
pygame.display.update()
pygame.time.Clock().tick(FPS)```
This line causes problems:
if gravity_check == True:
player_rect.y += gravity
If you put print():
if gravity_check == True:
print(player_rect.y)
player_rect.y += gravity
print(player_rect.y)
You'll see that player_rect.y constantly changes between 56 and 60 (for my random image) at the start. So you need to prevent change of the player_rect.y on more than one place simultaneously to avoid this behaviour. Also as I mentioned in the comment try to avoid loading images inside of the loop because it will consume much resources.
EDIT:
for p in platforms:
p.draw_platform()
if player_rect.colliderect(p.rect):
player_rect.bottom = p.rect.top + gravity
gravity_check = False
player_rect.bottom = p.rect.top + gravity adding gravity value will solve the problem. And this is the line of code that was causing changes to player_rect.y as well as one mentioned in the original post. Hope this solves your problem.

Pygame Multiple bullets not spawning

So im new at pygame and coding my first project- a side scrolling shooter. The issue im having is with my bullets: when i press the space key, some of the bullets will show up but there are times when nothing happens, and no bullets spawn when i jump. Not quite sure how to go about fixing this issue- any ideas would be greatly appreciated.
Code is as follows:
import pygame
import math, random, sys, pygame.mixer
from pygame.locals import *
pygame.init()
pygame.mixer.pre_init(44100, -16, 2, 8192)
pygame.mixer.init()
jump = False
jump_offset = 0
jump_height = 250
k = pygame.key.get_pressed()
def events():
for event in pygame.event.get():
if event.type == QUIT or (event.type == KEYDOWN and event.key == K_ESCAPE):
pygame.quit()
sys.exit()
def do_jumping():
global jump_height
global jump
global jump_offset
if jump:
jump_offset += 3
if jump_offset >= jump_height:
jump = False
elif jump_offset > 0 and jump == False:
jump_offset -= 3
#Defining colours
BLACK = ( 0, 0, 0)
WHITE = ( 255, 255, 255)
#Window Settings
w = 1280
h = 720
half_w = w /2
half_h = h /2
AREA = w*h
#Initialising the window
pygame.init()
display = pygame.display.set_mode((w,h)) #Sets the size of the window
pygame.display.set_caption("Cattleman") #Sets the title of the window
Clock = pygame.time.Clock() #clockspeed for the game ie. 60fps
FPS = 600
#pygame.mouse.set_visible(True) #Allows the mouse to be shown in the game window.
background = pygame.image.load("background.png").convert()
backgroundWidth, backgroundHeight = background.get_rect().size
stageWidth = backgroundWidth*2 #sets the area which the player can move in
stagePosX = 0 #Records position of stage as the player moves
startScrollPosX = half_w
circleRadius = 25
circlePosX = circleRadius
playerPosX = circleRadius
playerPosY = 602
playerVelocityX = 0
playersprite = pygame.image.load("player_spriteR2.png").convert_alpha()
playersprite = pygame.transform.scale(playersprite, (130,130))
bullets = []
bulletSprite = pygame.image.load("Bullet1.png").convert_alpha()
bulletSprite = pygame.transform.scale(bulletSprite, (20,10))
#Sounds
#gunSounds = ["pew1.wav", "pew2.wav", "pew3.wav", "pew4.wav"]
#SOUNDS
shot = pygame.mixer.Sound("pew1.wav")
#------------------------MAIN PROGRAM LOOP------------------------#
while True:
events()
do_jumping()
k = pygame.key.get_pressed()
if k[K_RIGHT]:
playerVelocityX = 2 #Moves the player right
playersprite = pygame.image.load("player_spriteR2.png").convert_alpha()
playersprite = pygame.transform.scale(playersprite, (130,130))
if k[K_LEFT]:
playerVelocityX = -2 #Moves the player left
playersprite = pygame.image.load("player_spriteL2.png").convert_alpha()
playersprite = pygame.transform.scale(playersprite, (130,130))
if k[K_UP] and jump == False and jump_offset == 0:
jump = True
if not k[K_RIGHT] and not k[K_LEFT]:
playerVelocityX = 0 #If no input detected, the player does not move
if k[K_SPACE]:
for event in pygame.event.get():
bullets.append([circlePosX-100, playerPosY-20])
shot.play()
playerPosX += playerVelocityX
if playerPosX > stageWidth - circleRadius-25: playerPosX = stageWidth - circleRadius-25 #Checks if the player trie to go past the right boundary
if playerPosX < circleRadius+55:playerPosX = circleRadius+55 #Checks if the player tries to go past the left boundary
if playerPosX < startScrollPosX: circlePosX = playerPosX
elif playerPosX > stageWidth - startScrollPosX: circlePosX = playerPosX - stageWidth + w
else:
circlePosX = startScrollPosX
stagePosX += -playerVelocityX
for b in range(len(bullets)):
bullets[b][0] -= 3
for bullet in bullets[:]:
if bullet[0] < 0:
bullets.remove(bullet)
rel_x = stagePosX % backgroundWidth
display.blit(background,(rel_x - backgroundWidth, 0))
if rel_x < w:
display.blit(background, (rel_x, 0))
for bullet in bullets:
display.blit(bulletSprite, pygame.Rect(bullet[0], bullet[1], 0, 0,))
#pygame.draw.circle(display,WHITE, (int(circlePosX),playerPosY - jump_offset), circleRadius, 0)
display.blit(playersprite, (int(circlePosX-80),playerPosY-100 - jump_offset))
pygame.display.update()
Clock.tick(FPS)
display.fill(BLACK)
I have done this in my code that leaves multiple balls similar like bullets :
class Bullet():
def __init__(self, x, y):
# self.image = pygame.image.load("SingleBullet.png")
self.image = pygame.image.load("ball.png")
self.image = pygame.transform.scale(self.image, (25, 25))
self.rect = self.image.get_rect()
self.rect.centerx = x
self.rect.centery = y
self.is_alive = True
# --------------------
def update(self):
self.rect.y -= 15
if self.rect.y < 0:
self.is_alive = False
# --------------------
def draw(self, screen):
screen.blit(self.image, self.rect.topleft)
for getting keyboard :
def event_handler(self, event):
if event.type == KEYDOWN:
if event.key == K_LEFT:
self.move_x = -5
elif event.key == K_RIGHT:
self.move_x = 5
elif event.key == K_SPACE:
if len(self.shots) < self.max_shots:
self.shots.append(Bullet(self.rect.centerx, self.rect.top))
if event.type == KEYUP:
if event.key in (K_LEFT, K_RIGHT):
self.move_x = 0

Collision not working Pygame

I'm making a game with pygame, Space Invaders, and now I'm doing the collisions between the shoot of the eneimies and the player (those are images), but it doesn't work all time and I'd like to know why, and what's the solution.
Thanks for attention!
Here's the code:
# -*- coding: cp1252 -*-
import sys
import random
import pygame
import time
print pygame.init()
x_player, y_player = 650, 440
screen = pygame.display.set_mode((700, 500))
pygame.display.set_caption("Space Invaders v1.0.0")
invaders = pygame.image.load(
"C:\\Users\\bernardo\\Documents\\IFC\\Programação\\SpaceInvaders- my_own\\space-invaders.jpeg").convert_alpha()
player = pygame.image.load(
"C:\\Users\\bernardo\\Documents\\IFC\\Programação\\SpaceInvaders-my_own\\28006.png").convert_alpha()
mother_ship = pygame.image.load(
"C:\\Users\\bernardo\\Documents\\IFC\\Programação\\SpaceInvaders-my_own\\mother_ship.png").convert_alpha()
lifes = pygame.image.load(
"C:\\Users\\bernardo\\Documents\\IFC\\Programação\\SpaceInvaders-my_own\\28007.png").convert_alpha()
shoot_enemie = pygame.image.load(
"C:\\Users\\bernardo\\Documents\\IFC\\Programação\\SpaceInvaders-my_own\\shots_and_bombs2.png").convert_alpha()
shoot = pygame.image.load(
"C:\\Users\\bernardo\\Documents\\IFC\\Programação\\SpaceInvaders-my_own\\shots_and_bombs2.png").convert_alpha()
pygame.font.init()
clock = pygame.time.Clock()
move_x = 0
x_invaders, y_invaders = 60, 60
lifes_list = [lifes, lifes, lifes]
x_mother = 0
invaders_matrix = [[invaders] * 11] * 5
existe_nave = False
start = True
tru = False
tru3= True
x_shoot = x_player
y_shoot = 0
tru2 = True
shoot_enemie1, shoot_enemie2, shoot_enemie3 = shoot_enemie, shoot_enemie, shoot_enemie
shoot_list = [shoot_enemie1, shoot_enemie2, shoot_enemie]
tiros = {
"se1" : [0, 0],
"se2" : [0, 0],
"se3" : [0, 0]
}
cont = 0
while True:
invaders_matrix = [[invaders] * 11] * 5
if len(lifes_list) > 0:
clock.tick(40)
screen.fill((0, 0, 0))
screen.blit(player, ((x_player / 2), y_player))
if not tru:
invaders = pygame.image.load(
"C:\\Users\\bernardo\\Documents\\IFC\\Programação\\SpaceInvaders-my_own\\space- invader-motif.png"
).convert_alpha()
tru = True
else:
invaders = pygame.image.load(
"C:\\Users\\bernardo\\Documents\\IFC\\Programação\\SpaceInvaders-my_own\\space-invaders.jpeg"
).convert_alpha()
tru = False
x_invaders, y_invaders = 105, 125
for invader in range(len(invaders_matrix)):
for invad in range(len(invaders_matrix[invader])):
screen.blit(invaders_matrix[invader][invad], (x_invaders, y_invaders))
x_invaders += 45
x_invaders = 105
y_invaders += 30
if tru2:
for i in tiros.keys():
tiros[i][0] += tiros[i][0] + random.randint(0, 10) * 45 + 105
tiros[i][1] += tiros[i][1] + random.randint(0, 4) * 45 + 125
tru2 = False
elif tiros["se1"][1] >= 600 and tiros["se2"][1] >= 600 and tiros["se3"][1] >= 600:
tiros["se1"][1], tiros["se2"][1], tiros["se3"][1], \
tiros["se1"][0], tiros["se2"][0], tiros["se3"][0] = 0, 0, 0, 0, 0, 0
for i in tiros.keys():
tiros[i][0] += tiros[i][0] + random.randint(0, 10) * 45 + 105
tiros[i][1] += tiros[i][1] + random.randint(0, 4) * 45 + 125
for i in shoot_list:
for j in tiros.keys():
screen.blit(i, (tiros[j][0], tiros[j][1]))
for i in tiros.keys():
tiros[i][1] += 4
if existe_nave and (x_mother < 700):
screen.blit(mother_ship, [x_mother, 35])
x_mother += 4.5
screen.blit(mother_ship, [x_mother, 35])
elif random.randint(0, 800) == 0:
existe_nave = True
x_mother = 0
width_for_lifes = 680
for icon_lifes in lifes_list:
width_for_lifes -= 50
screen.blit(icon_lifes, (width_for_lifes, 15))
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_LEFT:
move_x -= 10
if event.key == pygame.K_RIGHT:
move_x += 10
if tru3:
if event.key == pygame.K_SPACE:
y_shoot = y_player - player.get_height()
x_shoot = x_player / 2 + 20
tru3 = False
elif not tru3:
if y_shoot <= 0 and event.key == pygame.K_SPACE:
y_shoot = y_player - player.get_height()
x_shoot = x_player / 2 + 20
if event.type == pygame.KEYUP and (event.key == pygame.K_LEFT or event.key == pygame.K_RIGHT):
move_x = 0
if y_shoot > -50:
screen.blit(shoot, (x_shoot, y_shoot))
y_shoot -= 10
if x_player >= 1280:
x_player = 1280
if x_player <= 25:
x_player = 25
x_player += move_x
font = pygame.font.Font(None, 36)
text = font.render("Lifes", 1, (0, 255, 85))
screen.blit(text, (450, 15))
font = pygame.font.Font(None, 36)
text = font.render("Score", 1, (0, 255, 85))
screen.blit(text, (20, 15))
#Here is the problem
player_rect = pygame.Rect(x_player, y_player, player.get_height(), player.get_width())
shoot_enemie1_rect = pygame.Rect(tiros["se1"][0], tiros["se1"][1], shoot_enemie1.get_height(),
shoot_enemie1.get_width())
shoot_enemie2_rect = pygame.Rect(tiros["se2"][0], tiros["se2"][1], shoot_enemie2.get_height(),
shoot_enemie2.get_width())
shoot_enemie3_rect = pygame.Rect(tiros["se3"][0], tiros["se3"][1], shoot_enemie3.get_height(),
shoot_enemie3.get_width())
if player_rect.colliderect(shoot_enemie1_rect) or player_rect.colliderect(shoot_enemie2_rect) or \
player_rect.colliderect(shoot_enemie3_rect):
print True
print player_rect
pygame.display.update()
Here is a collision detection code that will sense if one rectangle collides with another rectangle, if the enemy's shot hits the player:
if player x < shot x + player width and player x + shot width > shot x and player y < shot y + player height and shot height + player_y > shot y:
It works by sensing if any of the edges of the bullet are touching any edges of the character. I hope this helps.

Adding in drops from enemies in Pygame?

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 :)

Categories