Object to shoot a projectile - python

I'm trying to make my tanks shoot, and I did all the code I think I should have done but I don't know why the tanks aren't shooting anything.
import pygame, assetloader
from pygame.locals import *
import random, time, math
import pygame
GRAD = math.pi/180
blue = (0, 0, 255)
wallRects = []
bullets = []
maze = [[] for i in range(25)]
assetloader.set_asset_path("assets/")
I defined the Bullet Class here:
def calculate_dir_with_angle(angle):
direction = [0, 0]
if (angle > 0 and angle < 180) or (angle > -360 and angle < -180):
direction[0] = -1
elif (angle > -180 and angle < 0) or (angle > 180 and angle < 360):
direction[0] = 1
elif (angle > -90 and angle < 90) or (angle > 270 and anlge < 360):
direction[1] = -1
elif (angle > 90 and angle < 270) or (angle > -270 and angle < -90):
direction[1] = 1
return direction
class Bullet:
def __init__(self, pos, r, angle):
self.x = pos[0]
self.y = pos[1]
self.r = r
self.counter = 50
direction = calculate_dir_with_angle(angle)
self.vel = [direction[0] * 2, direction[1] * 2]
def draw(self, screen):
self.x = int(self.x)
self.y = int(self.y)
pygame.draw.circle(screen, (25, 25, 25), (self.x, self.y), (self.r))
def move(self):
self.x += self.vel[0]
self.y += self.vel[1]
self.rect = pygame.Rect(self.x-self.r, self.y - self.r, 2 * self.r, 2 * self.r)
for wr in wallRects:
if self.rect.centery >= wr.top and self.rect.centery <= wr.bottom:
if self.rect.left <= wr.right and self.rect.left > wr.left:
self.vel[0] = -self.vel[0]
self.x = wr.right + self.r + 1
self.rect.x = wr.right + 1
elif self.rect.right >= wr.left and self.rect.right < wr.right:
self.vel[0] = -self.vel[0]
self.x = wr.left + self.r - 1
self.rect.x = wr.left - 2 * self.r - 1
if self.rect.centerx >= wr.left and self.rect.centerx <= wr.right:
if self.rect.top <= wr.bottom and self.rect.top > wr.top:
self.vel[1] = -self.vel[1]
self.y = wr.bottom + self.r + 1
self.rect.y = wr.bottom + 1
elif self.rect.bottom >= wr.top and self.rect.bottom < wr.bottom:
self.vel[1] = -self.vel[1]
self.y = wr.top - self.r - 1
self.rect.y = wr.top - 2 * self.r - 1
if self.counter > 0:
self.counter -= 1
def generateRandomPosition():
row = random.randint(1, 23)
col = random.randint(1, 23)
while maze[row][col-1] != 0 or maze[row][col] != 0 or maze[row][col+1] != 0:
row = random.randint(1, 23)
col = random.randint(1, 23)
return row, col
Player 1:
class Player(pygame.sprite.Sprite):
def __init__(self, x, y, pos):
pygame.sprite.Sprite.__init__(self)
self.image, self.rect = assetloader.load_image("Tank.png", -1)
self.rect.x = x
self.rect.y = y
self.rect.clamp_ip(screen.get_rect())
self.rows = pos[0]
self.cols = pos[1]
self.x = self.cols * gsize
self.y = self.rows * gsize
self.orig_image, self.orig_rect = assetloader.load_image("Tank.png", -1)
self.orig_rect.x = self.x
self.orig_rect.y = self.y
self.orig_gun_pos = self.orig_rect.midtop
self.ammo = 5
def checkCollisions(self):
for b in bullets:
if b.counter <= 0:
if b.rect.colliderect(self.orig_rect):
self.dead = True
def calculate_gun_pos(self):
self.orig_gun_pos = self.orig_rect.midtop
new_y = self.orig_gun_pos[1] - self.orig_rect.centery
new_x = self.orig_gun_pos[0] - self.orig_rect.centerx
rads = self.dir * GRAD
gun_x = (new_y * math.sin(rads)) + (new_x * math.cos(rads)) + (self.orig_rect.centerx)
gun_y = (new_y * math.cos(rads)) - (new_x * math.sin(rads)) + (self.orig_rect.centery)
self.gun_pos = (gun_x, gun_y)
def shoot(self):
if self.ammo > 0:
self.calculate_gun_pos()
b = Bullet(self.gun_pos, 3, self.dir)
bullets.append(b)
self.ammo -= 1
def draw(self, screen):
image = pygame.transform.rotate(self.image, self.dir)
screen.blit(image, self.rect)
def update(self):
oldCenter = self.rect.center
self.rect = self.image.get_rect()
self.rect.center = oldCenter
screen_rect = screen.get_rect()
keys = pygame.key.get_pressed()
if keys[K_m]:
p.shoot()
if not screen_rect.contains(self.rect):
self.rect.clamp_ip(screen_rect)
Calling the functions:
size = width, height = 500, 400
gsize = 25
start_x, start_y = 0, 0
bgColor = 255, 255, 255
pygame.init()
screen = pygame.display.set_mode(size)#, pygame.FULLSCREEN)
pygame.display.set_caption("Sample Sprite")
clock = pygame.time.Clock()
p = Player(width/2, height/4, (3,4))
coll_font = pygame.font.Font(None, 30)
going = True
while going:
clock.tick(60)
for event in pygame.event.get():
if event.type == QUIT:
going = False
elif event.type == KEYDOWN:
if event.key == K_ESCAPE:
going = False
elif event.type == KEYDOWN:
if event.key == K_m:
p.shoot()
for b in bullets:
b.move()
p.update()
screen.fill(bgColor)
p.draw(screen)
pygame.display.flip()
pygame.quit()
How would I call the bullet to actually appear and fire because I have the Bullet class which gets called within the Player class in def shoot(self) so does anyone have an idea why the bullets aren't appearing?

I usually add bullets in this way: I pass the group that contains all sprites and the bullet group to the player instance and add new bullets to these group in the player's handle_event method.
import pygame as pg
from pygame.math import Vector2
pg.init()
screen = pg.display.set_mode((640, 480))
screen_rect = screen.get_rect()
FONT = pg.font.Font(None, 24)
BG_COLOR = pg.Color('gray12')
BULLET_IMAGE = pg.Surface((20, 11), pg.SRCALPHA)
pg.draw.polygon(
BULLET_IMAGE, pg.Color('aquamarine1'), [(0, 0), (20, 5), (0, 11)])
PLAYER_IMAGE = pg.Surface((50, 30), pg.SRCALPHA)
pg.draw.polygon(
PLAYER_IMAGE, pg.Color('dodgerblue1'), [(0, 0), (50, 15), (0, 30)])
class Player(pg.sprite.Sprite):
def __init__(self, pos, all_sprites, bullet_group):
super().__init__()
self.image = PLAYER_IMAGE
self.orig_image = self.image # Needed to preserve image quality.
self.rect = self.image.get_rect(center=(pos))
self.pos = Vector2(pos)
self.vel = Vector2(1, 0)
self.angle = 0
self.angle_speed = 0
self.all_sprites = all_sprites
self.bullet_group = bullet_group
def handle_event(self, event):
if event.type == pg.MOUSEBUTTONDOWN:
# Left button fires a bullet from cannon center with
# current angle. Add the bullet to the bullet_group.
if event.button == 1:
bullet = Bullet(self.pos, self.angle)
self.bullet_group.add(bullet)
self.all_sprites.add(bullet)
elif event.type == pg.KEYDOWN:
# Rotate self by setting the .angle_speed.
if event.key in (pg.K_a, pg.K_LEFT):
self.angle_speed = -3
elif event.key in (pg.K_d, pg.K_RIGHT):
self.angle_speed = 3
elif event.type == pg.KEYUP:
if event.key in (pg.K_a, pg.K_LEFT):
self.angle_speed = 0
elif event.key in (pg.K_d, pg.K_RIGHT):
self.angle_speed = 0
def update(self):
self.pos += self.vel
self.rect.center = self.pos
if self.angle_speed != 0:
self.rotate()
def rotate(self):
# Update the angle and the velocity vector.
self.angle += self.angle_speed
self.vel.rotate_ip(self.angle_speed)
# Rotate the image and get a new rect with the previous center.
self.image = pg.transform.rotozoom(self.orig_image, -self.angle, 1)
self.rect = self.image.get_rect(center=self.rect.center)
class Bullet(pg.sprite.Sprite):
def __init__(self, pos, angle):
super().__init__()
self.image = pg.transform.rotate(BULLET_IMAGE, -angle)
self.rect = self.image.get_rect(center=pos)
# To apply an offset (40 pixels) to the start position,
# create another vector and rotate it as well.
offset = Vector2(40, 0).rotate(angle)
# Add the offset vector to the position vector (the center).
self.pos = Vector2(pos) + offset
# Rotate the start velocity vector (9, 0) by the angle.
self.vel = Vector2(9, 0).rotate(angle)
def update(self):
# Add the velocity to the pos to move the sprite.
self.pos += self.vel
self.rect.center = self.pos # Update the rect as well.
# Remove bullets outside of the screen area.
if not screen_rect.contains(self.rect):
self.kill()
def main():
clock = pg.time.Clock()
all_sprites = pg.sprite.Group()
# Bullets will be added to this group.
bullet_group = pg.sprite.Group()
# Pass the bullet group to the player.
player = Player((300, 200), all_sprites, bullet_group)
all_sprites.add(player)
playing = True
while playing:
for event in pg.event.get():
if event.type == pg.QUIT:
playing = False
# Pass events to the player instance.
player.handle_event(event)
all_sprites.update()
screen.fill(BG_COLOR)
all_sprites.draw(screen)
pg.display.update()
clock.tick(30)
if __name__ == '__main__':
main()
pg.quit()

Related

i have a problem: my enemies are stacked vertically, on top of my player which is weird, and they don't move to their predefined positions [duplicate]

This question already exists:
in my shooting game, my players are positioned on top of my head (player) which is very abnormal and also once the game starts, they start shooting [closed]
Closed 6 months ago.
i have earlier tried to format my question properly but i hope this one is better. am creating a shooter game from https://github.com/russs123/Shooter. however my problem is that my enemies are stacked vertically upwards in a straight line when i run my game and the enemies don't start off at their predefined location. below is the full code i wrote. perhaps if you can run it, it will be better understood.
import pygame, sys
from player import Player
import os
import random
import csv
pygame.init()
screen_width = 600
scroll_thresh = 200
screen_scroll = 0
bg_scroll = 0
screen_height = int(screen_width * 0.8)
screen = pygame.display.set_mode((screen_width, screen_height))
pygame.display.set_caption("Shooter Game")
clock = pygame.time.Clock()
fps = 60
# define game variables
GRAVITY = 0.75
level = 1
ROWS = 16
COLS = 150
TILE_SIZE = screen_height // ROWS
TILE_TYPES = 21
img_list = []
for x in range(TILE_TYPES):
img = pygame.image.load(f"img/tile/{x}.png")
img = pygame.transform.scale(img, (TILE_SIZE, TILE_SIZE))
img_list.append(img)
# color variables
bg = (144, 201, 120)
RED = (255, 0, 0)
WHITE = (255, 255, 255)
GREEN = (0, 255, 0)
BLACK = (0, 0, 0)
# define player action variables
moving_left = False
moving_right = False
shoot = False
grenade = False
grenade_thrown = False
# load up images
pine1_img = pygame.image.load("img/Background/pine1.png").convert_alpha()
pine2_img = pygame.image.load("img/Background/pine2.png").convert_alpha()
mountain_img = pygame.image.load("img/Background/mountain.png").convert_alpha()
sky_cloud_img = pygame.image.load("img/Background/sky_cloud.png").convert_alpha()
bullet_img = pygame.image.load("img/icons/bullet.png").convert_alpha()
grenade_img = pygame.image.load("img/icons/grenade.png").convert_alpha()
# pick up boxes
health_box_img = pygame.image.load("img/icons/health_box.png").convert_alpha()
ammo_box_img = pygame.image.load("img/icons/ammo_box.png").convert_alpha()
grenade_box_img = pygame.image.load("img/icons/grenade_box.png").convert_alpha()
# name_dt = type(name)
item_boxes = {
"Health": health_box_img,
"Ammo": ammo_box_img,
"Grenade": grenade_img,
}
# define fonts
font = pygame.font.SysFont("Futura", 30)
def draw_text(text, font, text_col, x, y):
img = font.render(text, True, text_col)
screen.blit(img, (x, y))
def draw_bg():
screen.fill(bg)
screen.blit(sky_cloud_img, (0, 0))
screen.blit(mountain_img, (0, screen_height - mountain_img.get_height() - 300))
screen.blit(pine1_img, (0, screen_height - pine1_img.get_height() - 150))
screen.blit(pine2_img, (0, screen_height - pine2_img.get_height()))
class Soldier(pygame.sprite.Sprite):
def __init__(self, char_type, x, y, scale, speed, ammo, grenades):
pygame.sprite.Sprite.__init__(self)
self.alive = True
self.char_type = char_type
self.speed = speed
self.ammo = ammo
self.start_ammo = ammo
self.shoot_cooldown = 0
self.grenades = grenades
self.health = 100
self.max_health = self.health
self.direction = 1
self.vel_y = 0
self.jump = False
self.in_air = True
self.flip = False
self.animation_list = []
self.frame_index = 0
self.action = 0
# ai specific variables
self.move_counter = 0
self.vision = pygame.Rect(0, 0, 150, 20)
self.idling = 0
self.idling_counter = 0
self.update_time = pygame.time.get_ticks()
# load all images for the players
animation_types = ["idle", "run", "jump", "death"]
for animation in animation_types:
temp_list = []
# reset temporary list of images
# count number of files in the folder
num_of_frames = len(os.listdir(f"img/{self.char_type}/{animation}"))
for i in range(num_of_frames):
img = pygame.image.load(f"img/{self.char_type}/{animation}/{i}.png").convert_alpha()
img = pygame.transform.scale(img, (int(img.get_width() * scale), int(img.get_height() * scale)))
temp_list.append(img)
self.animation_list.append(temp_list)
self.image = self.animation_list[self.action][self.frame_index]
self.rect = self.image.get_rect()
self.rect.center = (x, y)
self.width = self.image.get_width()
self.height = self.image.get_height()
def update(self):
self.update_animation()
self.check_alive()
# update cooldown
if self.shoot_cooldown > 0:
self.shoot_cooldown -= 1
def move(self, moving_left, moving_right):
screen_scroll = 0
dx = 0
dy = 0
if moving_left:
dx = -self.speed
self.flip = True
self.direction = -1
if moving_right:
dx = self.speed
self.flip = False
self.direction = 1
if self.jump == True and self.in_air == False:
self.vel_y = -11
self.jump = False
self.in_air = True
# apply gravity
self.vel_y += GRAVITY
if self.vel_y > 10:
self.vel_y
dy += self.vel_y
# check for collision
for tile in world.obstacle_list:
# check collision in the x direction
if tile[1].colliderect(self.rect.x + dx, self.rect.y, self.width, self.height):
dx = 0
# check for collision in the y direction
if tile[1].colliderect(self.rect.x, self.rect.y + dy, self.width, self.height):
# check if below the ground, i.e jumping
if self.vel_y < 0:
self.vel_y = 0
dy = tile[1].bottom - self.rect.top
# check if above the ground, ie falling
elif self.vel_y >= 0:
self.vel_y = 0
self.in_air = False
dy = tile[1].top - self.rect.bottom
self.rect.x += dx
self.rect.y += dy
# update scroll based on player position
if self.char_type == "player":
if self.rect.right > screen_width - scroll_thresh or self.rect.left < scroll_thresh:
self.rect.x = -dx
screen_scroll = -dx
return screen_scroll
def shoot(self):
if self.shoot_cooldown == 0 and self.ammo > 0:
self.shoot_cooldown = 20
bullet = Bullet(self.rect.centerx + (0.75 * self.rect.size[0] * self.direction), self.rect.centery,
self.direction)
bullet_group.add(bullet)
# reduce ammo after each shot
self.ammo -= 1
def ai(self):
if self.alive and player.alive:
if self.idling == False and random.randint(1, 200) == 1:
self.update_action(0)
self.idling = True
self.idling_counter = 50
# check if ai is near the player
if self.vision.colliderect(player.rect):
# stop running and face the player
self.update_action(0)
self.shoot()
else:
if self.idling == False:
if self.direction == 1:
ai_moving_right = True
else:
ai_moving_right = False
ai_moving_left = not ai_moving_right
self.move(ai_moving_left, ai_moving_right)
self.update_action(1)
self.move_counter += 1
# update ai vision as the enemy moves
self.vision.center = (self.rect.centerx + 75 * self.direction, self.rect.centery)
if self.move_counter > TILE_SIZE:
self.direction *= -1
self.move_counter *= -1
else:
self.idling_counter -= 1
if self.idling_counter <= 0:
self.idling = False
# scroll
self.rect.x = screen_scroll
def update_animation(self):
ANIMATION_COOLDOWN = 100
# update image depending on current index
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.update_time = pygame.time.get_ticks()
self.frame_index += 1
# if animation has run out then restart to the first
if self.frame_index >= len(self.animation_list[self.action]):
if self.action == 3:
self.frame_index = len(self.animation_list[self.action]) - 1
else:
self.frame_index = 0
def check_alive(self):
if self.health <= 0:
self.health = 0
self.speed = 0
self.alive = False
self.update_action(3)
def update_action(self, new_action):
# check if new action is different from the previous one
if new_action != self.action:
self.action = new_action
# update animation settings
self.frame_index = 0
self.update_time = pygame.time.get_ticks()
def draw(self):
screen.blit(pygame.transform.flip(self.image, self.flip, False), self.rect)
class HealthBar():
def __init__(self, health, x, y, max_health):
self.x = x
self.y = y
self.health = health
self.max_health = max_health
def draw(self, health):
self.health = health
pygame.draw.rect(screen, BLACK, (self.x - 2, self.y - 2, 154, 24))
pygame.draw.rect(screen, RED, (self.x, self.y, 150, 20))
ratio = self.health / self.max_health
pygame.draw.rect(screen, GREEN, (self.x, self.y, 150 * ratio, 20))
class World():
def __init__(self):
self.obstacle_list = []
def process_data(self, data):
for y, row in enumerate(data):
for x, tile in enumerate(row):
if tile >= 0:
img = img_list[tile]
img_rect = img.get_rect()
img_rect.x = x * TILE_SIZE
img_rect.y = y * TILE_SIZE
tile_data = (img, img_rect)
if 0 <= tile <= 8:
self.obstacle_list.append(tile_data)
elif 9 <= tile <= 10:
# water
water = Water(img, x * TILE_SIZE, y * TILE_SIZE, )
water_group.add(water)
pass
elif 11 <= tile <= 14:
# decoration
decoration = Decoration(img, x * TILE_SIZE, y * TILE_SIZE)
decoration_group.add(decoration)
elif tile == 15:
# create a player
player = Soldier("player", x * TILE_SIZE, y * TILE_SIZE, 1.65, 5, 20, 5)
health_bar = HealthBar(10, 10, player.health, player.health)
elif tile == 16:
# create enemy
enemy = Soldier("enemy", x * TILE_SIZE, y * TILE_SIZE, 1.65, 2, 20, 0)
enemy_group.add(enemy)
elif tile == 17:
# create ammo box
item_box = ItemBox("Ammo", x * TILE_SIZE, y * TILE_SIZE)
item_box_group.add(item_box)
elif tile == 18:
# create grenade box
item_box = ItemBox("Grenade", x * TILE_SIZE, y * TILE_SIZE)
item_box_group.add(item_box)
elif tile == 19:
# create health box
item_box = ItemBox("Health", x * TILE_SIZE, y * TILE_SIZE)
item_box_group.add(item_box)
elif tile == 20:
# create exit point
exit = Exit(img, x * TILE_SIZE, y * TILE_SIZE, )
exit_group.add(exit)
return player, health_bar
def draw(self):
for tile in self.obstacle_list:
tile[1][0] += screen_scroll
screen.blit(tile[0], tile[1])
class Decoration(pygame.sprite.Sprite):
def __init__(self, img, x, y):
pygame.sprite.Sprite.__init__(self)
self.image = img
self.rect = self.image.get_rect()
self.rect.midtop = (x + TILE_SIZE // 2, y + (TILE_SIZE - self.image.get_height()))
def update(self):
self.rect.x += screen_scroll
class Water(pygame.sprite.Sprite):
def __init__(self, img, x, y):
pygame.sprite.Sprite.__init__(self)
self.image = img
self.rect = self.image.get_rect()
self.rect.midtop = (x + TILE_SIZE // 2, y + (TILE_SIZE - self.image.get_height()))
def update(self):
self.rect.x += screen_scroll
class Exit(pygame.sprite.Sprite):
def __init__(self, img, x, y):
pygame.sprite.Sprite.__init__(self)
self.image = img
self.rect = self.image.get_rect()
self.rect.midtop = (x + TILE_SIZE // 2, y + (TILE_SIZE - self.image.get_height()))
class ItemBox(pygame.sprite.Sprite):
def __init__(self, item_type, x, y):
pygame.sprite.Sprite.__init__(self)
self.item_type = item_type
self.image = item_boxes[self.item_type]
self.rect = self.image.get_rect()
self.rect.midtop = (x + TILE_SIZE // 2, y + (TILE_SIZE - self.image.get_height()))
def update(self):
# scroll
self.rect.x += screen_scroll
# check if player has picked up the box
if pygame.sprite.collide_rect(self, player):
# check what kind of box it was
if self.item_type == "Health":
player.health += 25
if player.health > player.max_health:
player.health = player.max_health
elif self.item_type == "Ammo":
player.ammo += 15
elif self.item_type == "Grenade":
player.grenades += 3
# delete the item box
self.kill()
class Bullet(pygame.sprite.Sprite):
def __init__(self, x, y, direction):
pygame.sprite.Sprite.__init__(self)
self.speed = 10
self.image = bullet_img
self.rect = self.image.get_rect()
self.rect.center = (x, y)
self.direction = direction
def update(self):
self.rect.x += self.direction * self.speed
# check if bullet has left the screen
if self.rect.right < 0 and self.rect.left > screen_width:
self.kill()
# check for collision with level
for tile in world.obstacle_list:
if tile[1].colliderect(self.rect):
self.kill()
# check collision with characters
if pygame.sprite.spritecollide(player, bullet_group, False):
if player.alive:
player.health -= 5
self.kill()
for enemy in enemy_group:
if pygame.sprite.spritecollide(enemy, bullet_group, False):
if enemy.alive:
enemy.health -= 25
self.kill()
class Grenade(pygame.sprite.Sprite):
def __init__(self, x, y, direction):
pygame.sprite.Sprite.__init__(self)
self.timer = 100
self.vel_y = -11
self.speed = 7
self.image = grenade_img
self.rect = self.image.get_rect()
self.rect.center = (x, y)
self.direction = direction
self.width = self.image.get_width()
self.height = self.image.get_height()
def update(self):
self.vel_y += GRAVITY
dx = self.direction * self.speed
dy = self.vel_y
# check for collision with level
for tile in world.obstacle_list:
# check if grenade has hit a wall
if tile[1].colliderect(self.rect.x + dx, self.rect.y, self.width, self.height):
self.direction *= -1
dx = self.direction * self.speed
if tile[1].colliderect(self.rect.x, self.rect.y + dy, self.width, self.height):
self.speed = 0
# check if below the ground, i.e thrown
if self.vel_y < 0:
self.y = 0
dy = tile[1].bottom - self.rect.top
# check if above the ground, ie falling
elif self.vel_y >= 0:
self.vel_y = 0
dy = tile[1].top - self.rect.bottom
# update grenade position
self.rect.x += dx
self.rect.y += dy
# explosion countdown
self.timer -= 1
if self.timer <= 0:
self.kill()
explosion = Explosion(self.rect.x, self.rect.y, 0.5)
explosion_group.add(explosion)
# do damage to anyone nearby
if abs(self.rect.centerx - player.rect.centerx) < TILE_SIZE * 2 and \
abs(self.rect.centery - player.rect.centery) < TILE_SIZE * 2:
player.health -= 50
for enemy in enemy_group:
if abs(self.rect.centerx - enemy.rect.centerx) < TILE_SIZE * 2 and \
abs(self.rect.centery - enemy.rect.centery) < TILE_SIZE * 2:
enemy.health -= 50
class Explosion(pygame.sprite.Sprite):
def __init__(self, x, y, scale):
pygame.sprite.Sprite.__init__(self)
self.images = []
for num in range(1, 6):
img = pygame.image.load(f"img/explosion/exp{num}.png").convert_alpha()
img = pygame.transform.scale(img, (int(img.get_width() * scale), (int(img.get_height() * scale))))
self.images.append(img)
self.frame_index = 0
self.image = self.images[self.frame_index]
self.rect = self.image.get_rect()
self.rect.center = (x, y)
self.counter = 0
def update(self):
EXPLOSION_SPEED = 4
# update explosion animation
self.counter += 1
if self.counter >= EXPLOSION_SPEED:
self.counter = 0
self.frame_index += 1
# if animation is complete, then delete the explosion
if self.frame_index >= len(self.images):
self.kill()
else:
self.image = self.images[self.frame_index]
# create sprite groups
enemy_group = pygame.sprite.Group()
bullet_group = pygame.sprite.Group()
grenade_group = pygame.sprite.Group()
explosion_group = pygame.sprite.Group()
item_box_group = pygame.sprite.Group()
decoration_group = pygame.sprite.Group()
water_group = pygame.sprite.Group()
exit_group = pygame.sprite.Group()
# create empty tile list
world_data = []
for row in range(ROWS):
r = [-1] * COLS
world_data.append(r)
# load in level data and create world
with open(f"level{level}_data.csv", newline="") as csvfile:
reader = csv.reader(csvfile, delimiter=",")
for x, row in enumerate(reader):
for y, tile in enumerate(row):
world_data[x][y] = int(tile)
print(world_data)
world = World()
player, health_bar = world.process_data(world_data)
run = True
while run:
clock.tick(fps)
draw_bg()
world.draw()
health_bar.draw(player.health)
# show ammo
draw_text("AMMO:", font, WHITE, 10, 35)
for x in range(player.ammo):
screen.blit(bullet_img, (90 + (x * 10), 40))
# show grenade
draw_text("GRENADES: ", font, WHITE, 10, 65)
for x in range(player.grenades):
screen.blit(grenade_img, (130 + (x * 15), 66))
player.update()
player.draw()
for enemy in enemy_group:
enemy.ai()
enemy.update()
enemy.draw()
# update and draw groups
bullet_group.update()
grenade_group.update()
explosion_group.update()
item_box_group.update()
decoration_group.update()
water_group.update()
exit_group.update()
bullet_group.draw(screen)
grenade_group.draw(screen)
explosion_group.draw(screen)
item_box_group.draw(screen)
decoration_group.draw(screen)
water_group.draw(screen)
exit_group.draw(screen)
# update player actions, 1 is run, 0 = idle, 2 = in air
if player.alive:
# shoot bullet
if shoot:
player.shoot()
elif grenade and grenade_thrown == False and player.grenades > 0:
grenade = Grenade(player.rect.centerx + (0.5 * player.rect.size[0] * player.direction),
player.rect.top, player.direction)
grenade_group.add(grenade)
# reduce grenades
player.grenades -= 1
grenade_thrown = True
if player.in_air:
player.update_action(2)
elif moving_left or moving_right:
player.update_action(1)
else:
player.update_action(0)
screen_scroll = player.move(moving_left, moving_right)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
# keyboard presses
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_a:
moving_left = True
if event.key == pygame.K_d:
moving_right = True
if event.key == pygame.K_SPACE:
shoot = True
if event.key == pygame.K_q:
grenade = True
if event.key == pygame.K_w and player.alive:
player.jump = True
if event.key == pygame.K_ESCAPE:
run = False
# keyboard button released
if event.type == pygame.KEYUP:
if event.key == pygame.K_a:
moving_left = False
if event.key == pygame.K_d:
moving_right = False
if event.key == pygame.K_SPACE:
shoot = False
if event.key == pygame.K_q:
grenade = False
grenade_thrown = False
pygame.display.update()
pygame.quit()
i have looked at this code for days but cant seem to find out the problem exactly. so, the question once again is how to properly arrange the enemies on the screen at their various predefined positions and not directly on top of my player.

I am having trouble with my stat function in my player class

When I shoot at my cement block sprites I have it set so that self.score is self.score += 1 in my player collision function, but when I shoot my cement blocks and destroy them, either 1 or 2 points is added at random to my score. Why? How can I fix this? A clear example is, I shoot at and destroy 2 cement blocks in a row and 1 point is added for each one destroyed which means my score is 2, which is what I want cause I want to add 1 point to my score whenever I destroy a cement block, but then when I shoot and destroy the third cement block, 2 points are added instead of 1 bringing my score to 4 instead of being a score of 3 points.
Github: https://github.com/Enoc-Mena99/AutoPilot
My code:
import random
import pygame
import pygame.freetype
pygame.init()
#screen settings
WIDTH = 1000
HEIGHT = 400
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("AutoPilot")
screen.fill((255, 255, 255))
#fps
FPS = 120
clock = pygame.time.Clock()
#load images
bg = pygame.image.load('background/street.png').convert_alpha() # background
bullets = pygame.image.load('car/bullet.png').convert_alpha()
debris_img = pygame.image.load('debris/cement.png')
#define game variables
shoot = False
#player class
class Player(pygame.sprite.Sprite):
def __init__(self, scale, speed):
pygame.sprite.Sprite.__init__(self)
self.bullet = pygame.image.load('car/bullet.png').convert_alpha()
self.bullet_list = []
self.speed = speed
#self.x = x
#self.y = y
self.moving = True
self.frame = 0
self.flip = False
self.direction = 0
self.score = 0
#load car
self.images = []
img = pygame.image.load('car/car.png').convert_alpha()
img = pygame.transform.scale(img, (int(img.get_width()) * scale, (int(img.get_height()) * scale)))
self.images.append(img)
self.image = self.images[0]
self.rect = self.image.get_rect()
self.update_time = pygame.time.get_ticks()
self.movingLeft = False
self.movingRight = False
self.rect.x = 465
self.rect.y = 325
#draw car to screen
def draw(self):
screen.blit(self.image, (self.rect.centerx, self.rect.centery))
#move car
def move(self):
#reset the movement variables
dx = 0
dy = 0
#moving variables
if self.movingLeft and self.rect.x > 33:
dx -= self.speed
self.flip = True
self.direction = -1
if self.movingRight and self.rect.x < 900:
dx += self.speed
self.flip = False
self.direction = 1
#update rectangle position
self.rect.x += dx
self.rect.y += dy
#shoot
def shoot(self):
bullet = Bullet(self.rect.centerx + 18, self.rect.y + 30, self.direction)
bullet_group.add(bullet)
#check collision
def collision(self, debris_group):
for debris in debris_group:
if pygame.sprite.spritecollide(debris, bullet_group, True):
debris.health -= 1
if debris.health <= 0:
self.score += 1
#player stats
def stats(self):
myfont = pygame.font.SysFont('comicsans', 30)
scoretext = myfont.render("Score: " + str(self.score), 1, (0,0,0))
screen.blit(scoretext, (100,10))
#bullet class
class Bullet(pygame.sprite.Sprite):
def __init__(self, x, y, direction):
pygame.sprite.Sprite.__init__(self)
self.speed = 5
self.image = bullets
self.rect = self.image.get_rect()
self.rect.center = (x,y)
self.direction = direction
def update(self):
self.rect.centery -= self.speed
#check if bullet has gone off screen
if self.rect.centery < 1:
self.kill()
#debris class
class Debris(pygame.sprite.Sprite):
def __init__(self,scale,speed):
pygame.sprite.Sprite.__init__(self)
self.scale = scale
self.x = random.randrange(100,800)
self.speed_y = 10
self.y = 15
self.speed = speed
self.vy = 0
self.on_ground = True
self.move = True
self.health = 4
self.max_health = self.health
self.alive = True
self.velocity = random.randrange(1,2)
self.speed_x = random.randrange(-3,3)
self.moving_down = True
self.is_destroyed = False
#load debris
self.image = debris_img
self.rect = self.image.get_rect()
self.rect.x = random.randrange(100, 800)
self.rect.y = random.randrange(-150, -100)
self.rect.center = (self.x,self.y)
#load explosion
self.img_explosion_00 = pygame.image.load('explosion/0.png').convert_alpha()
self.img_explosion_00 = pygame.transform.scale(self.img_explosion_00, (self.img_explosion_00.get_width() * 2,
self.img_explosion_00.get_height() * 2))
self.img_explosion_01 = pygame.image.load('explosion/1.png').convert_alpha()
self.img_explosion_01 = pygame.transform.scale(self.img_explosion_01, (self.img_explosion_01.get_width() * 2,
self.img_explosion_01.get_height() * 2))
self.img_explosion_02 = pygame.image.load('explosion/2.png').convert_alpha()
self.img_explosion_02 = pygame.transform.scale(self.img_explosion_02, (self.img_explosion_02.get_width() * 2,
self.img_explosion_02.get_height() * 2))
self.img_explosion_03 = pygame.image.load('explosion/3.png').convert_alpha()
self.img_explosion_03 = pygame.transform.scale(self.img_explosion_03, (self.img_explosion_03.get_width() * 2,
self.img_explosion_03.get_height() * 2))
#explosion list
self.anim_explosion = [self.img_explosion_00,
self.img_explosion_01,
self.img_explosion_02,
self.img_explosion_03]
self.anim_index = 0
self.frame_len = 10
#spawn new debris
def spawn_new_debris(self):
self.rect.x = random.randrange(100, 800)
self.rect.y = random.randrange(-150, -100)
self.velocity = random.randrange(1, 2)
self.speed_x = random.randrange(-3, 3)
#respawn debris when they go of the screen
def boundaries(self):
if self.rect.left > WIDTH + 10 or self.rect.right < -10 or self.rect.top > HEIGHT + 10:
self.spawn_new_debris()
#update image
def update(self):
self.rect.y += self.velocity
self.rect.x += self.speed_x
self.boundaries()
if self.health <= 0:
max_index = len(self.anim_explosion) - 1
if self.anim_index > max_index:
self.kill()
else:
if self.frame_len == 0:
self.image = self.anim_explosion[self.anim_index]
self.anim_index += 1
self.frame_len = 10
else:
self.frame_len -= 1
#make debris fall down
def falldown(self):
self.rect.centery += self.velocity
if self.moving_down and self.rect.y > 350:
self.kill()
######################CAR/DEBRIS##########################
player = Player(1,5)
##########################################################
#groups
bullet_group = pygame.sprite.Group()
debris_group = pygame.sprite.Group()
all_sprites = pygame.sprite.Group()
for x in range(50):
d = Debris(1, 5)
debris_group.add(d)
all_sprites.add(d)
#game runs here
run = True
while run:
#draw street
screen.blit(bg, [0, 0])
#update groups
bullet_group.update()
bullet_group.draw(screen)
debris_group.update()
debris_group.draw(screen)
#draw car
player.draw()
player.move()
player.collision(debris_group)
player.stats()
#update all sprites
all_sprites.update()
all_sprites.draw(screen)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
#check if key is down
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
run = False
if event.key == pygame.K_a:
player.movingLeft = True
if event.key == pygame.K_d:
player.movingRight = True
if event.key == pygame.K_SPACE:
player.shoot()
shoot = True
#check if key is up
if event.type == pygame.KEYUP:
if event.key == pygame.K_a:
player.movingLeft = False
if event.key == pygame.K_d:
player.movingRight = False
#update the display
pygame.display.update()
pygame.display.flip()
clock.tick(FPS)
pygame.quit()
Do not count debris objects with healt <= 0:
class Player(pygame.sprite.Sprite):
# [...]
def collision(self, debris_group):
for debris in debris_group:
# if health > 0 and collision:
if debris.health > 0 and pygame.sprite.spritecollide(debris, bullet_group, True):
debris.health -= 1
if debris.health <= 0:
self.score += 1

Bullets Are not Drawing on Simple Pygame

I am trying to create a simple bullet function in which am shooting bullets vertically. No bullets seem to be drawing in the program Help would be much appreciated.
class Bullet(pg.sprite.Sprite):
def __init__(self):
super().__init__()
pygame.sprite.Sprite.__init__(self)
self.image = pg.image.load(os.path.join(path, 'img', 'bullet.png'))
self.image = pygame.Surface([4, 10])
self.image.fill(RED)
self.rect = self.image.get_rect()
def update(self):
self.rect.y -= 5 enter code here
elif e.type == pg.KEYDOWN and e.key == pg.K_SPACE:
# Fire a bullet if the user clicks the space button
bullet = Bullet()
# Set the bullet so it is where the player is
bullet.rect.x = player.rect.x
bullet.rect.y = player.rect.y
# Add the bullet to the lists
cars_group.add(bullet)
bullet_list.add(bullet)
# Calculate mechanics for each bullet
for bullet in bullet_list:
# See if it hit a block
block_hit_list = pygame.sprite.spritecollide(bullet, cars_group, True)
# For each block hit, remove the bullet and add to the score
for block in block_hit_list:
bullet_list.remove(bullet)
cars_group.remove(bullet)
disclosure this isnt fully my code
Full code here:
import pygame as pg
import pygame.freetype
import random
import os
import math
os.environ['SDL_VIDEO_CENTERED'] = '1'
path = os.path.dirname(os.path.abspath(__file__))
record_file = os.path.join(path, 'Record', 'record.txt')
try:
with open(record_file, 'x') as f:
f.write(str(0))
except (BaseException, OSError):
pass
SIZE = WIDTH, HEIGHT = 800, 600
GREY = (128, 128, 128)
GREEN = (0, 128, 0)
WHITE = (200, 200, 200)
RED = (230, 0, 0)
rgb = [0, 250, 0]
block = False
pause = [False, True]
count = [0]
car_accident = 0
level = 40
start = 255
blink = 0
hit_old = None
play, out = None, None
def icon():
size, text = 32, '\u0056\u004F'
sur = pg.Surface((size, size), pg.SRCALPHA)
pg.draw.circle(
sur, '#44475a59', (size // 2, size // 2), size // 2)
font_text = pg.freetype.SysFont('Arial', 16, True)
rect = font_text.get_rect(text)
x, y = (size - rect.width) // 2, (size - rect.height) // 2
font_text.render_to(sur, (x, y), text, fgcolor='#ff0000')
pg.display.set_icon(sur)
pg.init()
icon()
pg.display.set_caption('Rally')
screen = pg.display.set_mode(SIZE)
FPS = 120
clock = pg.time.Clock()
font = pygame.freetype.Font(os.path.join(path, 'font', 'seguisym.ttf'), 30)
cars = [pg.image.load(os.path.join(path, 'img', 'car1.png')),
pg.image.load(os.path.join(path, 'img', 'car2.png')),
pg.image.load(os.path.join(path, 'img', 'car3.png'))]
alarm = [pg.image.load(os.path.join(path, 'alarm', '1.png')),
pg.image.load(os.path.join(path, 'alarm', '2.png'))]
sound_car_accident = pg.mixer.Sound(os.path.join(path, 'sound', 'udar.wav'))
sound_canister = pg.mixer.Sound(os.path.join(path, 'sound', 'canister.wav'))
sound_accident = pg.mixer.Sound(os.path.join(path, 'sound', 'accident.wav'))
button_start = pg.image.load(os.path.join(path, 'img', 'btn_play.png'))
button_start_rect = button_start.get_rect(center=(WIDTH // 2, HEIGHT // 2 - 100))
button_stop = pg.image.load(os.path.join(path, 'img', 'btn_exit.png'))
button_stop_rect = button_stop.get_rect(center=(WIDTH // 2, HEIGHT // 2 + 100))
fuel_image = pg.image.load(os.path.join(path, 'img', 'fuel.png'))
canister_image = pg.image.load(os.path.join(path, 'img', 'canister.png'))
water_image = pg.image.load(os.path.join(path, 'img', 'water.png'))
bullet_image = pg.image.load(os.path.join(path, 'img', 'bullet.png'))
u1_event = pg.USEREVENT + 1
pg.time.set_timer(u1_event, random.randrange(6000, 26001, 4000))
u2_event = pg.USEREVENT + 2
pg.time.set_timer(u2_event, random.randrange(13000, 28001, 5000))
class Player(pg.sprite.Sprite):
def __init__(self):
pg.sprite.Sprite.__init__(self)
self.image = pg.image.load(os.path.join(path, 'img', 'car4.png'))
self.orig_image = self.image
self.angle = 0
self.speed = 2
self.acceleration = 0.02
self.rect = self.image.get_rect(center=(WIDTH - 20, HEIGHT - 70))
self.position = pg.math.Vector2()
self.velocity = pg.math.Vector2()
self.vx = 0 # velocity.x for speedometer
def update(self):
self.image = pg.transform.rotate(self.orig_image, self.angle)
self.position += self.velocity
self.rect = self.image.get_rect(center=self.position)
keys = pg.key.get_pressed()
if keys[pg.K_RIGHT]:
self.velocity.x = self.speed
self.angle -= 1
self.vx -= self.acceleration
if self.angle < -25:
self.angle = -25
elif keys[pg.K_LEFT]:
self.velocity.x = -self.speed
self.angle += 1
self.vx -= self.acceleration
if self.angle > 25:
self.angle = 25
else:
self.vx += self.acceleration if self.vx < 0 else 0
self.velocity.x = 0
if self.angle < 0:
self.angle += 1
elif self.angle > 0:
self.angle -= 1
if keys[pg.K_UP]:
self.velocity.y -= self.acceleration
if self.velocity.y < -self.speed:
self.velocity.y = -self.speed
elif keys[pg.K_DOWN]:
self.velocity.y += self.acceleration
if self.velocity.y > self.speed:
self.velocity.y = self.speed
else:
if self.velocity.y < 0:
self.velocity.y += self.acceleration
if self.velocity.y > 0:
self.velocity.y = 0
elif self.velocity.y > 0:
self.velocity.y -= self.acceleration
if self.velocity.y < 0:
self.velocity.y = 0
def for_speedometer(self):
if self.vx <= -0.4:
self.vx = -0.4 # left-right speedometer max
if self.velocity.y < self.vx or self.velocity.y > 0:
self.vx = self.velocity.y
if self.vx >= 1.04:
self.vx = 1.04 # speedometer min for speed=2
return self.vx
class Alarm(pg.sprite.Sprite):
def __init__(self):
pg.sprite.Sprite.__init__(self)
self.images = alarm
self.index = 0
self.range = len(self.images)
self.image = self.images[self.index]
self.rect = self.image.get_rect()
self.speed = 1
def update(self):
self.index += 0.02
self.image = self.images[int(self.index % self.range)]
self.rect.y += self.speed
if self.rect.top > HEIGHT:
self.kill()
class Car(pg.sprite.Sprite):
def __init__(self, x, y, img):
pg.sprite.Sprite.__init__(self)
if img == fuel_image:
self.image = img
self.speed = 0
elif img == canister_image or img == water_image:
self.image = img
self.speed = 1
else:
self.image = pg.transform.flip(img, False, True)
self.speed = random.randint(2, 3)
self.rect = self.image.get_rect(center=(x, y))
def update(self):
self.rect.y += self.speed
if self.rect.top >= HEIGHT:
if self is canister or self is water:
self.kill()
else:
if 40 < player.rect.centerx < WIDTH - 40 \
and player.rect.top < HEIGHT and player.rect.bottom > 0:
count[0] += 1
list_x.remove(self.rect.centerx)
while True:
self.rect.centerx = random.randrange(80, WIDTH, 80)
if self.rect.centerx in list_x:
continue
else:
list_x.append(self.rect.centerx)
self.speed = random.randint(2, 3)
self.rect.bottom = 0
break
class Road(pg.sprite.Sprite):
def __init__(self, x, y):
pg.sprite.Sprite.__init__(self)
self.image = pg.Surface(screen.get_size())
self.image.fill(GREY)
pg.draw.line(self.image, GREEN, (20, 0), (20, 600), 40)
pg.draw.line(self.image, GREEN, (780, 0), (780, 600), 40)
for xx in range(10):
for yy in range(10):
pg.draw.line(
self.image, WHITE,
(40 + xx * 80, 0 if xx == 0 or xx == 9 else 10 + yy * 60),
(40 + xx * 80, 600 if xx == 0 or xx == 9 else 50 + yy * 60), 5)
self.rect = self.image.get_rect(topleft=(x, y))
self.speed = 1
def update(self):
self.rect.y += self.speed
if self.rect.top >= HEIGHT:
self.rect.bottom = 0
class Volume(pg.sprite.Sprite):
def __init__(self, x, y):
pg.sprite.Sprite.__init__(self)
self.image = pg.Surface((20, 140), pg.SRCALPHA)
self.rect = self.image.get_rect(center=(x, y))
self.radius = 10
self.x = self.y = self.radius
self.color_circle = (0, 255, 0, 128)
self.color_rect = (0, 180, 0, 128)
self.color_text = (255, 255, 255)
self.alpha = 255
self.volume = 1
def update(self):
self.image.set_alpha(self.alpha)
pg.draw.rect(
self.image, self.color_rect, [0, 0, *self.rect[2:]],
border_radius=self.radius)
pg.draw.circle(self.image, self.color_circle, (self.x, self.y), self.radius)
text = str(round(self.volume * 100))
text_rect = font.get_rect(text, size=11)
font.render_to(
self.image, (self.x - text_rect[2] / 2., self.y - text_rect[3] / 2.), text,
self.color_text, rotation=0, size=11)
sp = "\U0001F507" if self.volume == 0 else "\U0001F508" if self.volume < 0.2 \
else "\U0001F509" if self.volume < 0.7 else "\U0001F50A"
font.render_to(
screen, (self.rect.x, self.rect.y - font.size), sp, [*WHITE, self.alpha])
def render(self, e_buttons, e_pos):
if self.rect.left < e_pos[0] < self.rect.right and \
self.rect.top < e_pos[1] < self.rect.bottom and \
e_buttons:
self.y = abs(self.rect.top - e_pos[1])
if self.y > self.rect.h - self.radius:
self.y = self.rect.h - self.radius
elif self.y < self.radius:
self.y = self.radius
self.volume = (100 - (self.y - self.radius) / 1.2) / 100.
sound_car_accident.set_volume(self.volume)
sound_canister.set_volume(self.volume)
sound_accident.set_volume(self.volume)
class Speedometer(pg.sprite.Sprite):
def __init__(self):
pg.sprite.Sprite.__init__(self)
w, h = 150, 150
self.radius = 140
self.image = pg.Surface((w, h), pg.SRCALPHA)
self.rect = self.image.get_rect(bottomright=(WIDTH, HEIGHT))
font.render_to(self.image, (w - 50, h - 50), 'km/h', WHITE, size=20)
for deg in range(5, 84, 6):
length = 18 if deg == 5 or deg == 23 or deg == 41 or deg == 59 or deg == 77 else 10
cos = math.cos(math.radians(deg))
sin = math.sin(math.radians(deg))
pg.draw.line(
self.image, WHITE,
(w - self.radius * cos, h - self.radius * sin),
(w - (self.radius - length) * cos, h - (self.radius - length) * sin), 2)
for value, deg in enumerate(range(9, 78, 17)):
cos = math.cos(math.radians(deg))
sin = math.sin(math.radians(deg))
font.render_to(self.image, (
round(w - (self.radius - 30) * cos), round(h - (self.radius - 30) * sin)),
str(value * 100), WHITE, size=15)
def render(self):
s = 30 - player.for_speedometer() * 25 # from 4 to 80
pg.draw.line(
screen, RED, self.rect.bottomright,
(self.rect.right - (self.radius - 10) * math.cos(math.radians(s)),
self.rect.bottom - (self.radius - 10) * math.sin(math.radians(s))), 4)
pg.draw.circle(screen, WHITE, self.rect.bottomright, 25)
vol.update()
class Bullet(pg.sprite.Sprite):
def __init__(self):
super().__init__()
pygame.sprite.Sprite.__init__(self)
self.image = pg.image.load(os.path.join(path, 'img', 'bullet.png'))
self.image = pygame.Surface([4, 10])
self.image.fill(RED)
self.rect = self.image.get_rect()
def update(self):
self.rect.y -= 5
all_sprite = pg.sprite.LayeredUpdates()
cars_group = pg.sprite.Group()
canister_group = pg.sprite.Group()
bullet_list = pg.sprite.Group()
for r in range(2):
bg = Road(x=0, y=0)
all_sprite.add(Road(0, 0 if r == 0 else -HEIGHT), layer=0)
speedometer = Speedometer()
all_sprite.add(speedometer, layer=0)
player = Player()
list_x = []
n = 0
while n < 6:
car_x = random.randrange(80, WIDTH, 80)
if car_x in list_x:
continue
else:
list_x.append(car_x)
cars_group.add(Car(car_x, random.randint(
-cars[0].get_height() * 3, -cars[0].get_height()),
cars[n] if n < 3 else random.choice(cars)))
n += 1
fuel = Car(WIDTH - 80, 40, fuel_image)
canister = Car(0, 0, canister_image)
water = Car(0, 0, water_image)
vol = Volume(20, HEIGHT - 80)
all_sprite.add(*cars_group, layer=1)
all_sprite.add(player, layer=3)
all_sprite.add(fuel, layer=4)
all_sprite.add(vol, layer=4)
def my_record():
with open(record_file, 'r+') as d:
record = d.read()
if count[0] > int(record):
record = str(count[0])
d.seek(0)
d.truncate()
d.write(record)
return record
def home_screen(b):
screen.blit(all_sprite.get_sprite(0).image, (0, 0))
screen.blit(speedometer.image, speedometer.rect)
button_start.set_alpha(start)
button_stop.set_alpha(start)
screen.blit(button_start, button_start_rect)
screen.blit(button_stop, button_stop_rect)
font.render_to(screen, (48, 10), f'Record: {rec}', [
*RED, 255 if count[0] <= record_old else 255 if int(b) % 2 else 0], size=24)
font.render_to(screen, (48, 40), f'Points: {count[0]}', RED, size=24)
font.render_to(screen, (48, 70), f'Accidents: {car_accident}', RED, size=24)
vol.update()
screen.blit(vol.image, vol.rect)
rec = my_record()
record_old = int(rec)
game = True
while game:
for e in pg.event.get():
if e.type == pg.QUIT or e.type == pg.KEYDOWN and e.key == pg.K_ESCAPE:
game = False
elif e.type == pg.KEYDOWN and e.key == pg.K_p and start == 0:
pause.reverse()
if pause[0]:
pg.mouse.set_visible(True)
vol.alpha = 255
else:
pg.mouse.set_visible(False)
vol.alpha = 0
elif e.type == pg.MOUSEMOTION and (start == 255 or pause[0]):
vol.render(e.buttons[0], e.pos)
elif e.type == pg.KEYDOWN and e.key == pg.K_SPACE:
# Fire a bullet if the user clicks the space button
bullet = Bullet()
# Set the bullet so it is where the player is
bullet.rect.x = player.rect.x
bullet.rect.y = player.rect.y
# Add the bullet to the lists
cars_group.add(bullet)
bullet_list.add(bullet)
elif e.type == pg.MOUSEBUTTONDOWN and start == 255:
if e.button == 1:
if button_start_rect.collidepoint(e.pos):
player.angle = 0
player.velocity.x, player.velocity.y = 0, 0
player.position.x, player.position.y = WIDTH - 400, HEIGHT - 70
player.update()
all_sprite.remove_sprites_of_layer(2)
water.kill()
canister.kill()
for cr in cars_group:
cr.speed = random.randint(2, 3)
cr.rect.bottom = 0
level = 40
car_accident = 0
count[0] = 0
start -= 1
record_old = int(rec)
pg.mouse.set_visible(False)
elif button_stop_rect.collidepoint(e.pos):
game = False
elif e.type == u1_event and not pause[0] and not all_sprite.has(water): # water.alive():
all_sprite.add(water, layer=0)
water.rect.center = \
random.randrange(80, WIDTH, 80), -water.rect.h
timer1 = random.randrange(6000, 26001, 4000)
pg.time.set_timer(u1_event, timer1)
elif e.type == u2_event and not pause[0] and not canister_group.has(canister):
canister_group.add(canister)
all_sprite.add(canister, layer=0)
canister.rect.center = \
random.randrange(80, WIDTH, 80), -canister.rect.h
timer2 = random.randrange(13000, 28001, 5000)
pg.time.set_timer(u2_event, timer2)
# Calculate mechanics for each bullet
for bullet in bullet_list:
# See if it hit a block
block_hit_list = pygame.sprite.spritecollide(bullet, cars_group, True)
# For each block hit, remove the bullet and add to the score
for block in block_hit_list:
bullet_list.remove(bullet)
cars_group.remove(bullet)
hit = pg.sprite.spritecollideany(player, cars_group) # hit -> sprite car
if hit and hit.speed != 1:
player.position.x += 50 * random.randrange(-1, 2, 2)
player.angle = 50 * random.randrange(-1, 2, 2)
hit.speed = 1
car_alarm = Alarm()
all_sprite.add(car_alarm, layer=2)
car_alarm.rect.center = hit.rect.center
car_accident += 1
if car_accident > 10:
car_accident = 10
sound_car_accident.play()
if pg.sprite.spritecollide(player, canister_group, True):
level = 40
sound_canister.play()
if pg.sprite.collide_rect(player, water):
if not block:
player.angle = random.randint(60, 90) * random.randrange(-1, 2, 2)
sound_accident.play()
block = True
else:
block = False
if start > 0:
home_screen(blink)
blink = 0 if blink > 99 else blink + .02
if start != 255:
start -= 1
vol.alpha = start
else:
if not pause[0]:
level -= .01
if level < 0 or car_accident > 9:
rec = my_record()
pg.mouse.set_visible(True)
vol.alpha = start
elif level < 10:
rgb[:2] = 250, 0
elif level < 20:
rgb[0] = 250
else:
rgb[:2] = 0, 250
all_sprite.update()
else:
vol.update()
all_sprite.draw(screen)
pg.draw.rect(
screen, rgb,
(fuel.rect.left + 10, fuel.rect.bottom - level - 8, 21, level))
font.render_to(screen, (48, 10), f'accidents: {car_accident}', GREEN, size=24)
font.render_to(screen, (48, HEIGHT - 30), f'{count[0]}', GREEN, size=24)
speedometer.render() # speedometer
pg.display.update()
clock.tick(FPS)
pg.display.set_caption(f'Rally FPS: {int(clock.get_fps())}')
pygame.quit()
# pg.image.save(screen, 'road.jpg')
aos;dfihj ;aslkdjfh ;salkj
askl;fjas;lkfjd
a sdlfkj as;ldkfj as
asld;kj f;laskjd
asl;kjdf;lasjk f
sdla ;fjkas;ldkf j
asdlf jkasl;dkf j
asld flasdkjf ;
You are drawing all the Sprites in the all_sprites Group:
all_sprite.draw(screen)
However, t he bullets are not in this Group Either add the bullets to the all_sprites Group or draw the Sprites contained in the bullet_list Group.
Either
elif e.type == pg.KEYDOWN and e.key == pg.K_SPACE:
# [...]
bullet_list.add(bullet)
bullet_list.draw(screen)
or
bullet_list.draw(screen)
Remove the bullets form all Groups using kill():
for bullet in bullet_list:
# See if it hit a block
block_hit_list = pygame.sprite.spritecollide(bullet, cars_group, True)
# For each block hit, remove the bullet and add to the score
for block in block_hit_list:
bullet.kill()

Pygame Game results in Segmentation Fault(pygame parachute)

If you play the game and win, clicking on the screen will cause the game to play again. On the second play, the game segmentation faults after a second or two.
This code is for an intro to coding class and many others have coded this game successfully. I don't understand what is the problem here.
Help!
import sys
import os
import pygame
import random
import math
#Force static position of screen
os.environ ['SDL_VIDEO_CENTERED'] = '1'
#constants
BLACK = (0,0,0)
WHITE = (255, 255, 255)
SHIP_WIDTH = 13
SHIP_HEIGHT = 13
SIZE = WIDTH, HEIGHT = 920, 570
TOP_BUFFER = 50
PILL_HEIGHT = 30
PILL_WIDTH = 10
YELLOW = (157, 185, 45)
RED = (185, 45, 45)
BLUE = (45, 115, 185)
GREEN = (5, 94, 16)
#Runs imported module
pygame.init()
class Text:
def __init__(self, size, text, color, xpos, ypos):
self.font = pygame.font.SysFont("Britannic Bold", size)
self.image = self.font.render(text, 1, color)
self.rect = self.image.get_rect()
self.rect = self.rect.move(xpos, ypos)
class Ship(pygame.sprite.Sprite):
def __init__ (self, x, y, side):
pygame.sprite.Sprite.__init__(self)
self.density = SHIP_HEIGHT * SHIP_WIDTH
self.speed = 10
self.image = pygame.Surface((math.sqrt(self.density), math.sqrt(self.density))).convert()
self.rect = self.image.get_rect()
self.rect = self.rect.move(x, y)
self.type = side
self.score = Text(30, str(self.density - 169), BLACK, WIDTH / 4 , HEIGHT/ 17)
self.score_2 = Text(30, str(self.density - 169), BLACK, WIDTH * .75, HEIGHT / 17)
def update(self, pill_group):
key = pygame.key.get_pressed()
if self.type == "left":
if key[pygame.K_w]:
self.rect.y -= self.speed
if key[pygame.K_s]:
self.rect.y += self.speed
if key[pygame.K_a]:
self.rect.x -= self.speed
if key[pygame.K_d]:
self.rect.x += self.speed
if self.type == "left":
#Boundary Conditions
if self.rect.right > WIDTH/2:
self.rect.right = WIDTH/2
if self.rect.left < 0:
self.rect.left = 0
if self.rect.top < 50:
self.rect.top = 50
if self.rect.bottom > 570:
self.rect.bottom = 570
elif self.type == "right":
if key[pygame.K_UP]:
self.rect.y -= self.speed
if key[pygame.K_DOWN]:
self.rect.y += self.speed
if key[pygame.K_LEFT]:
self.rect.x -= self.speed
if key[pygame.K_RIGHT]:
self.rect.x += self.speed
# Ship 2 boundary conditions
if self.rect.right > WIDTH:
self.rect.right = WIDTH
if self.rect.top < TOP_BUFFER:
self.rect.top = TOP_BUFFER
if self.rect.left < WIDTH/2:
self.rect.left = WIDTH/2
if self.rect.bottom > HEIGHT:
self.rect.bottom = HEIGHT
collisions = pygame.sprite.spritecollide(self, pill_group, True)
for p in collisions:
self.density += p.density * 50
print(self.density)
self.score.image = self.score.font.render(str(self.density - 169), 1, BLACK)
self.score_2.image = self.score.font.render(str(self.density), 1, BLACK)
##if self.density > 500:
##self.play == False
self.rect.width = self.rect.height = math.sqrt(self.density)
self.image = pygame.transform.scale(self.image, (self.rect.width, self.rect.height))
class Pill(pygame.sprite.Sprite):
def __init__(self, xpos, density):
pygame.sprite.Sprite.__init__(self)
self.density = density
self.speed = 3
self.image = pygame.Surface((PILL_WIDTH, PILL_HEIGHT)).convert()
self.image.fill(self.set_color())
self.rect = pygame.Rect(xpos, -PILL_HEIGHT, 10, 30)
self.rect = self.image.get_rect()
self.rect = self.rect.move(xpos, HEIGHT/15)
def set_color(self):
if self.density == 1:
return YELLOW
elif self.density == 2:
return RED
elif self.density == 3:
return BLUE
elif self.density == 4:
return GREEN
def update(self):
self.rect.y += self.speed
if self.rect.y > HEIGHT:
self.kill()
def main():
#Initialize Local Vars
size = width, height = 920, 570
fps = 30
LeftWins = Text(30, "Left Ship Wins!", BLACK, WIDTH / 2.5, HEIGHT / 2)
RightWins = Text(30, "Right Ship Wins!", BLACK, WIDTH / 2.5, HEIGHT / 2)
Winner = Text (30, "Click here to play again", BLACK, WIDTH / 2.6, HEIGHT * .75)
pygame.display.set_caption('Density')
screen = pygame.display.set_mode(SIZE, pygame.SRCALPHA)
clock = pygame.time.Clock()
play = True
loop_counter = 0
vertical = pygame.Surface((1, HEIGHT - TOP_BUFFER)).convert()
horizontal = pygame.Surface((WIDTH, 1)).convert()
#Create Game Objects
ship_left = Ship(WIDTH/4 - SHIP_WIDTH/2, HEIGHT - (4 * SHIP_HEIGHT), "left")
ship_right = Ship((WIDTH * 3) / 4 - SHIP_WIDTH / 2, HEIGHT - (4 * SHIP_HEIGHT), "right")
#Create Groups
ship_group = pygame.sprite.Group()
ship_group.add(ship_left, ship_right)
pill_group = pygame.sprite.Group()
#play = True
outro = True
while True:
#Gameplay
while play:
for event in pygame.event.get():
if event.type == pygame.QUIT: sys.exit()
if loop_counter % 10 == 0:
pill = Pill(random.randrange(0, (WIDTH/2) - PILL_WIDTH), int(random.choice('1111111111111111111122222334')))
pill2 = Pill(random.randrange((WIDTH/2) + PILL_WIDTH, WIDTH - PILL_WIDTH), int(random.choice('1111111111111111111122222334')))
pill_group.add(pill)
pill_group.add(pill2)
#Update Groups
ship_group.update(pill_group)
pill_group.update()
#Draw/Blit Groups
screen.fill(WHITE)
screen.blit(ship_left.score.image, ship_left.score.rect)
screen.blit(ship_right.score_2.image, ship_right.score_2.rect)
ship_group.draw(screen)
pill_group.draw(screen)
screen.blit(vertical, (WIDTH/2, TOP_BUFFER))
screen.blit(horizontal, (0, TOP_BUFFER))
#60 / second one pill / 10 iterations
loop_counter += 1
#Limits frames per iteration of while loop
clock.tick(60)
# Writes to main surface
pygame.display.flip()
if (ship_left.density >= 500 or ship_right.density >= 500):
play = False
while outro:
for event in pygame.event.get():
if event.type == pygame.QUIT: sys.exit()
if event.type == pygame.MOUSEBUTTONDOWN or pygame.key.get_pressed()[pygame.K_RETURN != 0]:
outro = False
play = True
ship_left.density = 0
ship_right.density = 0
for p in pill_group:
p.kill()
ship_left = Ship(WIDTH / 4 - SHIP_WIDTH / 2, HEIGHT - (4 * SHIP_HEIGHT), "left")
ship_right = Ship((WIDTH * 3) / 4 - SHIP_WIDTH / 2, HEIGHT - (4 * SHIP_HEIGHT), "right")
screen.blit(ship_left.image, ship_left.rect)
screen.blit(ship_right.image, ship_right.rect)
#Draw/Blit Groups
screen.fill(WHITE)
if (ship_left.density >= 500):
screen.blit(LeftWins.image, LeftWins.rect)
screen.blit(Winner.image, Winner.rect)
if (ship_right.density >= 500):
screen.blit(RightWins.image, RightWins.rect)
screen.blit(Winner.image, Winner.rect)
#Limits frames per iteration of while loop
clock.tick(60)
# Writes to main surface
pygame.display.flip()
if __name__ == "__main__":
main()
One way to solve this (but arguably not the best one) is to move the setup code inside the while True loop and ditch the reset code in while outro:
def main():
# The setup code from here ...
while True:
# Goes here
#Gameplay
while play:
# The Gameplay code
while outro:
for event in pygame.event.get():
if event.type == pygame.QUIT: sys.exit()
if event.type == pygame.MOUSEBUTTONDOWN or pygame.key.get_pressed()[pygame.K_RETURN != 0]:
outro = False
#Draw/Blit Groups
screen.fill(WHITE)
# The reset of outro

How to make a sprite rotate to face the mouse? [duplicate]

This question already has answers here:
How do I make my player rotate towards mouse position?
(1 answer)
How to rotate a triangle to a certain angle in pygame?
(1 answer)
How do I rotate an image around its center using Pygame?
(6 answers)
Closed 2 years ago.
After several hours of complete utter chaos, I still haven't found a solution to rotating a sprite to face the mouse position. I've implemented several examples from other post, the links are below, but none of them seem to be effective. Any help with my problem, would be very appreciated :)
Pygame Making A Sprite Face The Mouse
https://ubuntuforums.org/showthread.php?t=1823825
https://gamedev.stackexchange.com/questions/132163/how-can-i-make-the-player-look-to-the-mouse-direction-pygame-2d
Original Code:
class Player(pygame.sprite.Sprite):
def __init__(self, game, x, y):
pygame.sprite.Sprite.__init__(self)
self.game = game
sprite_sheet = Spritesheet("Sprites/ships_spritesheet.png")
image = sprite_sheet.get_image(204, 115, 66, 113)
self.image = pygame.transform.flip(image, False, True)
self.orig_img = self.image
self.rect = self.image.get_rect()
self.pos = vec(x, y)
self.vel = vec(0, 0)
self.health = PLAYER_HEALTH
def update(self):
self.rotate()
self.pos += self.vel
self.rect.x = self.pos.x
self.collide_with_tiles(self.game.obstacle_list, "x")
self.rect.y = self.pos.y
self.collide_with_tiles(self.game.obstacle_list, "y")
def rotate(self):
mouse_x, mouse_y = pygame.mouse.get_pos()
rel_x, rel_y = mouse_x - self.rect.x, mouse_y - self.rect.y
angle = (180 / math.pi) * -math.atan2(rel_y, rel_x)
self.image = pygame.transform.rotate(self.orig_img, int(angle))
self.rect = self.image.get_rect(center=self.pos)
New Code:
class Player(pygame.sprite.Sprite):
def __init__(self, game, pos):
pygame.sprite.Sprite.__init__(self)
self.game = game
sprite_sheet = Spritesheet("Sprites/ships_spritesheet.png")
image = sprite_sheet.get_image(204, 115, 66, 113)
self.image = pygame.transform.flip(image, False, True)
self.orig_img = self.image
self.rect = self.image.get_rect(center=pos)
self.pos = vec(pos)
self.vel = vec(0, 0)
self.health = PLAYER_HEALTH
def update(self):
self.rotate()
self.pos += self.vel
self.rect.centerx = self.pos.x
#self.rect.x = self.pos.x
self.collide_with_tiles(self.game.obstacle_list, "x")
self.rect.centery = self.pos.y
#self.rect.y = self.pos.y
self.collide_with_tiles(self.game.obstacle_list, "y")
self.vel = vec(0, 0)
def rotate(self):
mouse_pos = pygame.mouse.get_pos()
rel_x, rel_y = mouse_pos - self.pos
angle = -math.degrees(math.atan2(rel_y, rel_x))
self.image = pygame.transform.rotate(self.orig_img, angle)
self.rect = self.image.get_rect(center=self.rect.center)
def collide_with_tiles(self, group, dir):
if dir == "x":
hits = pygame.sprite.spritecollide(self, group, False)
if hits:
if self.vel.x > 0:
self.rect.right = hits[0].rect.left
if self.vel.x < 0:
self.rect.left = hits[0].rect.right
self.pos.x = self.rect.centerx
if dir == "y":
hits = pygame.sprite.spritecollide(self, group, False)
if hits:
if self.vel.y > 0:
self.rect.bottom = hits[0].rect.top
if self.vel.y < 0:
self.rect.top = hits[0].rect.bottom
self.pos.y = self.rect.centery
My Game Class
import pygame, pytmx, sys, os
from Settings import *
from Obstacle import *
from Player import *
from Camera import *
from TiledMap import *
from MainMenu import *
from PauseMenu import *
from OptionsMenu import *
from HUD import *
class Game:
def __init__(self):
pygame.init()
pygame.mixer.init()
os.environ['SDL_VIDEO_CENTERED'] = '1'
pygame.display.set_caption(GAME_TITLE)
self.window = pygame.display.set_mode((WINDOW_WIDTH, WINDOW_HEIGHT))
self.clock = pygame.time.Clock()
self.click_sound = pygame.mixer.Sound("Sounds/click1.ogg")
self.main_menu = MainMenu(self, self.window)
self.obstacle_list = pygame.sprite.Group()
self.island_boundary_list = pygame.sprite.Group()
self.pause_menu = PauseMenu(self.window)
self.options_menu = OptionsMenu(self.window)
self.hud = HUD()
self.display_pause_menu = False
self.display_options_menu = False
self.display_main_menu = True
def get_map(self):
map_dir = TiledMap("Sprites/Maps/map_01.tmx")
self.map = map_dir.generate_map()
self.map_rect = self.map.get_rect()
for tile_obj in map_dir.tmxdata.objects:
if tile_obj.name == "Obstacle":
obstacle = Obstacle(self, tile_obj.x, tile_obj.y, 64, 64)
self.obstacle_list.add(obstacle)
if tile_obj.name == "PLAYER":
self.player = Player(self, (tile_obj.x, tile_obj.y))
def game_loop(self):
self.get_map()
self.camera = Camera(5120, 5120)
while True:
self.clock.tick(FPS)
self.game_events()
if not self.display_pause_menu and not self.display_options_menu and not self.display_main_menu:
self.update_game()
self.draw_game()
def game_events(self):
for event in pygame.event.get():
if event.type == pygame.QUIT:
self.run_game = False
pygame.quit()
sys.exit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_p and not self.display_options_menu:
self.display_pause_menu = not self.display_pause_menu
if event.key == pygame.K_o and not self.display_pause_menu:
self.display_options_menu = not self.display_options_menu
if event.type == pygame.MOUSEBUTTONDOWN and self.display_main_menu:
x, y = event.pos
self.click_sound.play()
if self.main_menu.play_button.collidepoint(x, y):
self.display_main_menu = False
if self.main_menu.credits_button.collidepoint(x, y):
pass
if self.main_menu.exit_button.collidepoint(x, y):
pygame.quit()
sys.exit()
if event.type == pygame.MOUSEBUTTONDOWN and self.display_pause_menu:
x, y = event.pos
self.click_sound.play()
if self.pause_menu.pause_resume_button.collidepoint(x, y) or self.pause_menu.pause_x_button.collidepoint(x, y):
self.display_pause_menu = False
if self.pause_menu.pause_options_button.collidepoint(x, y):
self.display_pause_menu = False
self.display_options_menu = True
if self.pause_menu.pause_quit_button.collidepoint(x, y):
pygame.quit()
sys.exit()
if event.type == pygame.MOUSEBUTTONDOWN and self.display_options_menu:
x, y = event.pos
self.click_sound.play()
if self.options_menu.options_x_button.collidepoint(x, y):
self.display_options_menu = False
if self.options_menu.options_reset_button.collidepoint(x, y):
#reset options to original options if modified
pass
if self.options_menu.options_home_button.collidepoint(x, y):
self.display_options_menu = False
self.display_main_menu = True
if self.options_menu.options_ok_button.collidepoint(x, y):
#save settings
self.display_options_menu = False
mouse_x, mouse_y = pygame.mouse.get_pos()
if mouse_x > self.main_menu.play_button.x and mouse_x < self.main_menu.play_button.x + self.main_menu.play_button.width and mouse_y > self.main_menu.play_button.y and mouse_y < self.main_menu.play_button.y + self.main_menu.play_button.height:
self.main_menu.img_id = 1
elif mouse_x > self.main_menu.credits_button.x and mouse_x < self.main_menu.credits_button.x + self.main_menu.credits_button.width and mouse_y > self.main_menu.credits_button.y and mouse_y < self.main_menu.credits_button.y + self.main_menu.credits_button.height:
self.main_menu.img_id = 2
elif mouse_x > self.main_menu.exit_button.x and mouse_x < self.main_menu.exit_button.x + self.main_menu.exit_button.width and mouse_y > self.main_menu.exit_button.y and mouse_y < self.main_menu.exit_button.y + self.main_menu.exit_button.height:
self.main_menu.img_id = 3
else:
self.main_menu.img_id = 0
if mouse_x > self.pause_menu.pause_resume_button.x and mouse_x < self.pause_menu.pause_resume_button.x + self.pause_menu.pause_resume_button.width and mouse_y > self.pause_menu.pause_resume_button.y and mouse_y < self.pause_menu.pause_resume_button.y + self.pause_menu.pause_resume_button.height:
self.pause_menu.img_id = 1
elif mouse_x > self.pause_menu.pause_x_button.x and mouse_x < self.pause_menu.pause_x_button.x + self.pause_menu.pause_x_button.width and mouse_y > self.pause_menu.pause_x_button.y and mouse_y < self.pause_menu.pause_x_button.y + self.pause_menu.pause_x_button.height:
self.pause_menu.img_id = 2
elif mouse_x > self.pause_menu.pause_options_button.x and mouse_x < self.pause_menu.pause_options_button.x + self.pause_menu.pause_options_button.width and mouse_y > self.pause_menu.pause_options_button.y and mouse_y < self.pause_menu.pause_options_button.y + self.pause_menu.pause_options_button.height:
self.pause_menu.img_id = 3
elif mouse_x > self.pause_menu.pause_quit_button.x and mouse_x < self.pause_menu.pause_quit_button.x + self.pause_menu.pause_quit_button.width and mouse_y > self.pause_menu.pause_quit_button.y and mouse_y < self.pause_menu.pause_quit_button.y + self.pause_menu.pause_quit_button.height:
self.pause_menu.img_id = 4
else:
self.pause_menu.img_id = 0
if mouse_x > self.options_menu.options_x_button.x and mouse_x < self.options_menu.options_x_button.x + self.options_menu.options_x_button.width and mouse_y > self.options_menu.options_x_button.y and mouse_y < self.options_menu.options_x_button.y + self.options_menu.options_x_button.height:
self.options_menu.img_id = 1
elif mouse_x > self.options_menu.options_reset_button.x and mouse_x < self.options_menu.options_reset_button.x + self.options_menu.options_reset_button.width and mouse_y > self.options_menu.options_reset_button.y and mouse_y < self.options_menu.options_reset_button.y + self.options_menu.options_reset_button.height:
self.options_menu.img_id = 2
elif mouse_x > self.options_menu.options_home_button.x and mouse_x < self.options_menu.options_home_button.x + self.options_menu.options_home_button.width and mouse_y > self.options_menu.options_home_button.y and mouse_y < self.options_menu.options_home_button.y + self.options_menu.options_home_button.height:
self.options_menu.img_id = 3
elif mouse_x > self.options_menu.options_ok_button.x and mouse_x < self.options_menu.options_ok_button.x + self.options_menu.options_ok_button.width and mouse_y > self.options_menu.options_ok_button.y and mouse_y < self.options_menu.options_ok_button.y + self.options_menu.options_ok_button.height:
self.options_menu.img_id = 4
else:
self.options_menu.img_id = 0
keys = pygame.key.get_pressed()
if keys[pygame.K_RIGHT] or keys[pygame.K_d]:
self.player.vel.x = PLAYER_SPEED
if keys[pygame.K_LEFT] or keys[pygame.K_a]:
self.player.vel.x = -PLAYER_SPEED
if keys[pygame.K_UP] or keys[pygame.K_w]:
self.player.vel.y = -PLAYER_SPEED
if keys[pygame.K_DOWN] or keys[pygame.K_s]:
self.player.vel.y = PLAYER_SPEED
def update_game(self):
self.player.update()
self.camera.update(self.player)
if self.player.rect.x <= 0:
self.player.rect.x = 0
if self.player.rect.right >= 5120:
self.player.rect.right = 5120
if self.player.rect.y <= 0:
self.player.rect.y = 0
if self.player.rect.bottom >= 5120:
self.player.rect.bottom = 5120
def draw_game(self):
self.window.blit(self.map, self.camera.apply_rect(self.map_rect))
self.window.blit(self.player.image, self.camera.apply(self.player))
self.hud.draw_health(self.window, 10, 10, self.player.health / PLAYER_HEALTH)
if self.display_main_menu:
self.main_menu.draw()
if self.display_pause_menu:
self.pause_menu.draw()
if self.display_options_menu:
self.options_menu.draw()
pygame.display.flip()
def main():
g = Game()
g.game_loop()
if __name__ == "__main__":
main()
Camera class
import pygame
from Settings import *
class Camera:
def __init__(self, width, height):
self.camera = pygame.Rect(0, 0, width, height)
self.width = width
self.height = height
def apply(self, target):
return target.rect.move(self.camera.topleft)
def apply_rect(self, rect):
return rect.move(self.camera.topleft)
def update(self, target):
x = -target.rect.centerx + int(WINDOW_WIDTH/2)
y = -target.rect.centery + int(WINDOW_HEIGHT/2)
x = min(0, x)
y = min(0, y)
x = max(-(self.width - WINDOW_WIDTH), x)
y = max(-(self.height - WINDOW_HEIGHT), y)
self.camera = pygame.Rect(x, y, self.width, self.height)
Use the center points self.rect.centerx and self.rect.centery or just self.rect.center and self.pos instead of self.rect.x self.rect.y (the topleft coordinates).
Here's the complete example that I used to test your code:
import math
import pygame
from pygame.math import Vector2
class Player(pygame.sprite.Sprite):
def __init__(self, pos):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.Surface((50, 30), pygame.SRCALPHA)
pygame.draw.polygon(
self.image,
pygame.Color('dodgerblue1'),
((0, 0), (50, 15), (0, 30)))
self.rect = self.image.get_rect(center=pos)
self.orig_img = self.image
self.pos = Vector2(pos)
self.vel = Vector2(0, 0)
def update(self):
self.rotate()
self.pos += self.vel
self.rect.centerx = self.pos.x
self.rect.centery = self.pos.y
def rotate(self):
mouse_pos = pygame.mouse.get_pos()
# Calculate the vector to the mouse position by subtracting
# the self.pos vector from the mouse_pos.
rel_x, rel_y = mouse_pos - self.pos
# Use math.atan2 to get the angle in radians and convert it to degrees.
angle = -math.degrees(math.atan2(rel_y, rel_x))
# Rotate the image.
self.image = pygame.transform.rotozoom(self.orig_img, angle, 1)
# Update the rect and keep the center at the old position.
self.rect = self.image.get_rect(center=self.rect.center)
def main():
screen = pygame.display.set_mode((640, 480))
clock = pygame.time.Clock()
sprite_group = pygame.sprite.Group()
player = Player((300, 200))
sprite_group.add(player)
done = False
while not done:
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
sprite_group.update()
screen.fill((30, 30, 30))
sprite_group.draw(screen)
pygame.display.flip()
clock.tick(30)
if __name__ == '__main__':
pygame.init()
main()
pygame.quit()
Edit3: In this example I use another pygame.Rect (called hitbox) to handle the collisions with the walls. The rect of the player can't be used for the collision detection, because it changes its size with each rotation what causes jumps if the player touches a wall. I'm using Rect.colliderect because spritecollide uses the rect not the hitbox, but you could also pass a custom collided callback function to spritecollide. (The red and green rects show the player.rect and player.hitbox.)
import math
import pygame
from pygame.math import Vector2 as vec
class Player(pygame.sprite.Sprite):
def __init__(self, x, y, walls):
pygame.sprite.Sprite.__init__(self)
self.walls = walls
self.image = pygame.Surface((50, 30), pygame.SRCALPHA)
pygame.draw.polygon(
self.image,
pygame.Color('dodgerblue1'),
((0, 0), (50, 15), (0, 30)))
self.rect = self.image.get_rect(center=(x, y))
self.hitbox = pygame.Rect(x, y, 50, 50)
self.orig_img = self.image
self.pos = vec(x, y)
self.vel = vec(0, 0)
def update(self):
self.rotate()
self.pos += self.vel
self.hitbox.centerx = self.pos.x
self.collide_with_tiles(self.walls, "x")
self.hitbox.centery = self.pos.y
self.collide_with_tiles(self.walls, "y")
self.rect.center = self.pos
def rotate(self):
rel_x, rel_y = pygame.mouse.get_pos() - self.pos
angle = -math.degrees(math.atan2(rel_y, rel_x))
self.image = pygame.transform.rotate(self.orig_img, int(angle))
self.rect = self.image.get_rect(center=self.pos)
def collide_with_tiles(self, group, dir):
if dir == "x":
for wall in self.walls:
if self.hitbox.colliderect(wall.rect):
if self.vel.x > 0:
self.hitbox.right = wall.rect.left
if self.vel.x < 0:
self.hitbox.left = wall.rect.right
self.vel.x = 0
self.pos.x = self.hitbox.centerx
if dir == "y":
for wall in self.walls:
if self.hitbox.colliderect(wall.rect):
if self.vel.y > 0:
self.hitbox.bottom = wall.rect.top
if self.vel.y < 0:
self.hitbox.top = wall.rect.bottom
self.vel.y = 0
self.pos.y = self.hitbox.centery
class Wall(pygame.sprite.Sprite):
def __init__(self, x, y, w, h):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.Surface((w, h))
self.image.fill(pygame.Color('sienna1'))
self.rect = self.image.get_rect(topleft=(x, y))
def main():
screen = pygame.display.set_mode((640, 480))
clock = pygame.time.Clock()
sprite_group = pygame.sprite.Group()
walls = pygame.sprite.Group()
wall = Wall(100, 200, 300, 30)
walls.add(wall)
sprite_group.add(wall)
player = Player(300, 400, walls)
sprite_group.add(player)
done = False
while not done:
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_w:
player.vel.y = -3
elif event.key == pygame.K_s:
player.vel.y = 3
elif event.key == pygame.K_a:
player.vel.x = -3
elif event.key == pygame.K_d:
player.vel.x = 3
elif event.type == pygame.KEYUP:
player.vel = vec(0, 0)
sprite_group.update()
screen.fill((30, 30, 30))
sprite_group.draw(screen)
pygame.draw.rect(screen, (200, 30, 30), player.rect, 2)
pygame.draw.rect(screen, (0, 200, 30), player.hitbox, 2)
pygame.display.flip()
clock.tick(30)
if __name__ == '__main__':
pygame.init()
main()
pygame.quit()
Edit4: To include the camera in the calculation, give the Player the camera as an attribute and in the rotate method just change this line:
rel_x, rel_y = pg.mouse.get_pos() - vec(self.camera.apply(self).center)

Categories