This is my Player class,
I currently have both players interacting with the walls (which is a separate class in the code but not pasted onto this question) but I need a way to prevent players from walking through each other just as players can't walk through walls. The issue is that I can use self.rect.right = block.rect.left to prevent the player from going through the wall when its right side touches the left side of the wall but I cannot use self.rect.right = self.rect.left to prevent player one from going through player 2 because it does not specify that one refers to player one and the other refers to player 2. Any suggestions would be appreciated.
class Player(pygame.sprite.Sprite):
# Constructor function
def __init__(self, x, y, colour):
# Call the parent's constructor
super().__init__()
# Set height, width
self.image = pygame.Surface([50, 50])
self.image.fill(colour)
# Make our top-left corner the passed-in location.
self.rect = self.image.get_rect()
self.rect.y = y
self.rect.x = x
# Set speed vector
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):
# Move left/right
self.rect.x += self.change_x
# Did this update cause us to hit a wall?
block_hit_list = pygame.sprite.spritecollide(self, self.walls, False)
for block in block_hit_list:
# If we are moving right, set our right side to the left side of
# the item we hit
if self.change_x > 0:
self.rect.right = block.rect.left
else:
# Otherwise if we are moving left, do the opposite.
self.rect.left = block.rect.right
# Move up/down
self.rect.y += self.change_y
# Check and see if we hit anything
block_hit_list = pygame.sprite.spritecollide(self, self.walls, False)
for block in block_hit_list:
# Reset our position based on the top/bottom of the object.
if self.change_y > 0:
self.rect.bottom = block.rect.top
else:
self.rect.top = block.rect.bottom
This is where I create the players as objects
P1 = Player(200, 200, BLUE)
P2 = Player(300, 300, WHITE)
P1.walls = wall_list
P2.walls = wall_list
all_sprite_list.add(P1)
all_sprite_list.add(P2)
Full code:
import pygame
import ctypes
user32 = ctypes.windll.user32
# Colors
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
BLUE = (50, 50, 255)
# Screen dimensions
SCREEN_WIDTH = user32.GetSystemMetrics(78)#1600
SCREEN_HEIGHT = user32.GetSystemMetrics(79)#900
WALL_THICKNESS = 10
MAP_WIDTH = SCREEN_WIDTH - 300 #1300
MAP_HEIGHT = SCREEN_HEIGHT - 160 #700
HEIGHT = SCREEN_HEIGHT - MAP_HEIGHT
#START CORDS = 150, 150
class Player(pygame.sprite.Sprite):
# Constructor function
def __init__(self, x, y, colour):
# Call the parent's constructor
super().__init__()
# Set height, width
self.image = pygame.Surface([50, 50])
self.image.fill(colour)
# Make our top-left corner the passed-in location.
self.rect = self.image.get_rect()
self.rect.y = y
self.rect.x = x
# Set speed vector
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):
# Move left/right
self.rect.x += self.change_x
# Did this update cause us to hit a wall?
block_hit_list = pygame.sprite.spritecollide(self, self.walls, False)
for block in block_hit_list:
# If we are moving right, set our right side to the left side of
# the item we hit
if self.change_x > 0:
self.rect.right = block.rect.left
else:
# Otherwise if we are moving left, do the opposite.
self.rect.left = block.rect.right
# Move up/down
self.rect.y += self.change_y
# Check and see if we hit anything
block_hit_list = pygame.sprite.spritecollide(self, self.walls, False)
for block in block_hit_list:
# Reset our position based on the top/bottom of the object.
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):
# Call the parent's constructor
super().__init__()
# Make a blue wall, of the size specified in the parameters
self.image = pygame.Surface([width, height])
self.image.fill(BLUE)
# Make our top-left corner the passed-in location.
self.rect = self.image.get_rect()
self.rect.y = y
self.rect.x = x
# Call this function so the Pygame library can initialize itself
pygame.init()
# Create an 800x600 sized screen
screen = pygame.display.set_mode([SCREEN_WIDTH, SCREEN_HEIGHT], pygame.FULLSCREEN)
# Set the title of the window
pygame.display.set_caption('Haste')
# List to hold all the sprites
all_sprite_list = pygame.sprite.Group()
# Make the walls. (x_pos, y_pos, width, height)
wall_list = pygame.sprite.Group()
#--------------------------------------------------------------------WALLS
#OUTER WALL 700 1500 - 1490. 1300
wall = Wall(150, 150, WALL_THICKNESS, MAP_HEIGHT - 150)#map height (left verticle)
wall_list.add(wall)
all_sprite_list.add(wall)
wall = Wall(160, 150, MAP_WIDTH, WALL_THICKNESS)#(top across)
wall_list.add(wall)
all_sprite_list.add(wall)
wall = Wall(160, MAP_HEIGHT - 10, MAP_WIDTH, WALL_THICKNESS)#(bottom across)
wall_list.add(wall)
all_sprite_list.add(wall)
wall = Wall(MAP_WIDTH + 150, 150, WALL_THICKNESS, MAP_HEIGHT - 150)#(right verticle)
wall_list.add(wall)
all_sprite_list.add(wall)
# Create the player paddle object
P1 = Player(200, 200, BLUE)
P2 = Player(300, 300, WHITE)
P1.walls = wall_list
P2.walls = wall_list
all_sprite_list.add(P1)
all_sprite_list.add(P2)
clock = pygame.time.Clock()
done = False
sped = 9
speed = -9
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:
P1.changespeed(speed, 0)
if event.key == pygame.K_RIGHT:
P1.changespeed(sped, 0)
if event.key == pygame.K_UP:
P1.changespeed(0, speed)
if event.key == pygame.K_DOWN:
P1.changespeed(0, sped)
if event.key == pygame.K_a:
P2.changespeed(speed, 0)
if event.key == pygame.K_d:
P2.changespeed(sped, 0)
if event.key == pygame.K_w:
P2.changespeed(0, speed)
if event.key == pygame.K_s:
P2.changespeed(0, sped)
elif event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT:
P1.changespeed(sped, 0)
if event.key == pygame.K_RIGHT:
P1.changespeed(speed, 0)
if event.key == pygame.K_UP:
P1.changespeed(0, sped)
if event.key == pygame.K_DOWN:
P1.changespeed(0, speed)
if event.key == pygame.K_a:
P2.changespeed(sped, 0)
if event.key == pygame.K_d:
P2.changespeed(speed, 0)
if event.key == pygame.K_w:
P2.changespeed(0, sped)
if event.key == pygame.K_s:
P2.changespeed(0, speed)
all_sprite_list.update()
screen.fill(BLACK)
all_sprite_list.draw(screen)
pygame.display.flip()
clock.tick(60)
pygame.quit()
I cannot use self.rect.right = self.rect.left ...
Correct: you have to write your code to refer to each Player as appropriate. You cannot refer to both of them as self.
Very simply, you have to use the appropriate variables, such as:
P1.rect.right == P2.rect.left
Whether you design this as a loop through player pairings, or check each player in turn against each of the others, depends on your system design. For instance, given only two players, you simply write a loop that flips between the two players:
active, passive = P1, P2 # P1 is the currently active player
while run_game:
...
if active.rect.right == passive.rect.left:
... #avoid collision
...
# Switch active player (take turns) at end of loop
active, passive = passive, active
Related
When i move right using the right key, i accelerate to a max speed. When i release it, i do decelerate to a stop so that is fine. However, when moving left using the left key, and after releasing it, i continue moving at a fixed speed and then come to an abrupt stop after a short while. Any idea what could be wrong with my code?
The original code is from http://programarcadegames.com/python_examples/show_file.php?file=platform_jumper.py
import pygame
# Global constants
# Colors
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
GREEN = (0, 255, 0)
RED = (255, 0, 0)
BLUE = (0, 0, 255)
# Screen dimensions
SCREEN_WIDTH = 800
SCREEN_HEIGHT = 600
class Player(pygame.sprite.Sprite):
""" This class represents the bar at the bottom that the player
controls. """
# -- Methods
def __init__(self):
""" Constructor function """
# Call the parent's constructor
super().__init__()
# Create an image of the block, and fill it with a color.
# This could also be an image loaded from the disk.
width = 40
height = 60
self.image = pygame.Surface([width, height])
self.image.fill(RED)
# Set a referance to the image rect.
self.rect = self.image.get_rect()
# Set speed vector of player
self.xVel = 0
self.yVel = 0
# List of sprites we can bump against
self.level = None
def update(self):
""" Move the player. """
# Gravity
self.calc_grav()
# Move left/right
# See if we hit anything
block_hit_list = pygame.sprite.spritecollide(self, self.level.platform_list, False)
for block in block_hit_list:
# If we are moving right,
# set our right side to the left side of the item we hit
if self.xVel > 0:
self.rect.right = block.rect.left
elif self.xVel < 0:
# Otherwise if we are moving left, do the opposite.
self.rect.left = block.rect.right
# Move up/down
self.rect.y += self.yVel
# Check and see if we hit anything
block_hit_list = pygame.sprite.spritecollide(self, self.level.platform_list, False)
for block in block_hit_list:
# Reset our position based on the top/bottom of the object.
if self.yVel > 0:
self.rect.bottom = block.rect.top
elif self.yVel < 0:
self.rect.top = block.rect.bottom
# Stop our vertical movement
self.yVel = 0
def calc_grav(self):
""" Calculate effect of gravity. """
if self.yVel == 0:
self.yVel = 1
else:
self.yVel += .35
# See if we are on the ground.
if self.rect.y >= SCREEN_HEIGHT - self.rect.height and self.yVel >= 0:
self.yVel = 0
self.rect.y = SCREEN_HEIGHT - self.rect.height
def jump(self):
""" Called when user hits 'jump' button. """
# move down a bit and see if there is a platform below us.
# Move down 2 pixels because it doesn't work well if we only move down
# 1 when working with a platform moving down.
self.rect.y += 2
platform_hit_list = pygame.sprite.spritecollide(self, self.level.platform_list, False)
self.rect.y -= 2
# If it is ok to jump, set our speed upwards
if len(platform_hit_list) > 0 or self.rect.bottom >= SCREEN_HEIGHT:
self.yVel = -10
class Platform(pygame.sprite.Sprite):
""" Platform the user can jump on """
def __init__(self, width, height):
""" Platform constructor. Assumes constructed with user passing in
an array of 5 numbers like what's defined at the top of this
code. """
super().__init__()
self.image = pygame.Surface([width, height])
self.image.fill(GREEN)
self.rect = self.image.get_rect()
class Level(object):
""" This is a generic super-class used to define a level.
Create a child class for each level with level-specific
info. """
def __init__(self, player):
""" Constructor. Pass in a handle to player. Needed for when moving platforms
collide with the player. """
self.platform_list = pygame.sprite.Group()
self.enemy_list = pygame.sprite.Group()
self.player = player
# Background image
self.background = None
# Update everythign on this level
def update(self):
""" Update everything in this level."""
self.platform_list.update()
self.enemy_list.update()
def draw(self, screen):
""" Draw everything on this level. """
# Draw the background
screen.fill(BLUE)
# Draw all the sprite lists that we have
self.platform_list.draw(screen)
self.enemy_list.draw(screen)
# Create platforms for the level
class Level_01(Level):
""" Definition for level 1. """
def __init__(self, player):
""" Create level 1. """
# Call the parent constructor
Level.__init__(self, player)
# Array with width, height, x, and y of platform
level = [[210, 70, 500, 500],
[210, 70, 200, 400],
[210, 70, 600, 300],
]
# Go through the array above and add platforms
for platform in level:
block = Platform(platform[0], platform[1])
block.rect.x = platform[2]
block.rect.y = platform[3]
block.player = self.player
self.platform_list.add(block)
def main():
""" Main Program """
pygame.init()
# Set the height and width of the screen
size = [SCREEN_WIDTH, SCREEN_HEIGHT]
screen = pygame.display.set_mode(size)
pygame.display.set_caption("Platformer Jumper")
# Create the player
player = Player()
# Create all the levels
level_list = []
level_list.append(Level_01(player))
# Set the current level
current_level_no = 0
current_level = level_list[current_level_no]
active_sprite_list = pygame.sprite.Group()
player.level = current_level
player.rect.x = 340
player.rect.y = SCREEN_HEIGHT - player.rect.height
active_sprite_list.add(player)
accel_x = 0
max_speed = 6
# Loop until the user clicks the close button.
done = False
# Used to manage how fast the screen updates
clock = pygame.time.Clock()
# -------- Main Program Loop -----------
while not done:
player_running = False
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
accel_x = -0.5
if event.key == pygame.K_RIGHT:
accel_x = 0.5
if event.key == pygame.K_SPACE:
player.jump()
elif event.type == pygame.KEYUP:
if event.key in (pygame.K_LEFT, pygame.K_RIGHT):
accel_x = 0
player.xVel += accel_x # Accelerate.
if abs(player.xVel) >= max_speed: # If max_speed is exceeded.
# Normalize the x_change and multiply it with the max_speed.
player.xVel = player.xVel / abs(player.xVel) * max_speed
# Decelerate if no key is pressed.
if accel_x == 0:
player.xVel *= 0.5
player.rect.x += player.xVel
# Update the player.
active_sprite_list.update()
# Update items in the level
current_level.update()
# If the player gets near the right side, shift the world left (-x)
if player.rect.right > SCREEN_WIDTH:
player.rect.right = SCREEN_WIDTH
# If the player gets near the left side, shift the world right (+x)
if player.rect.left < 0:
player.rect.left = 0
# ALL CODE TO DRAW SHOULD GO BELOW THIS COMMENT
current_level.draw(screen)
active_sprite_list.draw(screen)
# ALL CODE TO DRAW SHOULD GO ABOVE THIS COMMENT
# Limit to 60 frames per second
clock.tick(60)
# Go ahead and update the screen with what we've drawn.
pygame.display.flip()
# Be IDLE friendly. If you forget this line, the program will 'hang'
# on exit.
pygame.quit()
if __name__ == "__main__":
main()
The isssue is caused, because the pygame.Rect operates with integral data:
The coordinates for Rect objects are all integers. [...]
When you do
player.rect.x += player.xVel
it is the same as you would do:
player.rect.x = int(player.rect.x + player.xVel)
The fraction part of player.xVel gets lost. The result of the addition operation is truncated and the player tends to the coordinate with the lower value (left).
Add a floating point x coordinate (self.px) to the class Player and use it to calculate the position of the player. Use round to set the integral rectangle position from self.px:
class Player(pygame.sprite.Sprite):
def __init__(self):
# [...]
# Set a referance to the image rect.
self.rect = self.image.get_rect()
self.px = self.rect.x
# [...]
def update(self):
# [...]
block_hit_list = pygame.sprite.spritecollide(self, self.level.platform_list, False)
block_hit_list = pygame.sprite.spritecollide(self, self.level.platform_list, False)
for block in block_hit_list:
# If we are moving right,
# set our right side to the left side of the item we hit
if self.xVel > 0:
self.rect.right = block.rect.left
elif self.xVel < 0:
# Otherwise if we are moving left, do the opposite.
self.rect.left = block.rect.right
self.px = self.rect.x
def main():
# [...]
player.rect.x = 340
player.px = player.rect.x
# [...]
while not done:
# [...]
player.px += player.xVel
player.rect.x = round(player.px)
# [...]
This question already has answers here:
Problems getting pygame to show anything but a blank screen on Macos
(10 answers)
pygame installation issue in mac os
(5 answers)
Closed 2 years ago.
I run my code for my game and I get this error:
for event in pygame.event.get():
pygame.error: video system not initialized
This is my code here, I decided to post all of it incase there is another variable that is affecting it. I have looked online and only seen answers that say "You have no included pygame.init()"
import pygame
import random
import os
import sys
# Global constants
# Colors
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
GREEN = (0, 255, 0)
RED = (255, 0, 0)
BLUE = (0, 0, 255)
# Screen dimensions
SCREEN_WIDTH = 1024
SCREEN_HEIGHT = 400
game_folder = os.path.dirname(__file__)
img_folder = os.path.join(game_folder, "PyGame Images")
class Player(pygame.sprite.Sprite):
"""
This class represents the bar at the bottom that the player controls.
"""
# -- Methods
def __init__(self):
""" Constructor function """
# Call the parent's constructor
super().__init__()
# Create an image of the block, and fill it with a color.
# This could also be an image loaded from the disk.
width = 40
height = 60
self.image = pygame.image.load(os.path.join(img_folder,"0.png")).convert()
self.image.set_colorkey(BLACK)
# Set a referance to the image rect.
self.rect = self.image.get_rect()
# Set speed vector of player
self.change_x = 0
self.change_y = 0
# List of sprites we can bump against
self.level = None
def update(self):
""" Move the player. """
# Gravity
self.calc_grav()
# Move left/right
self.rect.x += self.change_x
# See if we hit anything
block_hit_list = pygame.sprite.spritecollide(self, self.level.platform_list, False)
for block in block_hit_list:
# If we are moving right,
# set our right side to the left side of the item we hit
if self.change_x > 0:
self.rect.right = block.rect.left
elif self.change_x < 0:
# Otherwise if we are moving left, do the opposite.
self.rect.left = block.rect.right
# Move up/down
self.rect.y += self.change_y
# Check and see if we hit anything
block_hit_list = pygame.sprite.spritecollide(self, self.level.platform_list, False)
for block in block_hit_list:
# Reset our position based on the top/bottom of the object.
if self.change_y > 0:
self.rect.bottom = block.rect.top
elif self.change_y < 0:
self.rect.top = block.rect.bottom
# Stop our vertical movement
self.change_y = 0
def calc_grav(self):
""" Calculate effect of gravity. """
if self.change_y == 0:
self.change_y = 1
else:
self.change_y += .35
# See if we are on the ground.
if self.rect.y >= SCREEN_HEIGHT - self.rect.height and self.change_y >= 0:
self.change_y = 0
self.rect.y = SCREEN_HEIGHT - self.rect.height
def jump(self):
""" Called when user hits 'jump' button. """
# move down a bit and see if there is a platform below us.
# Move down 2 pixels because it doesn't work well if we only move down 1
# when working with a platform moving down.
self.rect.y += 2
platform_hit_list = pygame.sprite.spritecollide(self, self.level.platform_list, False)
self.rect.y -= 2
# If it is ok to jump, set our speed upwards
if len(platform_hit_list) > 0 or self.rect.bottom >= SCREEN_HEIGHT:
self.change_y = -10
# Player-controlled movement:
def go_left(self):
""" Called when the user hits the A key. """
self.change_x = -6
def go_right(self):
""" Called when the user hits the D key. """
self.change_x = 6
def stop(self):
""" Called when the user lets off the keyboard. """
self.change_x = 0
class Platform(pygame.sprite.Sprite):
""" Platform the user can jump on """
def __init__(self, width, height):
""" Platform constructor. Assumes constructed with user passing in
an array of 5 numbers like what's defined at the top of this code.
"""
super().__init__()
self.image = pygame.Surface([width, height])
self.image.fill(GREEN)
self.rect = self.image.get_rect()
return
class Level():
""" This is a generic super-class used to define a level.
Create a child class for each level with level-specific
info. """
def __init__(self, player):
""" Constructor. Pass in a handle to player. Needed for when moving
platforms collide with the player. """
self.platform_list = pygame.sprite.Group()
self.enemy_list = pygame.sprite.Group()
self.player = player
# How far this world has been scrolled left/right
self.world_shift = 0
# Update everythign on this level
def update(self):
""" Update everything in this level."""
self.platform_list.update()
self.enemy_list.update()
def draw(self, screen):
""" Draw everything on this level. """
# Draw the background
screen.fill(BLUE)
# Draw all the sprite lists that we have
self.platform_list.draw(screen)
self.enemy_list.draw(screen)
def shift_world(self, shift_x):
""" When the user moves left/right and we need to scroll
everything: """
# Keep track of the shift amount
self.world_shift += shift_x
# Go through all the sprite lists and shift
for platform in self.platform_list:
platform.rect.x += shift_x
for enemy in self.enemy_list:
enemy.rect.x += shift_x
# Create platforms for the level
class Level_01(Level):
""" Definition for level 1. """
def __init__(self, player):
""" Create level 1. """
# Call the parent constructor
Level.__init__(self, player)
self.level_limit = -1000
# Array with width, height, x, and y of platform
level = [[210, 70, 500, 500],
[210, 70, 800, 400],
[210, 70, 1000, 500],
[210, 70, 1120, 280],
]
# Go through the array above and add platforms
for platform in level:
block = Platform(platform[0], platform[1])
block.rect.x = platform[2]
block.rect.y = platform[3]
block.player = self.player
self.platform_list.add(block)
# Create platforms for the level
class Level_02(Level):
""" Definition for level 2. """
def __init__(self, player):
""" Create level 1. """
# Call the parent constructor
Level.__init__(self, player)
self.level_limit = -1000
# Array with type of platform, and x, y location of the platform.
level = [[210, 30, 450, 570],
[210, 30, 850, 420],
[210, 30, 1000, 520],
[210, 30, 1120, 280],
]
# Go through the array above and add platforms
for platform in level:
block = Platform(platform[0], platform[1])
block.rect.x = platform[2]
block.rect.y = platform[3]
block.player = self.player
self.platform_list.add(block)
def main():
""" Main Program """
pygame.init()
mouse.set.visible(True)
# Set the height and width of the screen
size = [SCREEN_WIDTH, SCREEN_HEIGHT]
screen = pygame.display.set_mode(size)
pygame.display.set_caption("Dash Dojo")
# Create the player
player = Player()
# Create all the levels
level_list = []
level_list.append(Level_01(player))
level_list.append(Level_02(player))
# Set the current level
current_level_no = 0
current_level = level_list[current_level_no]
active_sprite_list = pygame.sprite.Group()
player.level = current_level
player.rect.x = 340
player.rect.y = SCREEN_HEIGHT - player.rect.height
active_sprite_list.add(player)
# Loop until the user clicks the close button.
done = False
# Used to manage how fast the screen updates
clock = pygame.time.Clock()
# -------- Main Program Loop -----------
player_images = []
player_images.append(pygame.image.load(os.path.join(img_folder,'15.png')))
player_images.append(pygame.image.load(os.path.join(img_folder,'16.png')))
player_images.append(pygame.image.load(os.path.join(img_folder,'17.png')))
player_images.append(pygame.image.load(os.path.join(img_folder,'18.png')))
player_images.append(pygame.image.load(os.path.join(img_folder,'19.png')))
player_images.append(pygame.image.load(os.path.join(img_folder,'20.png')))
player_images.append(pygame.image.load(os.path.join(img_folder,'21.png')))
player_images.append(pygame.image.load(os.path.join(img_folder,'22.png')))
player_images.append(pygame.image.load(os.path.join(img_folder,'23.png')))
player_images.append(pygame.image.load(os.path.join(img_folder,'24.png')))
player_current = 0
player = player_images[ player_current ]
playerX = 610
playerY = 350
walking = False
walking_steps = 0
# --- events ---
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_a:
player_current = (player_current + 1) % len(player_images)
player = pygame.image.load(images_running[player_current])
player.go_left()
if event.key == pygame.K_d:
player.go_right()
if event.key == pygame.K_w:
player.jump()
if event.type == pygame.KEYUP:
if event.key == pygame.K_a and player.change_x < 0:
player.stop()
if event.key == pygame.K_d and player.change_x > 0:
player.stop()
# --- moves ---
if walking == True:
# here you need to check some counter
# if it is time for next step to walk slower
# but don't use `time.sleep()`
if walking_steps > 0:
player_current = (player_current + 1) % len(player_images)
player = player_images[ player_current ]
playerY = playerY + 1
walking_steps -= 1
else:
walking = False
# --- draws ---
screen.fill((0, 0, 0))
screen.blit(player, (playerX, playerY))
pygame.display.flip()
# Update the player
active_sprite_list.update()
# Update items in the level
current_level.update()
# If the player gets near the right side, shift the world left (-x)
if player.rect.right >= 500:
diff = player.rect.right - 500
player.rect.right = 500
current_level.shift_world(-diff)
# If the player gets near the left side, shift the world right (+x)
if player.rect.left <= 120:
diff = 120 - player.rect.left
player.rect.left = 120
current_level.shift_world(diff)
# If the player gets to the end of the level, go to the next level
current_position = player.rect.x + current_level.world_shift
if current_position < current_level.level_limit:
player.rect.x = 120
if current_level_no < len(level_list)-1:
current_level_no += 1
current_level = level_list[current_level_no]
player.level = current_level
# ALL CODE TO DRAW SHOULD GO BELOW THIS COMMENT
current_level.draw(screen)
active_sprite_list.draw(screen)
# ALL CODE TO DRAW SHOULD GO ABOVE THIS COMMENT
# Limit to 60 frames per second
clock.tick(60)
# Go ahead and update the screen with what we've drawn.
pygame.display.flip()
# Be IDLE friendly. If you forget this line, the program will 'hang'
# on exit.
pygame.quit()
if __name__ == "__main__":
main()
When this part of the code has been run, it shows the sprite however when the arrow keys are pressed nothing moves, ive tried to use print statements to attempt to debug but nothing has come up, what is the issue and how do i solve it? Here ive added everything relating to the movement in my program the other files include the screen and the exit loop
from spritechanges import *
from lklk import *
import pygame
import time
WHITE = (255, 255, 255)
BLACK = (0, 0, 0, 0)
clock = pygame.time.Clock()
FPS = 120
# Create a surface/image and draw a circle onto it.
sprite_image = pygame.Surface((50, 50))
pygame.draw.circle(sprite_image, WHITE, [25, 25], 20)
# Create surface/image draw a line onto it
width = 40
height = 60
# Create an instance of the Sprite class.
class Sprite(pygame.sprite.Sprite):
def __init__(self, pos):
super(Sprite, self).__init__() # platform
self.width = width
self.height = height
self.platform = pygame.Surface((width, height))
self.platform.fill(WHITE)
# set a reference to the image rect
self.rect = self.platform.get_rect()
# Assign the global image to `self.image`.
self.image = sprite_image
# Create a rect which will be used as blit
# position and for the collision detection.
self.rect = self.image.get_rect()
# Set the rect's center to the passed `pos`.
self.rect.center = pos
self._vx = 0
self._vy = 0
# Assign the pos also to these attributes.
self._spritex = pos[0]
self._spritey = pos[1]
# set of sprites sprite can bump against
self.level = None
def update(self):
self._gravity = 99
block_hit_list = pygame.sprite.spritecollide(self, self.level.platform_list, False)
for block in block_hit_list:
if self._vx > 0:
self.rect.right = block.rect.left
elif self._vx < 0:
# Otherwise if we are moving left, do the opposite.
self.rect.left = block.rect.right
self.rect.y += self.change_y
# Check and see if we hit anything
block_hit_list = pygame.sprite.spritecollide(self, self.level.platform_list, False)
for block in block_hit_list:
# Reset our position based on the top/bottom of the object.
if self._vy > 0:
self.rect.bottom = block.rect.top
elif self._vy < 0:
self.rect.top = block.rect.bottom
# Stop our vertical movement
self._vy = 0
self._vx = 0
self.rect.y += 2
platform_hit_list = pygame.sprite.spritecollide(self, self.level.platform_list, False)
self.rect.y -= 2
# If it is ok to jump, set our speed upwards
if len(platform_hit_list) > 0 or self.rect.bottom >= H:
self._xy = -10
# Player-controlled movement:
def go_left(self):
""" Called when the user hits the left arrow. """
self._vx = -6
def go_right(self):
""" Called when the user hits the right arrow. """
self._vx = 6
def stop(self):
""" Called when the user lets off the keyboard. """
self._vx = 0
# Adjust the position.
self._spritex += self._vx
self._spritey += self._vy
# And update the center of the rect.
self.rect.center = (self._spritex, self._spritey)
sprite = Sprite([400, 550])
active_sprite_list = pygame.sprite.Group()
sprite.level = current_level
sprite.rect.x = 340
sprite.rect.y = H - sprite.rect.height
active_sprite_list.add(sprite)
done = True
while not done:
events()
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
sprite.go_left()
if event.key == pygame.K_RIGHT:
sprite.go_right()
if event.key == pygame.K_UP:
sprite.jump()
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT and sprite.change_x < 0:
sprite.stop()
if event.key == pygame.K_RIGHT and sprite.change_x > 0:
sprite.stop()
# If the player gets near the right side, shift the world left (-x)
if sprite.rect.right > W:
sprite.rect.right = W
# If the player gets near the left side, shift the world right (+x)
if sprite.rect.left < 0:
sprite.rect.left = 0
DS.fill(BLACK)
# Blit the sprite's image at the sprite's rect.topleft position.
DS.blit(sprite.image, sprite.rect)
pygame.display.flip()
clock.tick(FPS)
pygame.quit()
There's some code in the stop method that should be in the update method. The jump code needs to be in a separate jump method. Also, call active_sprite_list.update() in the main while loop to update all contained sprites and active_sprite_list.draw(DS) to draw them. Here's a complete working example:
import pygame
pygame.init()
clock = pygame.time.Clock()
FPS = 60
DS = pygame.display.set_mode((640, 480))
sprite_image = pygame.Surface((50, 50), pygame.SRCALPHA)
pygame.draw.circle(sprite_image, (90, 100, 200), [25, 25], 25)
W, H = DS.get_size()
class Platform(pygame.sprite.Sprite):
def __init__(self, x, y, w, h):
super(Platform, self).__init__()
self.image = pygame.Surface((w, h))
self.image.fill((90, 90, 120))
self.rect = self.image.get_rect(topleft=(x, y))
class Sprite(pygame.sprite.Sprite):
def __init__(self, pos):
super(Sprite, self).__init__()
self.image = sprite_image
self.rect = self.image.get_rect()
self.rect.center = pos
self._vx = 0
self._vy = 0
self._spritex = pos[0]
self._spritey = pos[1]
self.level = None
self._gravity = .9
def update(self):
# Adjust the x-position.
self._spritex += self._vx
self.rect.centerx = self._spritex # And update the rect.
block_hit_list = pygame.sprite.spritecollide(self, self.level, False)
for block in block_hit_list:
if self._vx > 0:
self.rect.right = block.rect.left
elif self._vx < 0:
# Otherwise if we are moving left, do the opposite.
self.rect.left = block.rect.right
self._spritex = self.rect.centerx # Update the position.
# Adjust the y-position.
self._vy += self._gravity # Accelerate downwards.
self._spritey += self._vy
self.rect.centery = self._spritey # And update the rect.
# Check and see if we hit anything
block_hit_list = pygame.sprite.spritecollide(self, self.level, False)
for block in block_hit_list:
# Reset our position based on the top/bottom of the object.
if self._vy > 0:
self.rect.bottom = block.rect.top
elif self._vy < 0:
self.rect.top = block.rect.bottom
self._spritey = self.rect.centery # Update the position.
# Stop our vertical movement
self._vy = 0
def jump(self):
self.rect.y += 2
platform_hit_list = pygame.sprite.spritecollide(self, self.level, False)
self.rect.y -= 2
# If it is ok to jump, set our speed upwards
if len(platform_hit_list) > 0 or self.rect.bottom >= H:
self._vy = -17
def go_left(self):
""" Called when the user hits the left arrow. """
self._vx = -3
def go_right(self):
""" Called when the user hits the right arrow. """
self._vx = 3
def stop(self):
""" Called when the user lets off the keyboard. """
self._vx = 0
sprite = Sprite([60, 60])
active_sprite_list = pygame.sprite.Group(sprite)
sprite.level = pygame.sprite.Group(
Platform(20, 400, 200, 20), Platform(220, 300, 20, 120),
Platform(220, 300, 300, 20))
active_sprite_list.add(sprite.level)
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:
sprite.go_left()
if event.key == pygame.K_RIGHT:
sprite.go_right()
if event.key == pygame.K_UP:
sprite.jump()
elif event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT and sprite._vx < 0:
sprite.stop()
if event.key == pygame.K_RIGHT and sprite._vx > 0:
sprite.stop()
# If the player gets near the right side, shift the world left (-x)
if sprite.rect.right > W:
sprite.rect.right = W
# If the player gets near the left side, shift the world right (+x)
if sprite.rect.left < 0:
sprite.rect.left = 0
active_sprite_list.update()
DS.fill((50, 50, 50))
# Blit the sprite's image at the sprite's rect.topleft position.
active_sprite_list.draw(DS)
pygame.display.flip()
clock.tick(FPS)
pygame.quit()
Is this the problem?
self._vx = 0
Whenever the user lets off the keyboard, you end up adjusting the position by zero?
import pygame
#Colours used throughout the game
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
GREEN = (0, 255, 0)
RED = (255, 0, 0)
BLUE = (0, 0, 255)
BackGround = ('D:\Idea 2\sky_colour_image.jpg', [0,0])
# Screen dimensions
SCREEN_WIDTH = 800
SCREEN_HEIGHT = 600
#Player class
class Player(pygame.sprite.Sprite):
#Player image
def __init__(self):
super().__init__()
# Create an image of the block, and fill it with a color.
# This could also be an image loaded from the disk.
width = 40
height = 40
self.image = pygame.Surface([width, height])
self.image.fill(BLUE)
# Set a referance to the image rect.
self.rect = self.image.get_rect()
# Set speed vector of player
self.change_x = 0
self.change_y = 0
# List of sprites we can bump against
self.level = None
def update(self):
""" Move the player. """
# Gravity
self.calc_grav()
# Move left/right
self.rect.x += self.change_x
# See if we hit anything
block_hit_list = pygame.sprite.spritecollide(self,self.level.platform_list, False)
for block in block_hit_list:
# If we are moving right,
# set our right side to the left side of the item we hit
if self.change_x > 0:
self.rect.right = block.rect.left
elif self.change_x < 0:
# Otherwise if we are moving left, do the opposite.
self.rect.left = block.rect.right
# Move up/down
self.rect.y += self.change_y
# Check and see if we hit anything
block_hit_list = pygame.sprite.spritecollide(self, self.level.platform_list, False)
for block in block_hit_list:
# Reset our position based on the top/bottom of the object.
if self.change_y > 0:
self.rect.bottom = block.rect.top
elif self.change_y < 0:
self.rect.top = block.rect.bottom
# Stop our vertical movement
self.change_y = 0
def calc_grav(self):
if self.change_y == 0:
self.change_y = 1
else:
self.change_y += .35
# See if we are on the ground.
if self.rect.y >= SCREEN_HEIGHT - self.rect.height and self.change_y >= 0:
self.change_y = 0
self.rect.y = SCREEN_HEIGHT - self.rect.height
def jump(self):
# move down a bit and see if there is a platform below us.
# Move down 2 pixels because it doesn't work well if we only move down
# 1 when working with a platform moving down.
self.rect.y += 2
platform_hit_list = pygame.sprite.spritecollide(self, self.level.platform_list, False)
self.rect.y -= 2
# If it is ok to jump, set our speed upwards
if len(platform_hit_list) > 0 or self.rect.bottom >= SCREEN_HEIGHT:
self.change_y = -10
# Player-controlled movement:
def go_left(self):
self.change_x = -6
def go_right(self):
self.change_x = 6
def stop(self):
self.change_x = 0
class Platform(pygame.sprite.Sprite):
def __init__(self, width, height):
super().__init__()
self.image = pygame.Surface([width, height])
self.image.fill(GREEN)
self.rect = self.image.get_rect()
class Level(object):
def __init__(self, player):
self.platform_list = pygame.sprite.Group()
self.enemy_list = pygame.sprite.Group()
self.player = player
# Update everythign on this level
def update(self):
self.platform_list.update()
self.enemy_list.update()
def draw(self, screen):
# Draw the background
screen.fill(BLUE)
# Draw all the sprite lists that we have
self.platform_list.draw(screen)
self.enemy_list.draw(screen)
# Background class
class Background(pygame.sprite.Sprite):
def __init__(self, image_file, location):
pygame.sprite.Sprite.__init__(self) #call Sprite initializer
self.image = pygame.image.load("D:\Idea 2\sky_colour_image.jpg")
self.rect = self.image.get_rect()
self.rect.left, self.rect.top = location
# Create platforms for the level
class Level_01(Level):
def __init__(self, player):
# Call the parent constructor
Level.__init__(self, player)
# Array with width, height, x, and y of platform
level = [[210, 70, 500, 500],
[210, 70, 200, 400],
[210, 70, 600, 300],
]
# Go through the array above and add platforms
for platform in level:
block = Platform(platform[0], platform[1])
block.rect.x = platform[2]
block.rect.y = platform[3]
block.player = self.player
self.platform_list.add(block)
def main():
pygame.init()
# Set the height and width of the screen
size = [SCREEN_WIDTH, SCREEN_HEIGHT]
screen = pygame.display.set_mode(size)
pygame.display.set_caption("Platformer Jumper")
# Create the player
player = Player()
# Create all the levels
level_list = []
level_list.append( Level_01(player) )
# Set the current level
current_level_no = 0
current_level = level_list[current_level_no]
active_sprite_list = pygame.sprite.Group()
player.level = current_level
player.rect.x = 340
player.rect.y = SCREEN_HEIGHT - player.rect.height
active_sprite_list.add(player)
# Loop until the user clicks the close button.
done = False
# Used to manage how fast the screen updates
clock = pygame.time.Clock()
# -------- Main Program Loop -----------
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_LEFT:
player.go_left()
if event.key == pygame.K_RIGHT:
player.go_right()
if event.key == pygame.K_UP:
player.jump()
screen.fill([255, 255, 255])
screen.blit(BackGround.image, BackGround.rect)
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT and player.change_x < 0:
player.stop()
if event.key == pygame.K_RIGHT and player.change_x > 0:
player.stop()
# Update the player.
active_sprite_list.update()
# Update items in the level
current_level.update()
# If the player gets near the right side, shift the world left (-x)
if player.rect.right > SCREEN_WIDTH:
player.rect.right = SCREEN_WIDTH
# If the player gets near the left side, shift the world right (+x)
if player.rect.left < 0:
player.rect.left = 0
current_level.draw(screen)
active_sprite_list.draw(screen)
# Limit to 60 frames per second
clock.tick(60)
# Go ahead and update the screen with what we've drawn.
pygame.display.flip()
if __name__ == "__main__":
main()
So far this is supposed to be (nothing exciting yet) a simple platform jumper with sky backgrouns. Creating a game for a computing project, not that experienced in python. Aim to be adding in moving platforms etc soon, if anyone could help with that or the error I'd appreciate it.
Basically you are asking an object (looks like self here) and asking it for the image that is part of it. BUT the tuple doesn't have an attribute of image.
Not sure here, but I think you may have an indent error.
def __init__() should be indented since it is a method on your class. Python does not use curly braces, but space is significant.
Complete novice, new to programming in general. I am trying to write a side scroller game in python, using pygame. I have created three different libraries for my sprite classes for: the player, the enemy, and the land. I made the land a sprite so that the player can interact (collide) with different objects in the land class and not be able to pass through them. The issue I am having is that I want the enemy sprite to interact with the land sprite as well. Ideally, I want the enemy sprites to start at point "x" and be set in motion (-2) until it comes into contact with the land sprite, at which point I want it to reverse direction. I have been trying everything I can think of, and searching online for a solution to make this work with no success. It seems like it should be really simple, but I can't make it work.
Thank you for your time.
here's my code:
land sprite :
import pygame
class Object(pygame.sprite.Sprite):
def __init__(self,image_file):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load(image_file)
self.rect = self.image.get_rect()
player sprite :
import pygame
class Player(pygame.sprite.Sprite):
change_x = 0
change_y = 0
jump_ready = False
frame_since_collision = 0
frame_since_jump = 0
frame = 0
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.images = []
for i in range(1,9):
img = pygame.image.load("pit"+str(i)+".png").convert()
img.set_colorkey((0,0,0))
self.images.append(img)
self.image = self.images[0]
self.rect = self.image.get_rect()
def changespeed_x(self,x):
self.change_x = x
def changespeed_y(self,y):
self.change_y = y
def update(self,ground,brick,enemy):
if self.change_x < 0:
self.frame += 1
if self.frame > 3*4:
self.frame = 0
self.image = self.images[self.frame//4]
if self.change_x > 0:
self.frame += 1
if self.frame > 3*4:
self.frame = 0
self.image = self.images[self.frame//4+4]
old_x = self.rect.x
new_x = old_x + self.change_x
self.rect.x = new_x
player_health = 5
hurt = pygame.sprite.spritecollide(self,enemy,False)
if hurt:
player_health -= 1
print(player_health)
brick_break = pygame.sprite.spritecollide(self,brick,True)
collide = pygame.sprite.spritecollide(self,ground,False)
if collide:
self.rect.x = old_x
old_y = self.rect.y
new_y = old_y + self.change_y
self.rect.y = new_y
touch_list = pygame.sprite.spritecollide(self,ground,False)
for ground in touch_list:
self.rect.y = old_y
self.rect.x = old_x
self.change_y = 0
self.frame_since_collision = 0
if self.frame_since_collision < 6 and self.frame_since_jump < 6:
self.frame_since_jump = 100
self.change_y -= 8
self.frame_since_collision += 1
self.frame_since_jump += 1
def calc_grav(self):
self.change_y += .35
if self.rect.y >= 450 and self.change_y >= 0:
self.change_y = 0
self.rect.y = 450
self.frame_since_collision = 0
def jump(self,blocks):
self.jump_ready = True
self.frame_since_jump = 0
this is the enemy sprite that works, it only moves left, every time I tried a variation of the collision code like I have in the player class the sprite would just stop when it collided with the land sprite
enemy sprite :
import pygame
class Enemy(pygame.sprite.Sprite):
def __init__(self,image_file):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load(image_file)
self.image = self.image.convert()
self.image.set_colorkey((0,0,0))
self.rect = self.image.get_rect()
def update(self,ground):
change_x = -2
self.rect.x += change_x
and my main program code :
# first must import
import pygame
import random
import thing
import enemy
import player
# initialize the game engine
pygame.init()
# define some colors
# more color combos at www.colorpicker.com
black = ( 0, 0, 0)
white = ( 255, 255, 255)
green = (0, 255, 0)
red = (255, 0, 0)
blue = (131,226,252)
# open and set window size.
screen_width = 700
screen_height = 350
screen = pygame.display.set_mode([screen_width,screen_height])
break_list = pygame.sprite.Group()
land_list = pygame.sprite.Group()
enemy_list = pygame.sprite.Group()
all_sprites_list = pygame.sprite.Group()
cloud = pygame.image.load("cumulus-huge.png").convert()
for x in range(300,500,60):
brick = thing.Object("birck.png")
brick.rect.x = x
brick.rect.y = 180
break_list.add(brick)
all_sprites_list.add(brick)
for x in range(0,200,50):
wall = thing.Object("Sky3.png")
wall.rect.x = -180
wall.rect.y = x
land_list.add(wall)
all_sprites_list.add(wall)
for x in range (-50,1400,70):
ground = thing.Object("Ground2.png")
ground.rect.x = x
ground.rect.y = 305
land_list.add(ground)
all_sprites_list.add(ground)
monster = enemy.Enemy("monster1.png")
monster.rect.x = 650
monster.rect.y = 250
enemy_list.add(monster)
all_sprites_list.add(monster)
for x in range(760,1070,300):
pipe = thing.Object("pipe-top.png")
pipe.rect.x = x
pipe.rect.y = 225
land_list.add(pipe)
all_sprites_list.add(pipe)
player = player.Player()
player.rect.x = 10
player.rect.y = 230
all_sprites_list.add(player)
# set the window title
pygame.display.set_caption("Scroller")
# the following code sets up the main program loop
# Boolean Variable to loop until the user clicks the close button.
done = False # loop control
# used to manage how fast the screen updates
clock = pygame.time.Clock() # controls how fast game runs
# Main Program Loop
while done == False:
# ALL EVENT PROCESSING (input) SHOULD GO BELOW THIS COMMENT
for event in pygame.event.get(): # user did something
if event.type == pygame.QUIT: #If user clicked close
done = True # flag that we are done so we exit this loop
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
player.changespeed_x(-6)
if event.key == pygame.K_RIGHT:
player.changespeed_x(6)
if event.key == pygame.K_UP:
player.jump(land_list)
if event.key == pygame.K_DOWN:
player.changespeed_y(6)
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT:
player.changespeed_x(-0)
if event.key == pygame.K_RIGHT:
player.changespeed_x(0)
monster.update()
player.update(land_list,break_list,enemy_list)
player.calc_grav()
# ALL EVENT PROCESSING (input) SHOULD GO ABOVE THIS COMMENT
# ALL GAME LOGIC (process) SHOULD GO BELOW THIS COMMENT
if player.rect.x >= 500:
diff = player.rect.x - 500
player.rect.x=500
for ground in land_list:
ground.rect.x -= diff
for brick in break_list:
brick.rect.x -= diff
for monster in enemy_list:
monster.rect.x -= diff
if player.rect.x <= 15:
diff = 15 - player.rect.x
player.rect.x = 15
for ground in land_list:
ground.rect.x += diff
for brick in break_list:
brick.rect.x += diff
for monster in enemy_list:
monster.rect.x += diff
# ALL GAME LOGIC (process) SHOULD GO ABOVE THIS COMMENT
# ALL CODE TO DRAW (output) SHOULD GO BELOW THIS COMMENT
# First, clear the screen. Don't put other drawing commands
# above this, or they will be erased with this command.
screen.fill(blue)
screen.blit(cloud,[200,0])
cloud.set_colorkey(black)
all_sprites_list.draw(screen)
# ALL CODE TO DRAW (output) SHOULD GO ABOVE THIS COMMENT
# This will update the screen with what's been drawn.
pygame.display.flip()
# limit to 30frames per second
clock.tick(30)
pygame.quit()
Your enemy class should be like this:
class Enemy(pygame.sprite.Sprite):
def __init__(self,image_file):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load(image_file)
self.image = self.image.convert()
self.image.set_colorkey((0,0,0))
self.rect = self.image.get_rect()
self.vel = -2
def update(self,ground):
self.rect.x += self.vel
Then in your update loop, implement this pseudocode:
...
if monster collides with ground:
monster.vel *= -1
...