I am making a capture the flag type game. From the code below, I have the fundamentals set up. However, I don't know how I stop the flag from moving when the character hits a wall. Can anyone help me with this? As you can see if you run the code, the flag is effectively picked up by the character and carried but the flag will not stop if the character hits a wall. I want the flag to stay on the right side of the character as well. Thanks for any help. (CODE HAS BEEN UPDATED SINCE ORIGINAL POST)
import pygame
def start():
pygame.init()
BLUE = (0, 0, 128)
RED = (204, 0, 0)
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
screen = pygame.display.set_mode((1920,1080), flags=pygame.FULLSCREEN)
pygame.display.set_caption("Recovery")
clock = pygame.time.Clock()
bigJoe = pygame.image.load("bigJoe.png")
characterSelected = bigJoe
game(BLACK, WHITE, BLUE, RED, screen, clock, characterSelected, bigJoe)
def game(BLACK, WHITE, BLUE, RED, screen, clock, characterSelected, bigJoe):
if characterSelected == bigJoe:
gameCharacter = "gameJoe.png"
all_sprite_list = pygame.sprite.Group()
playerList = pygame.sprite.Group()
wall_list = pygame.sprite.Group()
flagList = pygame.sprite.Group()
playerFlag = pygame.sprite.Group()
flag = Flag(1810,540)
flagList.add(flag)
'''Design of Map Below'''
topWall = Wall(0, 0, 1920, 5, BLUE)
bottomWall = Wall(0, 1075, 1920, 5, BLUE)
leftWall = Wall(0, 0, 5, 1080, BLUE)
rightWall = Wall(1915, 0, 5, 1080, BLUE)
baseWall1 = Wall(5, 300, 150, 75, WHITE)
baseWall2 = Wall(5, 375, 100, 330, WHITE)
baseWall3 = Wall(5, 705, 150, 75, WHITE)
baseSquare = Wall(30, 530, 40, 40, RED)
wall1 = Wall(400, 400, 200, 300, RED)
wall_list.add(topWall, bottomWall, leftWall, rightWall, baseWall1, wall1, baseWall2, baseWall3)
all_sprite_list.add(topWall, bottomWall, leftWall, rightWall, baseWall1, wall1, baseWall2, baseWall3, baseSquare, flag)
'''Adding Character to Game'''
player = Player(110, 550, gameCharacter)
flag.player = playerFlag
player.wall = wall_list
all_sprite_list.add(player)
playerFlag.add(player, flag)
playerList.add(player)
flag.player = player
flag.carried = playerFlag
flag.walls = wall_list
run = True
while run:
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
keys = pygame.key.get_pressed()
if keys[pygame.K_ESCAPE]:
run = False
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
player.changespeed(-3, 0)
flag.moveFlag(-3, 0)
elif event.key == pygame.K_RIGHT:
player.changespeed(3, 0)
flag.moveFlag(3, 0)
elif event.key == pygame.K_UP:
player.changespeed(0, -3)
flag.moveFlag(0, -3,)
elif event.key == pygame.K_DOWN:
player.changespeed(0, 3)
flag.moveFlag(0, 3)
elif event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT:
player.changespeed(3, 0)
flag.moveFlag(3, 0)
elif event.key == pygame.K_RIGHT:
player.changespeed(-3, 0)
flag.moveFlag(-3, 0)
elif event.key == pygame.K_UP:
player.changespeed(0, 3)
flag.moveFlag(0, 3)
elif event.key == pygame.K_DOWN:
player.changespeed(0, -3)
flag.moveFlag(0, -3)
all_sprite_list.update()
screen.fill(BLACK)
all_sprite_list.draw(screen)
pygame.display.flip()
clock.tick(75)
start()
On a separate file
import pygame
class Player(pygame.sprite.Sprite):
def __init__(self, x, y, gameCharacter):
super().__init__()
self.image = pygame.image.load(gameCharacter)
self.rect = self.image.get_rect()
self.rect.y = y
self.rect.x = x
self.change_x = 0
self.change_y = 0
self.wall = None
def changespeed(self, x, y):
self.change_x += x
self.change_y += y
def update(self):
self.rect.x += self.change_x
wallHitList = pygame.sprite.spritecollide(self, self.wall, False)
for wall in wallHitList:
if self.change_x > 0:
self.rect.right = wall.rect.left
else:
self.rect.left = wall.rect.right
self.rect.y += self.change_y
wallHitList = pygame.sprite.spritecollide(self, self.wall, False)
for wall in wallHitList:
if self.change_y > 0:
self.rect.bottom = wall.rect.top
else:
self.rect.top = wall.rect.bottom
class Wall(pygame.sprite.Sprite):
def __init__(self, x, y, width, height,color):
super().__init__()
self.image = pygame.Surface([width, height])
self.image.fill(color)
self.rect = self.image.get_rect()
self.rect.y = y
self.rect.x = x
class Flag(pygame.sprite.Sprite):
def __init__(self, x, y,):
super().__init__()
self.image = pygame.image.load("flag.png")
self.rect = self.image.get_rect()
self.rect.y = y
self.rect.x = x
self.change_x = 0
self.change_y = 0
def moveFlag(self, x, y):
self.change_x += x
self.change_y += y
def update(self):
hit = False
allowMove = True
flagCharacterList = pygame.sprite.spritecollide(self, self.carried, False)
for i in flagCharacterList:
if len(flagCharacterList) == 2:
hit = True
else:
hit = False
block_hit_list = pygame.sprite.groupcollide(self.walls, self.carried, False, False)
for block in block_hit_list:
if len(block_hit_list) == 1:
allowMove = False
else:
allowMove = True
if hit and allowMove:
self.rect.x += self.change_x
self.rect.y += self.change_y
The flag doesn't move bit itself. bit the player carries the flag. Possibly the player can carry more than 1 flag.
Remove the collision detection from the method Flag.update:
class Flag(pygame.sprite.Sprite):
def __init__(self, x, y,):
super().__init__()
#self.image = pygame.image.load("flag.png")
self.rect = self.image.get_rect()
self.rect.y = y
self.rect.x = x
self.change_x = 0
self.change_y = 0
def moveFlag(self, x, y):
self.change_x += x
self.change_y += y
def update(self):
self.rect.x += self.change_x
self.rect.y += self.change_y
Add an attribute self.flags to the player and move all the flags contained in the list by the same amount as the player:
class Player(pygame.sprite.Sprite):
def __init__(self, x, y, gameCharacter):
# [...]
self.flags = []
# [...]
def update(self):
current_pos = (self.rect.x, self.rect.y)
self.rect.x += self.change_x
wallHitList = pygame.sprite.spritecollide(self, self.wall, False)
for wall in wallHitList:
if self.change_x > 0:
self.rect.right = wall.rect.left
else:
self.rect.left = wall.rect.right
self.rect.y += self.change_y
wallHitList = pygame.sprite.spritecollide(self, self.wall, False)
for wall in wallHitList:
if self.change_y > 0:
self.rect.bottom = wall.rect.top
else:
self.rect.top = wall.rect.bottom
for flag in self.flags:
flag.rect.x += self.rect.x - current_pos[0]
flag.rect.y += self.rect.y - current_pos[1]
flag.move() is not needed any more. But if the player hits the flag, then the flag is add player.flags. That caused, that the plyer carries the flag:
def game(BLACK, WHITE, BLUE, RED, screen, clock, characterSelected, bigJoe):
# [...]
while run:
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
keys = pygame.key.get_pressed()
if keys[pygame.K_ESCAPE]:
run = False
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT: player.changespeed(-3, 0)
elif event.key == pygame.K_RIGHT: player.changespeed(3, 0)
elif event.key == pygame.K_UP: player.changespeed(0, -3)
elif event.key == pygame.K_DOWN: player.changespeed(0, 3)
elif event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT: player.changespeed(3, 0)
elif event.key == pygame.K_RIGHT: player.changespeed(-3, 0)
elif event.key == pygame.K_UP: player.changespeed(0, 3)
elif event.key == pygame.K_DOWN: player.changespeed(0, -3)
if flag not in player.flags:
if pygame.sprite.collide_rect(flag, player):
player.flags.append(flag)
flag.rect.left = player.rect.right
# [...]
Related
I'm developing a basic game, where you can move around and shoot projectiles to kill randomly spawned enemies, but if I boot the game and I try to move before I do anything else, the game crashes. If I shoot a projectile first, however, the game runs perfectly and I can move around without any problems, but I can't seem to figure out why this is.
import pygame
import random
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)
#Classes
class Player(pygame.sprite.Sprite):
def __init__(self, filename, x, y):
super().__init__()
self.image = pygame.image.load(filename).convert()
self.image.set_colorkey(BLACK)
self.rect = self.image.get_rect()
self.rect.y = y
self.rect.x = x
self.change_x = 0
self.change_y = 0
self.walls = None
def changespeed(self, x, y):
self.change_x += x
self.change_y += y
def update(self):
self.rect.x += self.change_x
block_hit_list = pygame.sprite.spritecollide(self, self.walls, False)
for block in block_hit_list:
if self.change_x > 0:
self.rect.right = block.rect.left
else:
self.rect.left = block.rect.right
self.rect.y += self.change_y
block_hit_list = pygame.sprite.spritecollide(self, self.walls, False)
for block in block_hit_list:
if self.change_y > 0:
self.rect.bottom = block.rect.top
else:
self.rect.top = block.rect.bottom
class Wall(pygame.sprite.Sprite):
def __init__(self, x, y, width, height):
super().__init__()
self.image = pygame.Surface([width, height])
self.image.fill(BLACK)
self.rect = self.image.get_rect()
self.rect.y = y
self.rect.x = x
class Enemy(pygame.sprite.Sprite):
def __init__(self, filename):
super().__init__()
self.image = pygame.image.load(filename).convert()
self.image.set_colorkey(BLACK)
self.rect = self.image.get_rect()
class ProjectileUp(pygame.sprite.Sprite):
def __init__(self, filename):
super().__init__()
self.image = pygame.image.load(filename).convert()
self.image.set_colorkey(BLACK)
self.rect = self.image.get_rect()
def update(self):
self.rect.y -= 5
class ProjectileDown(pygame.sprite.Sprite):
def __init__(self, filename):
super().__init__()
self.image = pygame.image.load(filename).convert()
self.image.set_colorkey(BLACK)
self.rect = self.image.get_rect()
def update(self):
self.rect.y += 5
class ProjectileLeft(pygame.sprite.Sprite):
def __init__(self, filename):
super().__init__()
self.image = pygame.image.load(filename).convert()
self.image.set_colorkey(BLACK)
self.rect = self.image.get_rect()
def update(self):
self.rect.x -= 5
class ProjectileRight(pygame.sprite.Sprite):
def __init__(self, filename):
super().__init__()
self.image = pygame.image.load(filename).convert()
self.image.set_colorkey(BLACK)
self.rect = self.image.get_rect()
def update(self):
self.rect.x += 5
# --- Create the window
#Initialise pygame
pygame.init()
#Window dimensions
screen_width = 1080
screen_height = 607
screen = pygame.display.set_mode([screen_width, screen_height])
#Window display name
pygame.display.set_caption('Labyrinth')
#Sprite Lists
all_sprite_list = pygame.sprite.Group()
block_list = pygame.sprite.Group()
wall_list = pygame.sprite.Group()
projectile_list = pygame.sprite.Group()
#Define game borders
wall = Wall(-32, 0, 10, 607)
wall_list.add(wall)
all_sprite_list.add(wall)
wall = Wall(0 , -64, 1080, 10)
wall_list.add(wall)
all_sprite_list.add(wall)
wall = Wall(1100, 0, 10, 607)
wall_list.add(wall)
all_sprite_list.add(wall)
wall = Wall(0 , 600, 1080, 10)
wall_list.add(wall)
all_sprite_list.add(wall)
#Create player sprite
player = Player("Isaac.png", 420, 150)
all_sprite_list = pygame.sprite.Group()
all_sprite_list.add(player)
player.walls = wall_list
#Create enemies
for i in range(7):
block = Enemy("Judas.png")
block.rect.x = random.randrange(50, 950)
block.rect.y = random.randrange(50, 450)
block_list.add(block)
all_sprite_list.add(block)
#Manage screen updates
clock = pygame.time.Clock()
#Load background image
background_position = [0, 0]
background_image = pygame.image.load("Floor.png").convert()
#Loop until game_exit
done = False
#---------- MAIN PROGRAM LOOP ----------#
while not done:
# --- Event processing
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
#Projectile spawn
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_UP:
projectile = ProjectileUp("LightningUp.png")
projectile.rect.x = player.rect.x+65
projectile.rect.y = player.rect.y
elif event.key == pygame.K_DOWN:
projectile = ProjectileDown("LightningDown.png")
projectile.rect.x = player.rect.x+65
projectile.rect.y = player.rect.y+100
elif event.key == pygame.K_LEFT:
projectile = ProjectileLeft("LightningLeft.png")
projectile.rect.x = player.rect.x+35
projectile.rect.y = player.rect.y+100
elif event.key == pygame.K_RIGHT:
projectile = ProjectileRight("LightningRight.png")
projectile.rect.x = player.rect.x+115
projectile.rect.y = player.rect.y+100
all_sprite_list.add(projectile)
projectile_list.add(projectile)
#Movement controls
if event.type == pygame.KEYDOWN:
if event.key == ord('a'):
player.changespeed(-7, 0)
elif event.key == ord('d'):
player.changespeed(7, 0)
elif event.key == ord('w'):
player.changespeed(0, -7)
elif event.key == ord('s'):
player.changespeed(0, 7)
elif event.type == pygame.KEYUP:
if event.key == ord('a'):
player.changespeed(7, 0)
elif event.key == ord('d'):
player.changespeed(-7, 0)
elif event.key == ord('w'):
player.changespeed(0, 7)
elif event.key == ord('s'):
player.changespeed(0, -7)
# --- Game logic
#Update sprites
all_sprite_list.update()
#Projectile mechanics
for projectile in projectile_list:
block_hit_list = pygame.sprite.spritecollide(projectile, block_list, True)
for block in block_hit_list:
projectile_list.remove(projectile)
#Determine if player hits enemy
blocks_hit_list = pygame.sprite.spritecollide(player, block_list, True)
#Call on background image
screen.blit(background_image, background_position)
# --- Draw the window
all_sprite_list.draw(screen)
pygame.display.flip()
clock.tick(60)
pygame.quit()
It's because your if/elif/else logic is messed up a bit. You have two paths for the KEYDOWN event. If the first event happens to be a movement command, your code runs through the projectile code first (without finding a valid projectile command) and then tries to reference a projectile object that doesn't exist. Try this instead:
#---------- MAIN PROGRAM LOOP ----------#
while not done:
# --- Event processing
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
elif event.type == pygame.KEYDOWN:
projectile = None # initialize
if event.key == pygame.K_UP:
projectile = ProjectileUp("LightningUp.png")
projectile.rect.x = player.rect.x+65
projectile.rect.y = player.rect.y
elif event.key == pygame.K_DOWN:
projectile = ProjectileDown("LightningDown.png")
projectile.rect.x = player.rect.x+65
projectile.rect.y = player.rect.y+100
elif event.key == pygame.K_LEFT:
projectile = ProjectileLeft("LightningLeft.png")
projectile.rect.x = player.rect.x+35
projectile.rect.y = player.rect.y+100
elif event.key == pygame.K_RIGHT:
projectile = ProjectileRight("LightningRight.png")
projectile.rect.x = player.rect.x+115
projectile.rect.y = player.rect.y+100
elif event.key == ord('a'):
player.changespeed(-7, 0)
elif event.key == ord('d'):
player.changespeed(7, 0)
elif event.key == ord('w'):
player.changespeed(0, -7)
elif event.key == ord('s'):
player.changespeed(0, 7)
if projectile: # did we create a valid projectile?
all_sprite_list.add(projectile)
projectile_list.add(projectile)
elif event.type == pygame.KEYUP:
if event.key == ord('a'):
player.changespeed(7, 0)
elif event.key == ord('d'):
player.changespeed(-7, 0)
elif event.key == ord('w'):
player.changespeed(0, 7)
elif event.key == ord('s'):
player.changespeed(0, -7)
new to pygame and game programming in general, just wondered how I could get a camera to follow a car (nothing fancy) in a top down car game - think Micro Machines! I'm using Python 3.6, and have got a bike rotating, and moving around. I've kept the code here shorter but I do have a static image for reference if the camera worked!
Here's what I have:
import pygame, math, sys, random
from pygame.locals import *
display_width = 1280
display_height = 800
# Sets size of screen
screen = pygame.display.set_mode((display_width, display_height))
# Initialises clock
clock = pygame.time.Clock()
# Colours
white = (255,255,255)
black = (0,0,0)
class Entity(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
class VehicleSprite(Entity):
# Creates a vehicle class
MAX_FORWARD_SPEED = 10
MAX_REVERSE_SPEED = 2
ACCELERATION = 0.05
TURN_SPEED = 0.000000000001
def __init__(self, image, position):
Entity.__init__(self)
# Creates object instance off
pygame.sprite.Sprite.__init__(self)
self.src_image = pygame.image.load(image)
self.position = position
self.speed = self.direction = 0
self.k_left = self.k_right = self.k_down = self.k_up = 0
def update(self, time):
# SIMULATION
self.speed += (self.k_up +self.k_down)
if self.speed > self.MAX_FORWARD_SPEED:
self.speed = self.MAX_FORWARD_SPEED
if self.speed < -self.MAX_REVERSE_SPEED:
self.speed = -self.MAX_REVERSE_SPEED
# Degrees sprite is facing (direction)
self.direction += (self.k_right + self.k_left)
x, y = self.position
rad = self.direction * math.pi / 180
x += -self.speed*math.sin(rad)
y += -self.speed*math.cos(rad)
self.position = (x, y)
self.image = pygame.transform.rotate(self.src_image, self.direction)
self.rect = self.image.get_rect()
self.rect.center = self.position
class Background(pygame.sprite.Sprite):
def __init__(self, image_file, location):
pygame.sprite.Sprite.__init__(self) #call Sprite initializer
self.image = pygame.image.load(image_file)
self.rect = self.image.get_rect()
self.rect.left, self.rect.top = location
rect = screen.get_rect()
# Background
BackGround = Background('/home/pi/gametuts/images/backgrounds/bkg_img.png', [0, 0])
# Bike image load
bike = VehicleSprite('/home/pi/gametuts/images/BikePixelBig.png', rect.center)
bike_group = pygame.sprite.RenderPlain(bike)
# Ball image load
ball = VehicleSprite('/home/pi/gametuts/images/ironball.png', rect.center)
ball_group = pygame.sprite.RenderPlain(ball)
# Main game loop
def game_loop():
while 1:
#USER INPUT
# Sets frame rate
time = clock.tick(60)
for event in pygame.event.get():
if not hasattr(event, 'key'): continue
down = event.type == KEYDOWN
# Bike Input (Player 1)
if event.key == K_d: bike.k_right = down * -5
elif event.key == K_a: bike.k_left = down * 5
elif event.key == K_w: bike.k_up = down * 2
elif event.key == K_s: bike.k_down = down * -2
# Quit
elif event.key == K_ESCAPE: sys.exit(0)
#RENDERING
# Game background
screen.fill(white)
screen.blit(BackGround.image, BackGround.rect)
# Bike render
bike_group.update(time)
bike_group.draw(screen)
ball_group.update(time)
ball_group.draw(screen)
pygame.display.flip()
game_loop()
pygame.quit()
quit()
Thanks in advance!
The simplest way to implement a camera is to use a pygame.math.Vector2 as the camera, subtract the player velocity from it each frame and add it to the position of all game elements during the blitting.
import pygame as pg
from pygame.math import Vector2
class Player(pg.sprite.Sprite):
def __init__(self, pos, walls, *groups):
super().__init__(*groups)
self.image = pg.Surface((30, 50))
self.image.fill(pg.Color('dodgerblue'))
self.rect = self.image.get_rect(center=pos)
self.vel = Vector2(0, 0)
self.pos = Vector2(pos)
self.walls = walls
self.camera = Vector2(0, 0)
def update(self):
self.camera -= self.vel # Change the camera pos if we're moving.
# Horizontal movement.
self.pos.x += self.vel.x
self.rect.centerx = self.pos.x
# Change the rect and self.pos coords if we touched a wall.
for wall in pg.sprite.spritecollide(self, self.walls, False):
if self.vel.x > 0:
self.rect.right = wall.rect.left
elif self.vel.x < 0:
self.rect.left = wall.rect.right
self.pos.x = self.rect.centerx
self.camera.x += self.vel.x # Also move the camera back.
# Vertical movement.
self.pos.y += self.vel.y
self.rect.centery = self.pos.y
for wall in pg.sprite.spritecollide(self, self.walls, False):
if self.vel.y > 0:
self.rect.bottom = wall.rect.top
elif self.vel.y < 0:
self.rect.top = wall.rect.bottom
self.pos.y = self.rect.centery
self.camera.y += self.vel.y
class Wall(pg.sprite.Sprite):
def __init__(self, x, y, w, h, *groups):
super().__init__(*groups)
self.image = pg.Surface((w, h))
self.image.fill(pg.Color('sienna2'))
self.rect = self.image.get_rect(topleft=(x, y))
def main():
screen = pg.display.set_mode((640, 480))
clock = pg.time.Clock()
all_sprites = pg.sprite.Group()
walls = pg.sprite.Group()
for rect in ((100, 170, 90, 20), (200, 100, 20, 140),
(400, 60, 150, 100), (300, 470, 150, 100)):
walls.add(Wall(*rect))
all_sprites.add(walls)
player = Player((320, 240), walls, all_sprites)
done = False
while not done:
for event in pg.event.get():
if event.type == pg.QUIT:
done = True
elif event.type == pg.KEYDOWN:
if event.key == pg.K_d:
player.vel.x = 5
elif event.key == pg.K_a:
player.vel.x = -5
elif event.key == pg.K_w:
player.vel.y = -5
elif event.key == pg.K_s:
player.vel.y = 5
elif event.type == pg.KEYUP:
if event.key == pg.K_d and player.vel.x > 0:
player.vel.x = 0
elif event.key == pg.K_a and player.vel.x < 0:
player.vel.x = 0
elif event.key == pg.K_w and player.vel.y < 0:
player.vel.y = 0
elif event.key == pg.K_s and player.vel.y > 0:
player.vel.y = 0
all_sprites.update()
screen.fill((30, 30, 30))
for sprite in all_sprites:
# Add the player's camera offset to the coords of all sprites.
screen.blit(sprite.image, sprite.rect.topleft+player.camera)
pg.display.flip()
clock.tick(30)
if __name__ == '__main__':
pg.init()
main()
pg.quit()
Edit: Here's your code example with a camera. I've also tried to improve a few more things, for example the max(min(...)) trick to clamp the speed value. I'm not sure if the movement works as you want, but you can of course adjust it yourself. (I'd probably make even more modifications to the update method.)
import math
import random
import pygame
pygame.init()
screen = pygame.display.set_mode((1280, 800))
rect = screen.get_rect()
clock = pygame.time.Clock()
WHITE = pygame.Color('white')
# Load images globally and reuse them in your program.
# Also use the `.convert()` or `.convert_alpha()` methods after
# loading the images to improve the performance.
VEHICLE1 = pygame.Surface((40, 70), pygame.SRCALPHA)
VEHICLE1.fill((130, 180, 20))
VEHICLE2 = pygame.Surface((40, 70), pygame.SRCALPHA)
VEHICLE2.fill((200, 120, 20))
BACKGROUND = pygame.Surface((1280, 800))
BACKGROUND.fill((30, 30, 30))
class Entity(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
class VehicleSprite(Entity):
MAX_FORWARD_SPEED = 10
MAX_REVERSE_SPEED = 2
ACCELERATION = 0.05
TURN_SPEED = 0.000000000001
def __init__(self, image, position):
Entity.__init__(self)
self.src_image = image
self.image = image
self.rect = self.image.get_rect(center=position)
self.position = pygame.math.Vector2(position)
self.velocity = pygame.math.Vector2(0, 0)
self.speed = self.direction = 0
self.k_left = self.k_right = self.k_down = self.k_up = 0
def update(self, time):
# SIMULATION
self.speed += self.k_up + self.k_down
# To clamp the speed.
self.speed = max(-self.MAX_REVERSE_SPEED,
min(self.speed, self.MAX_FORWARD_SPEED))
# Degrees sprite is facing (direction)
self.direction += (self.k_right + self.k_left)
rad = math.radians(self.direction)
self.velocity.x = -self.speed*math.sin(rad)
self.velocity.y = -self.speed*math.cos(rad)
self.position += self.velocity
self.image = pygame.transform.rotate(self.src_image, self.direction)
self.rect = self.image.get_rect(center=self.position)
class Background(pygame.sprite.Sprite):
def __init__(self, image, location):
pygame.sprite.Sprite.__init__(self)
self.image = image
self.rect = self.image.get_rect(topleft=location)
def game_loop():
background = Background(BACKGROUND, [0, 0])
bike = VehicleSprite(VEHICLE1, rect.center)
ball = VehicleSprite(VEHICLE2, rect.center)
bike_group = pygame.sprite.Group(bike)
ball_group = pygame.sprite.Group(ball)
all_sprites = pygame.sprite.Group(bike_group, ball_group)
camera = pygame.math.Vector2(0, 0)
done = False
while not done:
time = clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
elif event.type == pygame.KEYDOWN:
# Bike Input (Player 1)
if event.key == pygame.K_d:
bike.k_right = -5
elif event.key == pygame.K_a:
bike.k_left = 5
elif event.key == pygame.K_w:
bike.k_up = 2
elif event.key == pygame.K_s:
bike.k_down = -2
elif event.key == pygame.K_ESCAPE:
done = True
elif event.type == pygame.KEYUP:
if event.key == pygame.K_d:
bike.k_right = 0
elif event.key == pygame.K_a:
bike.k_left = 0
elif event.key == pygame.K_w:
bike.k_up = 0
elif event.key == pygame.K_s:
bike.k_down = 0
camera -= bike.velocity
all_sprites.update(time)
screen.fill(WHITE)
screen.blit(background.image, background.rect)
for sprite in all_sprites:
screen.blit(sprite.image, sprite.rect.topleft+camera)
pygame.display.flip()
game_loop()
pygame.quit()
I have a problem with my code, im trying to draw a hexagon polygon, but nth show up. When i'm trying with eclipse or other pygame.draw functions its ok, problem is with polygons. Here is my code. I think whole program is working fine, the problem is here :
hexagon = Hexagon.hexagon_generator(40,self.rect.x,self.rect.y)
pygame.draw.polygon(self.image,(0,225,0),list(hexagon),0)
Whole program:
import pygame
import random
import Hexagon
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
RED = (255, 0, 0)
class Player(pygame.sprite.Sprite):
def __init__(self,x,y):
super().__init__()
self.image = pygame.Surface([100,100])
self.rect = self.image.get_rect()
self.image.fill(WHITE)
self.image.set_colorkey(WHITE)
self.rect.x = x
self.rect.y = y
hexagon = Hexagon.hexagon_generator(40,self.rect.x,self.rect.y)
pygame.draw.polygon(self.image,(0,225,0),list(hexagon),0)
self.velocity_y = 0
self.velocity_x = 0
def move(self, x, y):
self.velocity_x += x
self.velocity_y += y
def update(self):
self.rect.x += self.velocity_x
self.rect.y += self.velocity_y
if self.rect.x >785:
self.rect.x =785
elif self.rect.x <0:
self.rect.x =0
elif self.rect.y > 585:
self.rect.y = 585
elif self.rect.y < 0:
self.rect.y = 0
elif self.rect.x<0 and self.rect.y < 0:
self.rect.x = 0
self.rect.y = 0
pygame.init()
screen_width = 800
screen_height = 600
screen = pygame.display.set_mode([screen_width, screen_height])
all_sprites_list = pygame.sprite.Group()
player = Player(200,200)
all_sprites_list.add(player)
done = False
clock = pygame.time.Clock()
while not done:
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_DOWN:
player.move(0,5)
if event.key == pygame.K_UP:
player.move(0, -5)
if event.key == pygame.K_LEFT:
player.move(-5, 0)
if event.key == pygame.K_RIGHT:
player.move(5, 0)
if event.type == pygame.KEYUP:
if event.key == pygame.K_DOWN:
player.move(0, -5)
if event.key == pygame.K_UP:
player.move(0, 5)
if event.key == pygame.K_LEFT:
player.move(5, 0)
if event.key == pygame.K_RIGHT:
player.move(-5, 0)
screen.fill(WHITE)
all_sprites_list.update()
all_sprites_list.draw(screen)
pygame.display.flip()
clock.tick(60)
pygame.quit()
There is a Hexagon module:
import math
def hexagon_generator(edge_length, x,y):
for angle in range(0, 360, 60):
x += math.cos(math.radians(angle)) * edge_length
y += math.sin(math.radians(angle)) * edge_length
yield x, y
If you print the values that hexagon_generator yields, you'll see that the points are outside of the image (which has a size of 100*100 pixels).
[(240.0, 200.0), (260.0, 234.64101615137753), (240.0, 269.28203230275506), (200.0, 269.28203230275506), (179.99999999999997, 234.64101615137753), (199.99999999999997, 200.0)]
You shouldn't use the world coordinates of the player as the start x, y values. If the hexagon should be centered, you can just pass the half edge length of the image to the generator and add it to x and y:
def hexagon_generator(edge_length):
for angle in range(0, 360, 60):
x = math.cos(math.radians(angle)) * edge_length + edge_length
y = math.sin(math.radians(angle)) * edge_length + edge_length
yield x, y
This is the error:
Traceback (most recent call last):
File "C:/Users/Lucas/PycharmProjects/FirstPyGame/Main.py", line 117, in <module>
player.changespeed(3, 0)
File "C:/Users/Lucas/PycharmProjects/FirstPyGame/Main.py", line 42, in changespeed
self.change_x += x
AttributeError: 'Ship' object has no attribute 'change_x'
Here is my code:
import pygame
import random
pygame.init()
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 255, 255)
size = [800, 600]
x_coord = 400
y_coord = 600
x_speed = 0
y_speed = 0
font = pygame.font.SysFont("Calibri", 25, True, False)
snow_list = []
for i in range(50):
x = random.randrange(0, 800)
y = random.randrange(0, 600)
snow_list.append([x, y])
pygame.display.set_caption("Star Fighter")
screen = pygame.display.set_mode(size)
clock = pygame.time.Clock()
class Ship(pygame.sprite.Sprite):
def ___init__(self, x, y):
super().__init__()
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
self.change_x = 0
self.change_y = 0
def changespeed(self, x, y):
self.change_x += x
self.change_y += y
def update(self):
self.rect.x += self.change_x
self.rect.y += self.change_y
def DrawShip(screen, x, y):
a = pygame.draw.rect(screen, WHITE, ((x_coord - 5), (y_coord - 60), 10, 10))
b = pygame.draw.rect(screen, WHITE, ((x_coord - 15), (y_coord - 50), 10, 10))
c = pygame.draw.rect(screen, RED, ((x_coord - 5), (y_coord - 50), 10, 10))
d = pygame.draw.rect(screen, WHITE, ((x_coord + 5), (y_coord - 50), 10, 10))
class Block(pygame.sprite.Sprite):
def __init__(self, color):
super().__init__()
self.image = pygame.Surface([20, 15])
self.image.fill(color)
self.rect = self.image.get_rect()
def ScrollStars():
for i in range(len(snow_list)):
pygame.draw.circle(screen, WHITE, snow_list[i], 3)
snow_list[i][1] += 1
if snow_list[i][1] > 600:
y = random.randrange(-50, -10)
snow_list[i][1] = y
x = random.randrange(0, 800)
snow_list[i][0] = x
class Bullet(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
self.image = pygame.Surface([4, 10])
self.image.fill(WHITE)
self.rect = self.image.get_rect()
def update(self):
self.rect.y -= 3
all_sprites_list = pygame.sprite.Group()
block_list = pygame.sprite.Group()
bullet_list = pygame.sprite.Group()
for i in range(50):
# This represents a block
block = Block(BLUE)
# Set a random location for the block
block.rect.x = random.randrange(800)
block.rect.y = random.randrange(300)
# Add the block to the list of objects
block_list.add(block)
all_sprites_list.add(block)
score = 0
player = Ship()
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
player.changespeed(-3, 0)
elif event.key == pygame.K_RIGHT:
player.changespeed(3, 0)
elif event.key == pygame.K_SPACE:
bullet = Bullet()
bullet.rect.x = x_coord
bullet.rect.y = 550
all_sprites_list.add(bullet)
bullet_list.add(bullet)
elif event.key == pygame.K_q:
running = False
elif event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT:
player.changespeed(3, 0)
elif event.key == pygame.K_RIGHT:
player.changespeed(-3, 0)
if event.key == pygame.K_LEFT or pygame.K_RIGHT:
x_speed = 0
if event.type == pygame.K_UP or pygame.K_DOWN:
y_speed = 0
for bullet in bullet_list:
block_hit_list = pygame.sprite.spritecollide(bullet, block_list, True)
for block in block_hit_list:
bullet_list.remove(bullet)
all_sprites_list.remove(bullet)
score += 1
if bullet.rect.y < -10:
bullet_list.remove(bullet)
all_sprites_list.remove(bullet)
x_coord = x_coord + x_speed
y_coord = y_coord + y_speed
all_sprites_list.update()
screen.fill(BLACK)
all_sprites_list.draw(screen)
Ship.DrawShip(screen, x_coord, y_coord)
pygame.display.update()
clock.tick(70)
pygame.quit()
Could someone explain the error that I am having? I am a beginner and I do not understand it very well. It says that the Ship class has no attribute 'change_x' but it does, right? Sorry if this doesn't make any sense, but someone please help me with this. I would really appreciate it.
The issue is caused by a typo. The name of the constructor is __init__ rather than ___init__:
def ___init__(self, x, y):
def __init__(self, x, y):
I am trying to create a circle sprite that will be in a window that will have walls on the left and right of the screen. I cannot get the class Player to work right as a circle but I can get it to work as a square. After trying to fix this for 20-ish hours I am hell bent to make the circle work... Or at least understand why my code is failing.
import pygame
pygame.init()
black = (0,0,0)
white = (255,255,255)
gray = (105,105,105)
red = (255,0,0)
class Barrier(pygame.sprite.Sprite): #Barriers will be walls and "floors"
def __init__(self,x,y,width,height,color):
super().__init__()
self.image = pygame.Surface([width, height])
self.image.fill(color)
self.rect = self.image.get_rect()
self.rect.y = y
self.rect.x = x
class Player(pygame.sprite.Sprite): #player will be a circle
def __int__(self,x,y):
super().__init__()
self.image = pygame.Surface((50,50))
self.image.fill(white)
pygame.draw.circle(self.image, black, (25, 25), 25, 0)
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
self.change_x = 0
self.change_y = 0
self.barrier = None
def changespeed(self, x, y):
self.change_x += x
self.change_y += y
def update(self):
self.rect.x += self.change_x
block_hit_list = pygame.sprite.spritecollide(self, self.barrier, False)
for block in block_hit_list:
if self.change_x > 0:
self.rect.right = block.rect.left
else:
self.rect.left = block.rect.right
self.rect.y += self.change_y
block_hit_list = pygame.sprite.spritecollide(self, self.barrier, False)
for block in block_hit_list:
if self.change_y > 0:
self.rect.bottom = block.rect.top
else:
self.rect.top = block.rect.bottom
screen = pygame.display.set_mode((800,480))
pygame.display.set_caption("Test")
background = pygame.Surface(screen.get_size())
background = background.convert()
background.fill(white)
all_sprite_list = pygame.sprite.Group()
wall_list = pygame.sprite.Group() #wall will be a vertical Barrier
wall = Barrier(0,0,10,800,red)
wall_list.add(wall)
all_sprite_list.add(wall)
wall = Barrier(790,0,10,800,red)
wall_list.add(wall)
all_sprite_list.add(wall)
player = Player(50,50)
player.barrier = wall_list
all_sprite_list.add(player)
clock = pygame.time.Clock()
score = 0
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_LEFT:
player.changespeed(-3, 0)
elif event.key == pygame.K_RIGHT:
player.changespeed(3, 0)
elif event.key == pygame.K_UP:
player.changespeed(0, -3)
elif event.key == pygame.K_DOWN:
player.changespeed(0, 3)
elif event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT:
player.changespeed(3, 0)
elif event.key == pygame.K_RIGHT:
player.changespeed(-3, 0)
elif event.key == pygame.K_UP:
player.changespeed(0, 3)
elif event.key == pygame.K_DOWN:
player.changespeed(0, -3)
all_sprite_list.update()
screen.fill(white)
all_sprite_list.draw(screen)
pygame.display.flip()
clock.tick(40)
pygame.quit()
Full Traceback Error:
Traceback (most recent call last):
File "D:/pyDump/FallGame/freeFALL.py", line 114, in <module>
all_sprite_list.update()
File "C:\Program Files\Anaconda3\lib\site-packages\pygame\sprite.py", line 462, in update
s.update(*args)
File "D:/pyDump/FallGame/freeFALL.py", line 43, in update
self.rect.x += self.change_x
AttributeError: 'Player' object has no attribute 'rect'
For context, I'm using Pycharm and python 3.5 on a PC. Thanks!
*edit- grammar
In your Player class, you spelled init as int. That means when the object is created, none of the code in that method runs.