I'm making a pygame game where a person can purchase bombs from a shop. The player can also drop as many bombs as he buys. I need a way to make each bomb disappear after 3 seconds of it being dropped. In the following code I am just able to drop the bombs however I have tried various methods and failed.
import pygame
import random
pygame.font.init()
width = 900
height = 600
screen = pygame.display.set_mode([width, height])
walkRight = [pygame.image.load('R1.png'), pygame.image.load('R2.png'), pygame.image.load('R3.png'),
pygame.image.load('R4.png'), pygame.image.load('R5.png'), pygame.image.load('R6.png'),
pygame.image.load('R7.png'), pygame.image.load('R8.png'), pygame.image.load('R9.png')]
walkLeft = [pygame.image.load('L1.png'), pygame.image.load('L2.png'), pygame.image.load('L3.png'),
pygame.image.load('L4.png'), pygame.image.load('L5.png'), pygame.image.load('L6.png'),
pygame.image.load('L7.png'), pygame.image.load('L8.png'), pygame.image.load('L9.png')]
char = pygame.image.load('standing.png')
bomb_pic = pygame.transform.scale(pygame.image.load('bomb.png'), (20,20))
bomb_explosion = pygame.transform.scale(pygame.image.load('explosion1.png'), (40,40))
# char_rect = char.get_rect()
enemy_Left = [pygame.image.load('L1E.png'), pygame.image.load('L2E.png'), pygame.image.load('L3E.png'),
pygame.image.load('L4E.png'), pygame.image.load('L5E.png'), pygame.image.load('L6E.png'),
pygame.image.load('L7E.png'), pygame.image.load('L8E.png'), pygame.image.load('L9E.png')]
x = 50
y = 50
width = 40
height = 60
vel = 5
isJump = False
jumpCount = 10
left = False
right = False
down = False
up = False
walkCount = 0
enemy_vel = 2
enemy_list = []
shop = pygame.transform.scale(pygame.image.load("shop.png"), (60, 60))
clock = pygame.time.Clock()
FPS = 60
font = pygame.font.Font('freesansbold.ttf', 32)
items_font = pygame.font.Font('freesansbold.ttf', 16)
bombs =[]
bag = {'bomb': 0}
print(bag["bomb"])
class Button():
def __init__(self, color, x, y, width, height, text=''):
self.color = color
self.x = x
self.y = y
self.width = width
self.height = height
self.text = text
def draw(self, win, outline=None):
# Call this method to draw the button on the screen
if outline:
pygame.draw.rect(win, outline, (self.x - 2, self.y - 2, self.width + 4, self.height + 4), 0)
pygame.draw.rect(win, self.color, (self.x, self.y, self.width, self.height), 0)
if self.text != '':
font = pygame.font.SysFont('comicsans', 20)
text = font.render(self.text, 1, (0, 0, 0))
win.blit(text, (
self.x + (self.width / 2 - text.get_width() / 2), self.y + (self.height / 2 - text.get_height() / 2)))
def shop_run():
shop_bomb = Button((0, 200, 0), 820, 150, 60, 20, text="Bomb_b")
bright_green = (0, 255, 0)
green = (0, 200, 0)
shop_bomb.draw(screen)
def redrawGameWindow():
global walkCount
global font
global bag
global items_font
global enemy_list
screen.fill([166, 166, 166])
for five_enemies in range(6):
random_enemy_location_y = random.randrange(100, 400)
random_enemy_location_x = random.randrange(800, 840)
enemy_list.append([random_enemy_location_x, random_enemy_location_y])
for enemies in range(6):
screen.blit(enemy_Left[enemies], enemy_list[enemies])
enemy_list[enemies][0] -= 0.3
pygame.draw.rect(screen, (0, 0, 0), (800, 0, 100, 600))
if x + char.get_width() < 60 and y + char.get_height() < 60:
shop_run()
screen.blit(shop, (0, 0))
screen.blit(font.render("Menu", True, (255,255,255)),(805, 10))
screen.blit(items_font.render("Bombs: "+ str(bag["bomb"]), True, (255, 255, 255)), (805, 550))
# screen.blit(bomb_explosion, (450, 300))
if walkCount + 1 >= 27:
walkCount = 0
if left:
screen.blit(walkLeft[walkCount // 3], (x, y))
walkCount += 1
elif right:
screen.blit(walkRight[walkCount // 3], (x, y))
walkCount += 1
elif down:
screen.blit(char, (x, y))
walkcount = 0
elif up:
screen.blit(char, (x, y))
walkcount = 0
else:
screen.blit(char, (x, y))
walkCount = 0
for pos in bombs:
screen.blit(bomb_pic, pos)
pygame.display.update()
def main():
run = True
# shopper()
pygame.display.set_caption("bomb-mania")
global x
global y
global width
global height
global vel
global isJump
global jumpCount
global left
global right
global down
global up
global walkCount
global bomb_pic
global font
while run:
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
if x + char.get_width() < 60 and y + char.get_height() < 60:
buy = pygame.key.get_pressed()
if buy[pygame.K_b]:
bag["bomb"] += 1
print(bag["bomb"])
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE and bag["bomb"] >= 1:
bombs.append(((x + (char.get_width()/2)),( y + (char.get_height() - 20))))
bag["bomb"] -= 1
redrawGameWindow()
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT] and x > vel - 15:
x -= vel
left = True
right = False
down = False
up = False
elif keys[pygame.K_RIGHT] and x < 800 - vel - width:
x += vel
left = False
right = True
down = False
up = False
elif keys[pygame.K_DOWN] and y < 600 - height:
y += vel
left = False
right = False
down = True
up = False
elif keys[pygame.K_UP] and y > vel - 15:
y -= vel
left = False
right = False
down = False
up = True
else:
left = False
right = False
down = False
up = False
walkCount = 0
clock.tick(FPS)
pygame.display.flip()
main()
Use pygame.time.get_ticks() to get the current time in milliseconds. Compute the time when the bomb has to disappear.
Store the time to the list bombs. The list bombs has to contain a tuple of position and time.
If the time is elapsed, then remove the bomb from the list:
def redrawGameWindow():
current_time = pygame.time.get_ticks()
# [...]
for i in reversed(range(len(bombs))):
pos, end_time = bombs[i]
if current_time > end_time
bombs.pop(i)
else:
screen.blit(bomb_pic, pos)
def main():
# [...]
while run:
current_time = pygame.time.get_ticks()
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
# [...]
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE and bag["bomb"] >= 1:
pos = x + char.get_width()/2, y + char.get_height() - 20
end_time = current_time + 3000 # 3000 milliseconds = 3 seconds
bombs.append((pos, end_time))
bag["bomb"] -= 1
redrawGameWindow()
Related
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.
import pygame
import os
import random
import time
import json
from pygame import joystick
pygame.font.init()
pygame.init()
WIDTH, HEIGHT = 1920, 1000
WIN = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("space invaders")
WHITE = (255, 255, 255)
#load images
RED_SPACE_SHIP = pygame.transform.scale(pygame.image.load(os.path.join("Assets", "pixel_ship_red_small.png")), (125, 100))
GREEN_SPACE_SHIP = pygame.transform.scale(pygame.image.load(os.path.join("Assets", "pixel_ship_green_small.png")), (125, 100))
BLUE_SPACE_SHIP = pygame.transform.scale(pygame.image.load(os.path.join("Assets", "pixel_ship_blue_small.png")), (125, 100))
#player
YELLOW_SPACE_SHIP = pygame.transform.rotate(pygame.transform.scale(pygame.image.load(os.path.join("Assets", "spaceship_yellow.png")), (154, 121)), 180)
#lasers
RED_LASER = pygame.image.load(os.path.join("Assets", "pixel_laser_red.png"))
BLUE_LASER = pygame.image.load(os.path.join("Assets", "pixel_laser_blue.png"))
GREEN_LASER = pygame.image.load(os.path.join("Assets", "pixel_laser_green.png"))
#player laser
YELLOW_LASER = pygame.image.load(os.path.join("Assets", "pixel_laser_yellow.png"))
#background
BG = pygame.transform.scale(pygame.image.load(
os.path.join('Assets', 'space.png')), (WIDTH, HEIGHT))
class Laser():
def __init__(self, x, y, img):
self.x = x
self.y = y
self.img = img
self.mask = pygame.mask.from_surface(self.img)
def draw(self, window):
window.blit(self.img, (self.x, self.y))
def move(self, vel):
self.y += vel
def off_screen(self, height):
return not(self.y <= height and self.y >= 0)
def collision(self, obj):
return collide(self, obj)
class Ship:
COOLDOWN = 30
def __init__(self, x, y, health = 100):
self.x = x
self.y = y
self.health = health
self.ship_img = None
self.laser_img = None
self.lasers = []
self.cool_down_counter = 0
def draw(self, window):
window.blit(self.ship_img, (self.x, self.y))
for laser in self.lasers:
laser.draw(window)
def move_lasers(self, vel, obj):
self.cooldown()
for laser in self.lasers:
laser.move(vel)
if laser.off_screen(HEIGHT):
self.lasers.remove(laser)
elif laser.collision(obj):
obj.health -= 10
self.lasers.remove(laser)
def cooldown(self):
if self.cool_down_counter >= self.COOLDOWN:
self.cool_down_counter = 0
elif self.cool_down_counter > 0:
self.cool_down_counter += 1
def shoot(self):
if self.cool_down_counter == 0:
laser = Laser(self.x, self.y, self.laser_img)
self.lasers.append(laser)
self.cool_down_counter = 1
def get_width(self):
return self.ship_img.get_width()
def get_height(self):
return self.ship_img.get_height()
class Player(Ship):
def __init__(self, x, y, health = 100):
super().__init__(x, y, health)
self.ship_img = YELLOW_SPACE_SHIP
self.laser_img = YELLOW_LASER
self.mask = pygame.mask.from_surface(self.ship_img)
self.max_health = health
def shoot(self):
if self.cool_down_counter == 0:
laser = Laser(self.x + 26, self.y - 57, self.laser_img)
self.lasers.append(laser)
self.cool_down_counter = 1
def move_lasers(self, vel, objs):
self.cooldown()
for laser in self.lasers:
laser.move(vel)
if laser.off_screen(HEIGHT):
self.lasers.remove(laser)
else:
for obj in objs:
if laser.collision(obj):
objs.remove(obj)
if laser in self.lasers:
self.lasers.remove(laser)
def draw(self, window):
super().draw(window)
self.healthbar(window)
def healthbar(self, window):
pygame.draw.rect(window, (255, 0, 0), (self.x, self.y + self.ship_img.get_height() + 10, self.ship_img.get_width(), 10))
pygame.draw.rect(window, (0, 255, 0), (self.x, self.y + self.ship_img.get_height() + 10, self.ship_img.get_width()* (self.health/self.max_health),10))
class Enemy(Ship):
COLOR_MAP = {
"red": (RED_SPACE_SHIP, RED_LASER),
"green": (GREEN_SPACE_SHIP, GREEN_LASER),
"blue": (BLUE_SPACE_SHIP, BLUE_LASER)
}
def __init__(self, x, y, color, health = 100):
super().__init__(x, y, health)
self.ship_img, self.laser_img = self.COLOR_MAP[color]
self.mask = pygame.mask.from_surface(self.ship_img)
def move(self, vel):
self.y += vel
def shoot(self):
if self.cool_down_counter == 0:
laser = Laser(self.x - 3, self.y + 20, self.laser_img)
self.lasers.append(laser)
self.cool_down_counter = 1
def collide(obj1, obj2):
offset_x = obj2.x - obj1.x
offset_y = obj2.y - obj1.y
return obj1.mask.overlap(obj2.mask, (offset_x, offset_y)) != None
def main():
run = True
FPS = 60
level = 0
lives = 5
lost = False
lost_count = 0
main_font = pygame.font.SysFont("comicsans", 75)
lost_font = pygame.font.SysFont("comicsans", 500)
enemies = []
wave_length = 5
player_vel = 7
laser_vel = 7
enemy_vel = 1
player = Player(WIDTH // 2, 650)
clock = pygame.time.Clock()
def redraw_window():
WIN.blit(BG, (0,0))
#draw text
level_label = main_font.render(f"Level: {level}", 1, WHITE)
lives_label = main_font.render(f"Lives: {lives}", 1, WHITE)
WIN.blit(lives_label, (10, 10))
WIN.blit(level_label, (WIDTH - level_label.get_width() - 10, 10))
player.draw(WIN)
for enemy in enemies:
enemy.draw(WIN)
if lost:
lost_label = lost_font.render("You Lost!", 1, (WHITE))
WIN.blit(lost_label, (WIDTH/2 - lost_label.get_width()/2, HEIGHT / 2 - lost_label.get_height() / 2))
pygame.display.update()
joysticks = []
for i in range(pygame.joystick.get_count()):
joysticks.append(pygame.joystick.Joystick(i))
for joystick in joysticks:
pygame.joystick.init()
print(pygame.joystick.get_init())
with open(os.path.join("ps4_keys.json"), 'r+') as file:
button_keys = json.load(file)
# 0: Left analog horizonal, 1: left analog verticle, 2: right analog horizonal
# 3: right analog verticle, 4: left Triger, 5: Right Trigger
analog_keys = {0:0, 1:0, 2:0, 3:0, 4:-1, 5:-1}
while run:
clock.tick(FPS)
redraw_window()
if lives <= 0 or player.health <= 0:
lost = True
lost_count += 1
if lost:
if lost_count > FPS * 3:
run = False
else:
continue
if len(enemies) == 0:
level += 1
wave_length += 5
for i in range(wave_length):
enemy = Enemy(random.randrange(100, WIDTH-100), random.randrange(-1500, -100), random.choice(["red", "blue", "green"]))
enemies.append(enemy)
for event in pygame.event.get():
if event.type == pygame.QUIT:
quit()
if event.type == pygame.JOYAXISMOTION:
analog_keys[event.axis] = event.value
print(analog_keys)
if abs(analog_keys[0]) > .4:
if analog_keys[0] < -.7:
player.x -= 7
else:
continue
if analog_keys[0] < .7:
player.x += 7
for enemy in enemies[:]:
enemy.move(enemy_vel)
enemy.move_lasers(laser_vel, player)
if random.randrange(0, 120) == 1:
enemy.shoot()
if collide(enemy, player):
player.health -= 10
enemies.remove(enemy)
elif enemy.y + enemy.get_height() > HEIGHT:
lives -= 1
enemies.remove(enemy)
player.move_lasers(-laser_vel, enemies)
def main_menu():
title_font = pygame.font.SysFont("comicsans", 150)
run = True
while run:
WIN.blit(BG, (0,0))
title_label = title_font.render("Click the mouse to begin...", 1, WHITE)
WIN.blit(title_label, (WIDTH / 2 - title_label.get_width() / 2, HEIGHT / 2 - title_label.get_height() / 2))
pygame.display.update()
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
if event.type == pygame.MOUSEBUTTONDOWN:
main()
pygame.quit()
main_menu()
^^^
so this is my code (here is the JSON file as well):
{
"x": 0,
"circle": 1,
"square": 2,
"triangle": 3,
"share": 4,
"PS": 5,
"options": 6,
"left_stick_click": 7,
"right_stick_click": 8,
"L1": 9,
"R1": 10,
"up_arrow": 11,
"down_arrow": 12,
"left_arrow": 13,
"right_arrow": 14,
"touchpad": 15
}
I'm trying to make the player be controlled by the controller left joystick and it returns no errors but my player does not move and it is printing true from the print(pygame.joystick.get_init()) and printing the joystick amounts from: print(analog_keys) but the player does not move. Any idea why?
Do not use the JOYAXISMOTION event. The event does not occur continuously, it only occurs once when the axis changes.
Use pygame.joystick.Joystick.get_axis to get the current position of the axis and move the player depending on the axis:
def main():
# [...]
while run:
# [...]
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
if joysticks:
joystick = joysticks[0]
axis_x, axis_y = (joystick.get_axis(0), joystick.get_axis(1))
if abs(axis_x) > 0.1:
player.x += round(7 * axis_x)
if abs(axis_y) > 0.1:
player.y += round(7 * axis_y)
# [...]
Minimal example:
import pygame
from pygame.locals import *
pygame.init()
window = pygame.display.set_mode((300, 300))
clock = pygame.time.Clock()
x, y = window.get_rect().center
if pygame.joystick.get_count() > 0:
joystick = pygame.joystick.Joystick(0)
joystick.init()
run = True
while run:
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
axis_x, axis_y = (joystick.get_axis(0), joystick.get_axis(1))
if abs(axis_x) > 0.1:
x = (x + round(7 * axis_x)) % window.get_width()
if abs(axis_y) > 0.1:
y = (y + round(7 * axis_y)) % window.get_height()
window.fill(0)
pygame.draw.circle(window, (255, 0, 0), (x, y), 10)
pygame.display.flip()
clock.tick(60)
pygame.quit()
exit()
import pygame
import os
import random
import time
import json
from pygame import joystick
pygame.font.init()
pygame.init()
WIDTH, HEIGHT = 1920, 1000
WIN = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("space invaders")
WHITE = (255, 255, 255)
#load images
RED_SPACE_SHIP = pygame.transform.scale(pygame.image.load(os.path.join("Assets", "pixel_ship_red_small.png")), (125, 100))
GREEN_SPACE_SHIP = pygame.transform.scale(pygame.image.load(os.path.join("Assets", "pixel_ship_green_small.png")), (125, 100))
BLUE_SPACE_SHIP = pygame.transform.scale(pygame.image.load(os.path.join("Assets", "pixel_ship_blue_small.png")), (125, 100))
#player
YELLOW_SPACE_SHIP = pygame.transform.rotate(pygame.transform.scale(pygame.image.load(os.path.join("Assets", "spaceship_yellow.png")), (154, 121)), 180)
#lasers
RED_LASER = pygame.image.load(os.path.join("Assets", "pixel_laser_red.png"))
BLUE_LASER = pygame.image.load(os.path.join("Assets", "pixel_laser_blue.png"))
GREEN_LASER = pygame.image.load(os.path.join("Assets", "pixel_laser_green.png"))
#player laser
YELLOW_LASER = pygame.image.load(os.path.join("Assets", "pixel_laser_yellow.png"))
#background
BG = pygame.transform.scale(pygame.image.load(
os.path.join('Assets', 'space.png')), (WIDTH, HEIGHT))
class Laser():
def __init__(self, x, y, img):
self.x = x
self.y = y
self.img = img
self.mask = pygame.mask.from_surface(self.img)
def draw(self, window):
window.blit(self.img, (self.x, self.y))
def move(self, vel):
self.y += vel
def off_screen(self, height):
return not(self.y <= height and self.y >= 0)
def collision(self, obj):
return collide(self, obj)
class Ship:
COOLDOWN = 30
def __init__(self, x, y, health = 100):
self.x = x
self.y = y
self.health = health
self.ship_img = None
self.laser_img = None
self.lasers = []
self.cool_down_counter = 0
def draw(self, window):
window.blit(self.ship_img, (self.x, self.y))
for laser in self.lasers:
laser.draw(window)
def move_lasers(self, vel, obj):
self.cooldown()
for laser in self.lasers:
laser.move(vel)
if laser.off_screen(HEIGHT):
self.lasers.remove(laser)
elif laser.collision(obj):
obj.health -= 10
self.lasers.remove(laser)
def cooldown(self):
if self.cool_down_counter >= self.COOLDOWN:
self.cool_down_counter = 0
elif self.cool_down_counter > 0:
self.cool_down_counter += 1
def shoot(self):
if self.cool_down_counter == 0:
laser = Laser(self.x, self.y, self.laser_img)
self.lasers.append(laser)
self.cool_down_counter = 1
def get_width(self):
return self.ship_img.get_width()
def get_height(self):
return self.ship_img.get_height()
class Player(Ship):
def __init__(self, x, y, health = 100):
super().__init__(x, y, health)
self.ship_img = YELLOW_SPACE_SHIP
self.laser_img = YELLOW_LASER
self.mask = pygame.mask.from_surface(self.ship_img)
self.max_health = health
def shoot(self):
if self.cool_down_counter == 0:
laser = Laser(self.x + 26, self.y - 57, self.laser_img)
self.lasers.append(laser)
self.cool_down_counter = 1
def move_lasers(self, vel, objs):
self.cooldown()
for laser in self.lasers:
laser.move(vel)
if laser.off_screen(HEIGHT):
self.lasers.remove(laser)
else:
for obj in objs:
if laser.collision(obj):
objs.remove(obj)
if laser in self.lasers:
self.lasers.remove(laser)
def draw(self, window):
super().draw(window)
self.healthbar(window)
def healthbar(self, window):
pygame.draw.rect(window, (255, 0, 0), (self.x, self.y + self.ship_img.get_height() + 10, self.ship_img.get_width(), 10))
pygame.draw.rect(window, (0, 255, 0), (self.x, self.y + self.ship_img.get_height() + 10, self.ship_img.get_width()* (self.health/self.max_health),10))
class Enemy(Ship):
COLOR_MAP = {
"red": (RED_SPACE_SHIP, RED_LASER),
"green": (GREEN_SPACE_SHIP, GREEN_LASER),
"blue": (BLUE_SPACE_SHIP, BLUE_LASER)
}
def __init__(self, x, y, color, health = 100):
super().__init__(x, y, health)
self.ship_img, self.laser_img = self.COLOR_MAP[color]
self.mask = pygame.mask.from_surface(self.ship_img)
def move(self, vel):
self.y += vel
def shoot(self):
if self.cool_down_counter == 0:
laser = Laser(self.x - 3, self.y + 20, self.laser_img)
self.lasers.append(laser)
self.cool_down_counter = 1
def collide(obj1, obj2):
offset_x = obj2.x - obj1.x
offset_y = obj2.y - obj1.y
return obj1.mask.overlap(obj2.mask, (offset_x, offset_y)) != None
def main():
run = True
FPS = 60
level = 0
lives = 5
lost = False
lost_count = 0
main_font = pygame.font.SysFont("comicsans", 75)
lost_font = pygame.font.SysFont("comicsans", 500)
enemies = []
wave_length = 5
player_vel = 7
laser_vel = 7
enemy_vel = 1
player = Player(WIDTH // 2, 650)
clock = pygame.time.Clock()
def redraw_window():
WIN.blit(BG, (0,0))
#draw text
level_label = main_font.render(f"Level: {level}", 1, WHITE)
lives_label = main_font.render(f"Lives: {lives}", 1, WHITE)
WIN.blit(lives_label, (10, 10))
WIN.blit(level_label, (WIDTH - level_label.get_width() - 10, 10))
player.draw(WIN)
for enemy in enemies:
enemy.draw(WIN)
if lost:
lost_label = lost_font.render("You Lost!", 1, (WHITE))
WIN.blit(lost_label, (WIDTH/2 - lost_label.get_width()/2, HEIGHT / 2 - lost_label.get_height() / 2))
pygame.display.update()
joysticks = []
for i in range(pygame.joystick.get_count()):
joysticks.append(pygame.joystick.Joystick(i))
for joystick in joysticks:
pygame.joystick.init()
print(pygame.joystick.get_init())
with open(os.path.join("ps4_keys.json"), 'r+') as file:
button_keys = json.load(file)
# 0: Left analog horizonal, 1: left analog verticle, 2: right analog horizonal
# 3: right analog verticle, 4: left Triger, 5: Right Trigger
analog_keys = {0:0, 1:0, 2:0, 3:0, 4:-1, 5:-1}
while run:
clock.tick(FPS)
redraw_window()
if lives <= 0 or player.health <= 0:
lost = True
lost_count += 1
if lost:
if lost_count > FPS * 3:
run = False
else:
continue
if len(enemies) == 0:
level += 1
wave_length += 5
for i in range(wave_length):
enemy = Enemy(random.randrange(100, WIDTH-100), random.randrange(-1500, -100), random.choice(["red", "blue", "green"]))
enemies.append(enemy)
for event in pygame.event.get():
if event.type == pygame.QUIT:
quit()
if event.type == pygame.JOYAXISMOTION:
analog_keys[event.axis] = event.value
print(analog_keys)
if abs(analog_keys[0]) > .4:
if analog_keys[0] < -.7:
player.x -= 7
else:
continue
if analog_keys[0] < .7:
player.x += 7
for enemy in enemies[:]:
enemy.move(enemy_vel)
enemy.move_lasers(laser_vel, player)
if random.randrange(0, 120) == 1:
enemy.shoot()
if collide(enemy, player):
player.health -= 10
enemies.remove(enemy)
elif enemy.y + enemy.get_height() > HEIGHT:
lives -= 1
enemies.remove(enemy)
player.move_lasers(-laser_vel, enemies)
def main_menu():
title_font = pygame.font.SysFont("comicsans", 150)
run = True
while run:
WIN.blit(BG, (0,0))
title_label = title_font.render("Click the mouse to begin...", 1, WHITE)
WIN.blit(title_label, (WIDTH / 2 - title_label.get_width() / 2, HEIGHT / 2 - title_label.get_height() / 2))
pygame.display.update()
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
if event.type == pygame.MOUSEBUTTONDOWN:
main()
pygame.quit()
main_menu()
^^^
so this is my code (here is the JSON file as well):
{
"x": 0,
"circle": 1,
"square": 2,
"triangle": 3,
"share": 4,
"PS": 5,
"options": 6,
"left_stick_click": 7,
"right_stick_click": 8,
"L1": 9,
"R1": 10,
"up_arrow": 11,
"down_arrow": 12,
"left_arrow": 13,
"right_arrow": 14,
"touchpad": 15
}
I'm trying to make the player be controlled by the controller left joystick and it returns no errors but my player does not move and it is printing true from the print(pygame.joystick.get_init()) and printing the joystick amounts from: print(analog_keys) but the player does not move. Any idea why?
Do not use the JOYAXISMOTION event. The event does not occur continuously, it only occurs once when the axis changes.
Use pygame.joystick.Joystick.get_axis to get the current position of the axis and move the player depending on the axis:
def main():
# [...]
while run:
# [...]
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
if joysticks:
joystick = joysticks[0]
axis_x, axis_y = (joystick.get_axis(0), joystick.get_axis(1))
if abs(axis_x) > 0.1:
player.x += round(7 * axis_x)
if abs(axis_y) > 0.1:
player.y += round(7 * axis_y)
# [...]
Minimal example:
import pygame
from pygame.locals import *
pygame.init()
window = pygame.display.set_mode((300, 300))
clock = pygame.time.Clock()
x, y = window.get_rect().center
if pygame.joystick.get_count() > 0:
joystick = pygame.joystick.Joystick(0)
joystick.init()
run = True
while run:
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
axis_x, axis_y = (joystick.get_axis(0), joystick.get_axis(1))
if abs(axis_x) > 0.1:
x = (x + round(7 * axis_x)) % window.get_width()
if abs(axis_y) > 0.1:
y = (y + round(7 * axis_y)) % window.get_height()
window.fill(0)
pygame.draw.circle(window, (255, 0, 0), (x, y), 10)
pygame.display.flip()
clock.tick(60)
pygame.quit()
exit()
I am trying to make a little game and I need to put some text over the background to show lives. But the text doesn't show up over the background and I don't know why. Any help is appreciated. All the drawing code is in the redrawgamewindow function. I know its something to do with the background maybe being put over the text but how would I fix this?
import random
import math
pygame.init()
GOLD = (255, 215, 0)
def text_objects(text, font):
textSurface = font.render(text, True, GOLD)
return textSurface, textSurface.get_rect()
screenwidth = 500
screenheight = 500
win = pygame.display.set_mode((screenwidth, screenheight))
pygame.display.set_caption('First Game')
bkg = pygame.image.load('2.jpg')
bkg = pygame.transform.scale(bkg, (500,500))
char1 = pygame.image.load('guy.png')
char1 = pygame.transform.scale(char1, (100, 100))
walkRight = []
walkLeft = []
HitAnim = []
Howmany = 4
for i in range(1, 13):
walkRight.append(pygame.transform.scale(pygame.image.load('R' + str(i) + '.png'), (100, 100)))
for i in range(1, 13):
walkLeft.append(pygame.transform.scale(pygame.image.load('L' + str(i) + '.png'), (100, 100)))
rockboom = pygame.image.load('b1.png')
rockboom = pygame.transform.scale(rockboom, (100,100))
GameO = pygame.image.load('GO.jpg')
rock = pygame.image.load('b.png')
rock = pygame.transform.scale(rock, (100, 100))
clock = pygame.time.Clock()
class player(object):
def __init__(self, x, y, width, height):
self.x = x
self.y = y
self.width = width
self.height = height
self.GameOver = False
self.vel = 10
self.walkCount = 0
self.left = False
self.right = False
self.lives = 3
self.hit = 0
self.hit1 = False
def draw(self, win):
if self.walkCount + 1 >= 27:
self.walkCount = 0
if self.left == True:
win.blit(walkLeft[self.walkCount // 3], (self.x, self.y))
self.walkCount += 1
pygame.display.update()
elif self.right == True :
win.blit(walkRight[self.walkCount // 3], (self.x, self.y))
self.walkCount += 1
else:
win.blit(char1, (self.x, self.y))
class rocky():
def __init__(self):
self.x = random.randrange(0, 430)
self.y = -100
def draw(self, win):
win.blit(rock, (self.x, self.y))
if man.hit1 == True:
win.blit (rockboom, (self.x, self.y))
def redrawgamewindow():
win.blit(bkg, (0, 0))
man.draw(win)
rock1.draw(win)
largeText = pygame.font.Font('freesansbold.ttf', 45)
TextSurf, TextRect = text_objects("Lives:" + str(man.lives), largeText)
TextRect.center = ((screenwidth / 2), (100 / 2))
pygame.display.flip()
def collided (rockx, rocky, manx, many):
man.hit = 0
distance = math.sqrt((math.pow(rockx-manx, 2) + (math.pow(rocky-many, 2))))
if distance < 75:
man.hit += 1
print("we be touched")
man.hit1 = True
else:
man.hit1 = False
my_list= []
for number in range(Howmany):
my_object = rocky()
my_list.append(my_object)
rock1 = rocky()
man = player(250, 350, 100, 100)
run = True
while run:
# Setting fps
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
run = False
# Getting keys pressed
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT] and man.x > 0:
man.x -= man.vel
man.left = True
man.right = False
elif keys[pygame.K_RIGHT] and man.x < 500 - man.vel - man.width:
man.x += man.vel
man.left = False
man.right = True
else:
man.left = False
man.right = False
man.walkCount = 0
for rockk in my_list:
rock1.draw(win)
rock1.y += 5
if rock1.y >= 500:
rock1.x = random.randrange(0, 430)
rock1.y = -100
if man.hit1 == True:
rock1.x = random.randrange(0, 430)
rock1.y = -100
if man.hit == 1:
man.lives -=1
if man.hit ==2:
man.lives -=1
if man.lives <= 0:
print("so uh yeah it worked cool ")
exit()
collided(rock1.x, rock1.y, man.x, man.y)
redrawgamewindow()
win.blit(pygame.image.load('R1.png').convert_alpha(), (200, 200))
You're not blitting the text. Try this:
def redrawgamewindow():
win.blit(bkg, (0, 0))
man.draw(win)
rock1.draw(win)
largeText = pygame.font.Font('freesansbold.ttf', 45)
TextSurf, TextRect = text_objects("Lives:" + str(man.lives), largeText)
TextRect.center = ((screenwidth / 2), (100 / 2))
win.blit(TextSurf,TextRect)
pygame.display.flip()
I am making a space invader/dodging game in pygame. I have items that you can touch to e.g. increase health. When the sprite touches the health item, I want the background to be green momentarily.
Below is what I have at the moment. Since I have more than 1 item on the screen at a time, I check for each time using (line 1). You can see that when touching potion, the fillcolor is set to green
The problem is if the sprite is only touching 1 of the 2 items in the screen, the background will be set to black when checking for the second one.
How do I make it so that if at least 1 of the 2 items is being touched, the background becomes green?
EDIT:
I had made the question too vague in fear of making it too long, so here are more details.
fillcolor is the variable that sets the background color of the window. There are three types of items that you can touch, and a maximum of 2 items can appear at once, regardless of the type of item.
This might be a bit long, but what is going wrong is:
By using the for loop, I am checking the 2 items on the screen, and checking if the item you hit is a potion, ammunition or "fever mode"(powerup item). As you can see if it is "potion", your health is increased and if it is "ammo" your ammo count is being increased. For example if there are two items on the screen and you are touching one of them, which is a potion. Then the background becomes green, however in the next round of the for loop when checking the second item, fillcolor instantly becomes black because you are not touching both of the items, only one of them. What is want to do is to make the background green if you are touching one of them, even if the second one is not touched.
for e in items:
ship.checkItemCollision(e, ship)
if ship.checkItemCollision(e, ship) == 'potion':
print('potion')
ship.health += 0.5
fillcolor = (0, 255, 0)
touchDatItem = True
elif ship.checkItemCollision(e, ship) == 'ammo':
print('ammo')
ammoCount += 1
fillcolor = (255, 255, 0)
touchDatItem = True
elif ship.checkItemCollision(e, ship) == 'fever':
print('fever')
feverMode = True
fillcolor = (255, 0, 0)
touchDatItem = True
elif not touchDatItem:
fillcolor = black
Here's the whole code:
import pygame as pg
import time
import random
import math
pg.init()
display_width = 800
display_height = 600
black = (0, 0, 0)
white = (255, 255, 255)
red = (200, 0, 0)
bllue = (0, 0, 255)
green = (0, 200, 0)
bright_red =(255, 0, 20)
bright_green = (0, 255, 0)
yellow = (255,255,0)
dark_yellow = (150, 150, 0)
clock = pg.time.Clock()
potion = pg.image.load('revive.png')
ammo = pg.image.load('ammo.png')
fever = pg.image.load('fever.png')
gameDisplay = pg.display.set_mode((display_width, display_height))
pg.display.set_caption('Object Oriented')
class Item:
def __init__(self):
self.items = [potion, potion, potion, ammo, ammo,ammo, ammo, ammo, fever, fever, fever, fever, fever, fever, fever, fever, fever, fever, fever, fever, fever, ]
self.images = potion
self.speed = 3
self.width = 30
self.height = 30
self.x = 30
self.y = random.randrange(-1000, -300)
def move(self):
self.y += self.speed
if self.y > display_height:
self.x = random.randrange(0, (display_width - self.width))
self.y = random.randrange(-5000, -1000)
self.images = random.choice(self.items)
def draw(self):
gameDisplay.blit(self.images, (self.x, self.y))
class Thing:
def __init__(self):
self.width = 20
self.height = 20
self.x = random.randrange(0, (display_width - self.width))
self.y = random.randrange(-500, 0)
self.speedY = 3
self.speedX = 3
self.color = bright_red
self.ratio = random.randrange(-3, 3)
def move(self, count):
if self.ratio == 0:
self.y += self.speedY
else:
self.y += self.speedY
## self.x += random.randint(-5, 5)
self.x += self.ratio
if self.y > display_height:
self.x = random.randrange(0, (display_width - self.width))
self.y = random.randrange(-500, 0)
self.ratio = random.randrange(-3, 3)
return True
def draw(self):
pg.draw.rect(gameDisplay, self.color, [self.x, self.y, self.height, self.width])
## def randomizeX(self):
## self.x = random.randrange(0, (display_width - self.width))
## def resetY(self):
## self.y = 05
##def checkQuit():
## for event in pg.event.get():
## if event.type == pg.QUIT:
## pg.quit()
## quit()
class Ship:
def __init__(self):
self.x = display_width / 2
self.y = display_height / 2
self.speed = 10
self.height = 20
self.width = 20
self.color = yellow
self.changeX = 0
self.changeY = 0
self.health = 100
## def move(self, event):
##
## if event.type == pg.KEYDOWN:
## print(event.key)
## if event.key == pg.K_LEFT:
## self.change = -(self.speed)
## if event.key == pg.K_RIGHT:
## self.change = self.speed
## if event.type == pg.KEYUP:
## if event.key == pg.K_LEFT or event.key == pg.K_RIGHT:
## self.change = 0
## self.x += self.change
def draw(self):
pg.draw.rect(gameDisplay, self.color, [self.x, self.y, self.height, self.width])
def moveShip(self, event):
if event.type == pg.KEYDOWN:
## print(self.changeY)
## print(self.changeX)
if event.key == pg.K_LEFT:
self.changeX = -(self.speed)
if event.key == pg.K_RIGHT:
self.changeX = self.speed
if event.key == pg.K_UP:
self.changeY = -(self.speed)
if event.key == pg.K_DOWN:
self.changeY = self.speed
if event.type == pg.KEYUP:
if event.key == pg.K_LEFT or event.key == pg.K_RIGHT or event.key == pg.K_UP or event.key == pg.K_DOWN:
self.changeX = 0
self.changeY = 0
def testWallCollision(self):
if self.x > (display_width - self.width) or self.x < 0:
self.health = self.health/2
def checkThingCollision(self, t, ship, fillcolor, red, count):
# if thing_starty < (y + car_height) and y < (thing_starty+thing_height):
if (t.y - (t.height/2)) < (ship.y + ship.height) and ship.y < ((t.y - (t.height/2)) + t.height):
if (self.x > t.x and self.x < (t.x + t.width) or ((self.x + t.width) > t.x and (self.x + t.width) < t.x + t.width)):
self.health -= 0.5
t.x = random.randrange(0, (display_width - t.width))
t.y = random.randrange(-500, 0)
t.ratio = random.randrange(-10, 10)
def checkItemCollision(self, e, ship):
if e.y < (ship.y + ship.height) and ship.y < (e.y + e.height):
if (self.x > e.x and self.x < (e.x + e.width) or ((self.x + e.width) > e.x and (self.x + e.width) < e.x + e.width)):
if e.images == potion:
return 'potion'
elif e.images == ammo:
return 'ammo'
elif e.images == fever:
return 'fever'
class Bullet:
def __init__(self, ship):
self.speed = 20
self.color = white
self.x = ship.x + (ship.width / 2)
self.y = ship.y + (ship.width / 2)
self.height = 5
self.width = 5
def draw(self):
## print('IN DRAAAAAW')
## if event.key == pg.K_SPACE:
pg.draw.rect(gameDisplay, self.color, [self.x, self.y, self.height, self.width])
def move(self, ship):
self.y -= self.speed
## if self.y < 0:
## self.x = ship.x + (ship.width / 2)
## self.y = ship.y + (ship.width / 2)
def checkCollision(self, t, ship, count):
if t.y < (self.y + self.height) and self.y < (t.y + t.height):
if (self.x > t.x and self.x < (t.x + t.width) or ((self.x + t.width) > t.x and (self.x + t.width) < t.x + t.width)):
t.x = random.randrange(0, (display_width - t.width))
t.y = random.randrange(-500, 0)
t.ratio = random.randrange(-10, 10)
self.y = -self.height
return True
def healthNum(health, color):
font = pg.font.SysFont(None, 25)
text = font.render('health:' + str(health) + '/100', True, color)
gameDisplay.blit(text, (500, 0))
def ammoNum(ammoCount, color):
font = pg.font.SysFont(None, 25)
text = font.render('ammo:' + str(ammoCount), True, color)
gameDisplay.blit(text, (300, 0))
def things_dodged(count):
font = pg.font.SysFont(None, 25)
text = font.render('score: ' + str(count), True, white)
gameDisplay.blit(text, (0, 0))
def main_loop():
touchDatItem = False
feverTimer = 0
gameExit = False
allItems = [potion, ammo]
things = []
ship = Ship()
bullets = []
fillcolor = black
count = 0
items = []
ammoCount = 20
FEVER = False
LIST = []
feverMode = False
for t in range (30):
things.append(Thing())
for e in range(2):
items.append(Item())
while not gameExit:
print(fillcolor)
for event in pg.event.get():
if event.type == pg.QUIT:
pg.quit()
quit()
ship.moveShip(event)
if event.type == pg.KEYDOWN:
if event.key == pg.K_SPACE:
## FEVER = True
if ammoCount > 0:
bullets.append(Bullet(ship))
if not feverMode:
ammoCount -= 1
if feverMode:
FEVER = True
else:
FEVER = False
if event.type == pg.KEYUP:
if event.key == pg.K_SPACE:
FEVER = False
if FEVER == True:
feverTimer += 1
if not feverTimer > 100:
if ammoCount > 0:
bullets.append(Bullet(ship))
else:
print('STAAAAAAAAAP')
FEVER = False
feverTimer = 0
feverMode = False
ship.x += ship.changeX
ship.y += ship.changeY
ship.testWallCollision()
gameDisplay.fill(fillcolor)
LIST = []
healthNum(ship.health, white)
ammoNum(ammoCount, white)
for t in things:
ship.checkThingCollision(t, ship, fillcolor, red, count)
if ship.checkThingCollision(t, ship, fillcolor, red, count) == True:
print('###########################')
ship.color = red
else:
ship.color = yellow
t.draw()
ship.draw()
t.move(count)
if t.move(count) == True:
count+= 1
for b in bullets:
b.draw()
for t in things:
b.checkCollision(t, ship, count)
if b.checkCollision(t, ship, count) == True:
count += 10
b.move(ship)
for e in items:
ship.checkItemCollision(e, ship)
if ship.checkItemCollision(e, ship) == 'potion':
LIST.append('potion')
print('potion')
ship.health += 0.5
touchDatItem = True
elif ship.checkItemCollision(e, ship) == 'ammo':
LIST.append('ammo')
print('ammo')
ammoCount += 1
touchDatItem = True
elif ship.checkItemCollision(e, ship) == 'fever':
LIST.append('fever')
print('fever')
feverMode = True
touchDatItem = True
if 'potion' in LIST:
fillcolor = (0, 255, 0)
elif 'ammo' in LIST:
fillcolor = (255, 255, 0)
elif 'fever' in LIST:
fillcolor = (255, 0, 0)
else:
fillcolor = black
e.draw()
e.move()
print('fillcolor = ' + str(fillcolor))
if ship.health < 1:
ship.health = 0
pg.quit()
quit()
things_dodged(count)
pg.display.update()
clock.tick(60)
pg.quit()
quit()
main_loop()
That happens when you invent your own collision detection function instead of using pygame's collision detection methods. ;) Your checkItemCollision method is incorrect.
Change this line ...
if (self.x > e.x and self.x < (e.x + e.width) or ((self.x + e.width) > e.x and (self.x + e.width) < e.x + e.width)):
to this:
if (self.x > e.x and self.x < e.x + e.width or self.x + self.width > e.x and self.x + self.width < e.x + e.width):
I'm still not 100% sure if everything is correct now. I'd give your objects a self.rect attribute and use it for the collision detection instead, e.g.:
# In __init__:
self.rect = pg.Rect(self.x, self.y, self.width, self.height)
# Then check if they collide with the `colliderect` method.
self.rect.colliderect(e.rect)
The rect needs to be moved as well when you update the positions.