I am getting this error when trying to run my code, the error.
Traceback (most recent call last):
File "D:/Colin Lewis/pythonProject3/Lib/import_tileset.py", line 264, in <module>
main()
File "D:/Colin Lewis/pythonProject3/Lib/import_tileset.py", line 259, in main
window.setup()
File "D:/Colin Lewis/pythonProject3/Lib/import_tileset.py", line 181, in setup
self.scene.add_sprite(LAYER_NAME_PLAYER, self.player_sprite)
File "D:\Colin Lewis\pythonProject3\lib\site-packages\arcade\scene.py", line 95, in add_sprite
new_list.append(sprite)
File "D:\Colin Lewis\pythonProject3\lib\site-packages\arcade\sprite_list\sprite_list.py", line 625, in append
self._atlas.add(texture)
File "D:\Colin Lewis\pythonProject3\lib\site-packages\arcade\texture_atlas.py", line 284, in add
if self.has_texture(texture):
File "D:\Colin Lewis\pythonProject3\lib\site-packages\arcade\texture_atlas.py", line 452, in has_texture
return texture.name in self._atlas_regions
AttributeError: 'str' object has no attribute 'name'
If anyone knows how to solve this, please help me.
here is my code:
# Colin A. Lewis
# Path of Torment
# Friday, April 1st 2022
# Coding, App & Game Design - A.M.
import os
import arcade
# Constants
SCREEN_WIDTH = 1900
SCREEN_HEIGHT = 1200
SCREEN_TITLE = "Forest_of_Acid_&_Spikes"
# Constants used to scale our sprites from their original size
TILE_SCALING = 0.75
CHARACTER_SCALING = TILE_SCALING * 2
SPRITE_PIXEL_SIZE = 64
GRID_PIXEL_SIZE = SPRITE_PIXEL_SIZE * TILE_SCALING
# How many pixels to keep as a minimum margin between the character
# and the edge of the screen.
LEFT_VIEWPORT_MARGIN = 200
RIGHT_VIEWPORT_MARGIN = 200
BOTTOM_VIEWPORT_MARGIN = 150
TOP_VIEWPORT_MARGIN = 100
# Movement speed of player, in pixels per frame
PLAYER_MOVEMENT_SPEED = 3
GRAVITY = 1.5
PLAYER_JUMP_SPEED = 30
PLAYER_START_X = 1
PLAYER_START_Y = 30
# Constants used to track if the player is facing left or right
RIGHT_FACING = 1
LEFT_FACING = 0
LAYER_NAME_TERRAIN = "Terrain"
LAYER_NAME_HAZARDS = "hazards"
LAYER_NAME_PLAYER = "player"
def load_frame(filename):
return [
arcade.load_texture(filename),
arcade.load_texture(filename, flipped_horizontally=True),
]
class Entity(arcade.Sprite):
def __init__(self):
super().__init__()
self.facing_direction = RIGHT_FACING
self.currentTexture = 0
self.scale = CHARACTER_SCALING
character = f"./Character/Run (1).png"
self.runFrames = []
for i in range(1, 8):
textures = f"{character}/Character/Run (1){i}.png"
self.runFrames.append(textures)
self.textures = self.runFrames[0][0]
class PlayerCharacter(Entity):
def __init__(self):
super().__init__()
def updateAnimation(self, delta_time: float = 1 / 8):
if self.change_x < 0 and self.facing_direction == RIGHT_FACING:
self.facing_direction = LEFT_FACING
elif self.change_x < 0 and self.facing_direction == LEFT_FACING:
self.facing_direction = RIGHT_FACING
# player run animation
if self.change_x != 0:
self.currentTexture += 1
if self.currentTexture > len(self.runFrames) - 1:
self.currentTexture = 0
self.currentTexture = self.runFrames[self.currentTexture][self.facing_direction]
class MyGame(arcade.Window):
def __init__(self):
# Calls from the parent class and sets up the main window
super().__init__(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_TITLE)
self.left_pressed = False
self.right_pressed = False
self.jump_needs_reset = False
self.up_pressed = False
self.down_pressed = False
# Set the path to start with this program
# File assertion
file_path = os.path.dirname(
os.path.abspath("D:\Colin Lewis\pythonProject3\Lib"))
os.chdir(file_path)
# Our TileMap Object
self.tile_map = ""
# Our Scene Object
self.scene = None
# Separate variable that holds the player sprite
self.player_sprite = None
# Our 'physics' engine
self.physics_engine = None
# A Camera that can be used for scrolling the screen
self.camera = None
# A Camera that can be used to draw GUI elements
self.gui_camera = None
self.end_of_map = 0
path = r"D:\\Colin Lewis\\pythonProject3\\Lib\\Forest_of_Acid_&_Spikes.tmx"
assert os.path.isfile(path)
with open(path, "r") as r:
pass
def setup(self):
"""Set up the game here. Call this function to restart the game."""
# Setup the Cameras
self.camera = arcade.Camera(self.width, self.height)
self.gui_camera = arcade.Camera(self.width, self.height)
# Map name
map_name = "D:\\Colin Lewis\\pythonProject3\\Lib\\Forest_of_Acid_&_Spikes.tmx"
# Layer Specific Options for the Tilemap
layer_options = {
LAYER_NAME_TERRAIN: {
"use_spatial_hash": True,
},
LAYER_NAME_HAZARDS: {
"use_spatial_hash": True,
},
LAYER_NAME_PLAYER: {
"use_spacial_hash": True
},
}
# Load in TileMap
print("Loading Tile Map")
print(map_name)
self.tile_map = arcade.load_tilemap(map_name, TILE_SCALING, layer_options)
print("Done loading Tile Map")
self.scene = arcade.Scene.from_tilemap(self.tile_map)
self.end_of_map = self.tile_map.width * GRID_PIXEL_SIZE
self.player_sprite = PlayerCharacter()
self.player_sprite.center_x = (
self.tile_map.tile_width * TILE_SCALING * PLAYER_START_X)
self.player_sprite.center_y = (
self.tile_map.tile_height * TILE_SCALING * PLAYER_START_Y
)
self.scene.add_sprite(LAYER_NAME_PLAYER, self.player_sprite)
self.end_of_map = self.tile_map.width * GRID_PIXEL_SIZE
# Create the 'physics engine'
self.physics_engine = arcade.PhysicsEnginePlatformer(
self.player_sprite,
gravity_constant=GRAVITY,
walls=(self.scene[LAYER_NAME_TERRAIN]))
def on_draw(self):
"""Render the screen."""
# Clear the screen to the background color
self.clear()
# Activate the game camera
self.camera.use()
# Draw our Scene
self.scene.draw()
# Activate the GUI camera before drawing GUI elements
self.gui_camera.use()
def process_keychange(self):
# Process left/right
if self.right_pressed and not self.left_pressed:
self.player_sprite.change_x = PLAYER_MOVEMENT_SPEED
elif self.left_pressed and not self.right_pressed:
self.player_sprite.change_x = -PLAYER_MOVEMENT_SPEED
else:
self.player_sprite.change_x = 0
def on_key_press(self, key, modifiers):
if key == arcade.key.LEFT:
self.left_pressed = True
elif key == arcade.key.RIGHT:
self.right_pressed = True
self.process_keychange()
def on_key_release(self, key, modifiers):
if key == arcade.key.LEFT:
self.left_pressed = False
elif key == arcade.key.RIGHT:
self.right_pressed = False
self.process_keychange()
def center_camera_to_player(self, speed=0.2):
screen_center_x = self.player_sprite.center_x - (self.camera.viewport_width / 2)
screen_center_y = self.player_sprite.center_y - (
self.camera.viewport_height / 2
)
if screen_center_x < 0:
screen_center_x = 0
if screen_center_y < 0:
screen_center_y = 0
player_centered = screen_center_x, screen_center_y
self.camera.move_to(player_centered, speed)
# Draw hit boxes.
for wall in self.wall_list:
wall.draw_hit_box(arcade.color.BLACK, 3)
self.player_sprite.draw_hit_box(arcade.color.RED, 3)
def main():
"""Main function"""
window = MyGame()
window.setup()
arcade.run()
if __name__ == "__main__":
main()
This is where I think the error is coming from in the code:
print("Loading Tile Map")
print(map_name)
self.tile_map = arcade.load_tilemap(map_name, TILE_SCALING, layer_options)
print("Done loading Tile Map")
self.scene = arcade.Scene.from_tilemap(self.tile_map)
self.end_of_map = self.tile_map.width * GRID_PIXEL_SIZE
self.player_sprite = PlayerCharacter()
self.player_sprite.center_x = (
self.tile_map.tile_width * TILE_SCALING * PLAYER_START_X)
self.player_sprite.center_y = (
self.tile_map.tile_height * TILE_SCALING * PLAYER_START_Y
)
self.scene.add_sprite(LAYER_NAME_PLAYER, self.player_sprite)
self.end_of_map = self.tile_map.width * GRID_PIXEL_SIZE
# Create the 'physics engine'
self.physics_engine = arcade.PhysicsEnginePlatformer(
self.player_sprite,
gravity_constant=GRAVITY,
walls=(self.scene[LAYER_NAME_TERRAIN]))
def on_draw(self):
"""Render the screen."""
# Clear the screen to the background color
self.clear()
# Activate the game camera
self.camera.use()
# Draw our Scene
self.scene.draw()
# Activate the GUI camera before drawing GUI elements
self.gui_camera.use()
Related
I'm trying write PongGame AI with pygame and stable-baselines. Environment is ready and working. For the agent, im using custom env documentation stable-baselines (https://stable-baselines.readthedocs.io/en/master/guide/custom_env.html)
But when i use check environment.py , error occuring which is
"assertion error: reset() method doesnt matching with observation space"
Game is working properly as i said but when i try make this with customEnv the error occuring which i wrote.
Traceback (most recent call last):
File "C:\Users\Goksel\anaconda3\envs\tensor37\lib\site-packages\spyder_kernels\py3compat.py", line 356, in compat_exec
exec(code, globals, locals)
File "c:\users\goksel\desktop\checkenv.py", line 9, in
check_env(env)
File "C:\Users\Goksel\anaconda3\envs\tensor37\lib\site-packages\stable_baselines\common\env_checker.py", line 214, in check_env
_check_returned_values(env, observation_space, action_space)
File "C:\Users\Goksel\anaconda3\envs\tensor37\lib\site-packages\stable_baselines\common\env_checker.py", line 99, in _check_returned_values
_check_obs(obs, observation_space, 'reset')
File "C:\Users\Goksel\anaconda3\envs\tensor37\lib\site-packages\stable_baselines\common\env_checker.py", line 89, in _check_obs
"method does not match the given observation space".format(method_name))
AssertionError: The observation returned by the reset() method does not match the given observation space
files and codes github link for those who want it:
https://github.com/RsGoksel/PongGame-AI.git
video resources which i used:
https://www.youtube.com/watch?v=uKnjGn8fF70&t=1493s
https://www.youtube.com/watch?v=eBCU-tqLGfQ&t=3551s
https://www.youtube.com/watch?v=bD6V3rcr_54&t=934s
import gym
from gym import spaces
import pygame
import random
import numpy as np
HEIGHT = 450
WIDTH = 600
screen = pygame.display.set_mode((WIDTH,HEIGHT))
white = (255,255,255)
black = (0,0,0)
red = (255,0,0)
blue = (50,0,200)
def updatePaddle(action, paddleY):
if action == 0:
paddleY.rect.y -= 4
if action == 1:
return
if action == 2:
paddleY.rect.y += 4
if paddleY.rect.y < 0:
paddleY.rect.y = 0
if paddleY.rect.y > HEIGHT:
paddleY.rect.y = HEIGHT
return paddleY.rect.y
class PongEnv(gym.Env):
metadata = {'render.modes': ['human']}
class paddle(pygame.sprite.Sprite):
def __init__(self,color):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.Surface([WIDTH/40,HEIGHT/4.5])
self.image.fill(color)
self.rect = self.image.get_rect()
class ball(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.Surface([WIDTH/40,WIDTH/40])
self.image.fill(red)
self.rect = self.image.get_rect()
self.Xspeed = 3
self.Yspeed = 3
def __init__(self):
super(PongEnv, self).__init__()
self.reward = 0
self.done = False
self.score = 0
self.action_space = spaces.Discrete(3)
self.observation_space = spaces.Box(low=0, high=255,
shape=(1,HEIGHT, WIDTH), dtype=np.float32)
self.pedal1 = self.paddle(blue)
self.pedal2 = self.paddle(blue)
self.BALL = self.ball()
self.all_sprites = pygame.sprite.Group()
self.all_sprites.add(self.pedal1, self.pedal2, self.BALL)
#paddle1 and paddle2(bot) location
self.pedal1.rect.x = WIDTH/50 #25
self.pedal1.rect.y = random.randint(0,HEIGHT/10)*10 #300
self.pedal2.rect.x = 23*WIDTH/24 #575
self.pedal2.rect.y = random.randint(0,HEIGHT/10)*10
#ball location. at the beginning of each round, the ball's destination flank changes
self.BALL.rect.x = WIDTH/2
self.BALL.rect.y = HEIGHT/4 + random.randint(0, int(3/4*HEIGHT))
self.BALL.Xspeed = random.sample([-self.BALL.Xspeed,self.BALL.Xspeed],1)[0]
self.BALL.Yspeed = random.sample([-self.BALL.Yspeed,self.BALL.Yspeed],1)[0]
def step(self, action):
self.BALL.rect.x += self.BALL.Xspeed
self.BALL.rect.y += self.BALL.Yspeed
self.pedal2.rect.y = self.BALL.rect.y - (WIDTH/40)
if action==0:
#self.pedal1.rect.y -+= 4
updatePaddle(0, self.pedal1)
if action==2:
updatePaddle(2, self.pedal1)
#if ball hits pedal1, score for paddle because its is exactly what we want
if self.pedal1.rect.colliderect(self.BALL.rect):
self.BALL.Xspeed *= -1
self.score += 5
self.reward = self.score
#collider with paddle2
if self.pedal2.rect.colliderect(self.BALL.rect):
self.BALL.Xspeed *= -1
#control for ball and boundries
if self.BALL.rect.y > HEIGHT - (WIDTH/40) or self.BALL.rect.y < WIDTH/200: #435 or self.top.rect.y < 3
self.BALL.Yspeed *= -1
#its negative score for agent.
if self.BALL.rect.x <= WIDTH/120: #self.pedal1.rect.x yazılabilirdi fakat const değişken ile
self.score -= 10
self.reward = self.score
done = True
self.observation = [self.pedal1.rect.x, self.pedal1.rect.y, self.BALL.rect.x, self.BALL.rect.y]
self.observation = np.array(self.observation)
info = {}
return self.observation, self.reward, self.done, info
def reset(self):
self.done = False
self.score = 0
self.pedal1.rect.x = WIDTH/50 #25
self.pedal1.rect.y = random.randint(0,HEIGHT/10)*10 #300
self.pedal2.rect.x = 23*WIDTH/24 #575
self.pedal2.rect.y = random.randint(0,HEIGHT/10)*10
self.BALL.rect.x = WIDTH/2
self.BALL.rect.y = HEIGHT/4 + random.randint(0, int(3/4*HEIGHT))
self.BALL.Xhiz = random.sample([-self.BALL.Xspeed,self.BALL.Xspeed],1)[0]
self.BALL.Yhiz = random.sample([-self.BALL.Yspeed,self.BALL.Yspeed],1)[0]
self.observation = [self.pedal1.rect.x, self.pedal1.rect.y, self.BALL.rect.x, self.BALL.rect.y]
self.observation = np.array(self.observation)
return self.observation # reward, done, info can't be included
def render(self, mode='human'):
self.screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.init()
pygame.display.init()
while True:
pygame.time.delay(10)
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.display.quit()
pygame.quit()
pygame.display.update()
self.ekran.fill(black)
self.all_sprites.draw(self.screen)
#self.step(0)
def close (self):
if self.screen is not None:
pygame.display.quit()
pygame.quit()
and other checkenv.py file:
from stable_baselines.common.env_checker import check_env
from Stable import PongEnv
env = PongEnv()
check_env(env)
error: AssertionError: The observation returned by the `reset()` method does not match the given observation space
I am developing a simple platformer game using the arcade game library of Python. I am still new to this, but I have tried to use as much object oriented programming as I could. I have successfully setup two "rooms" or levels of the game. However, I cannot figure out how to move to the second room after finishing the first room. Here is my code:
import arcade
import os
import random
SPRITE_SCALING = 0.5
SPRITE_SCALING_COIN = 0.3
SPRITE_NATIVE_SIZE = 128
SPRITE_SIZE = int(SPRITE_NATIVE_SIZE * SPRITE_SCALING)
SCREEN_WIDTH = 800
SCREEN_HEIGHT = 600
SCREEN_TITLE = "Help Nick Adams!"
# Physics
MOVEMENT_SPEED = 5
JUMP_SPEED = 12
GRAVITY = 0.5
class Room:
# Class to hold info about rooms/levels
def __init__(self):
self.wall_list = self.goal_list = self.enemy_list = self.victory_sprite = None
self.collectedCoins = 0
self.numCoins = 0
def setup_room_1():
room = Room()
room.wall_list = arcade.SpriteList(use_spatial_hash=True)
room.enemy_list = arcade.SpriteList()
room.goal_list = arcade.SpriteList(use_spatial_hash=True)
room.victory_sprite = arcade.SpriteList(use_spatial_hash=True)
# Draw platforms and ground
for x in range(0, SCREEN_WIDTH, SPRITE_SIZE):
wall = arcade.Sprite(":resources:images/tiles/grassMid.png", SPRITE_SCALING)
wall.bottom = 0
wall.left = x
room.wall_list.append(wall)
for x in range(SPRITE_SIZE * 3, SPRITE_SIZE * 8, SPRITE_SIZE):
wall = arcade.Sprite(":resources:images/tiles/grassMid.png", SPRITE_SCALING)
wall.bottom = SPRITE_SIZE * 3
wall.left = x
room.wall_list.append(wall)
# Draw the crates
for x in range(0, SCREEN_WIDTH, SPRITE_SIZE * 5):
wall = arcade.Sprite(":resources:images/tiles/boxCrate_double.png", SPRITE_SCALING)
wall.bottom = SPRITE_SIZE
wall.left = x
room.wall_list.append(wall)
# Draw an enemy 1
enemy = arcade.Sprite(":resources:images/enemies/wormGreen.png", SPRITE_SCALING)
enemy.bottom = SPRITE_SIZE
enemy.left = SPRITE_SIZE * 2
enemy.change_x = 2
room.enemy_list.append(enemy)
# -- Draw enemy2 on the platform
enemy = arcade.Sprite(":resources:images/enemies/wormGreen.png", SPRITE_SCALING)
enemy.bottom = SPRITE_SIZE * 4
enemy.left = SPRITE_SIZE * 4
# Set boundaries for enemy
enemy.boundary_right = SPRITE_SIZE * 8
enemy.boundary_left = SPRITE_SIZE * 3
enemy.change_x = 2
room.enemy_list.append(enemy)
# Set up coins
for pos in [[128, 96], [418, 300], [670, 150]]:
goal = arcade.Sprite(":resources:images/items/coinGold.png", SPRITE_SCALING)
goal.center_x = pos[0]
goal.center_y = pos[1]
room.goal_list.append(goal)
room.numCoins += 1
# Set up checkpoint/level clear
flag = arcade.Sprite(":resources:images/tiles/signExit.png", SPRITE_SCALING)
flag.center_x = 770
flag.center_y = 96
room.victory_sprite.append(flag)
# Load the background image for this level.
room.background = arcade.load_texture(":resources:images/backgrounds/abstract_1.jpg")
return room
def setup_room_2():
room = Room()
room.wall_list = arcade.SpriteList(use_spatial_hash=True)
room.enemy_list = arcade.SpriteList()
room.goal_list = arcade.SpriteList(use_spatial_hash=True)
room.victory_sprite = arcade.SpriteList(use_spatial_hash=True)
# Set up walls
for y in range(0, 800, 200):
for x in range(100, 700, 64):
wall = arcade.Sprite(":resources:images/tiles/boxCrate_double.png", SPRITE_SCALING)
wall.center_x = x
wall.center_y = y
room.wall_list.append(wall)
for pos in [[35, 40], [765, 80], [35, 280], [765, 480]]:
wall = arcade.Sprite(":resources:images/tiles/grassHalf.png", SPRITE_SCALING)
wall.center_x = pos[0]
wall.center_y = pos[1]
room.wall_list.append(wall)
# Create the coins
for i in range(50):
# Create the coin instance
# Coin image from kenney.nl
goal = arcade.Sprite(":resources:images/items/coinGold.png", SPRITE_SCALING_COIN)
# Boolean variable if we successfully placed the coin
coin_placed_successfully = False
# Keep trying until success
while not coin_placed_successfully:
# Position the coin
goal.center_x = random.randrange(100, 700)
goal.center_y = random.randrange(SCREEN_HEIGHT)
# See if the coin is hitting a wall
wall_hit_list = arcade.check_for_collision_with_list(goal, room.wall_list)
# See if the coin is hitting another coin
coin_hit_list = arcade.check_for_collision_with_list(goal, room.goal_list)
if len(wall_hit_list) == 0 and len(coin_hit_list) == 0:
coin_placed_successfully = True
# Add the coin to the lists
room.goal_list.append(goal)
room.numCoins += 1
# Draw an enemy1
enemy = arcade.Sprite(":resources:images/enemies/fly.png", SPRITE_SCALING_COIN)
enemy.bottom = SPRITE_SIZE
enemy.left = SPRITE_SIZE * 2
enemy.boundary_right = SPRITE_SIZE * 8 + 60
enemy.boundary_left = SPRITE_SIZE * 1 + 60
enemy.change_x = 3
room.enemy_list.append(enemy)
# Draw a enemy2
enemy = arcade.Sprite(":resources:images/enemies/fly.png", SPRITE_SCALING_COIN)
enemy.bottom = SPRITE_SIZE * 4
enemy.left = SPRITE_SIZE * 4
enemy.boundary_right = SPRITE_SIZE * 8
enemy.boundary_left = SPRITE_SIZE * 3
enemy.change_x = 4
room.enemy_list.append(enemy)
# Draw a enemy3
enemy = arcade.Sprite(":resources:images/enemies/fly.png", SPRITE_SCALING_COIN)
enemy.bottom = SPRITE_SIZE * 7.2
enemy.left = SPRITE_SIZE * 4
enemy.boundary_right = SPRITE_SIZE * 8 + 80
enemy.boundary_left = SPRITE_SIZE * 3
enemy.change_x = 4.8
room.enemy_list.append(enemy)
# Draw victory point
flag = arcade.Sprite(":resources:images/tiles/signExit.png", SPRITE_SCALING)
flag.center_x = 765
flag.center_y = 545
room.victory_sprite.append(flag)
# Load the background image for this level.
room.background = arcade.load_texture(":resources:images/backgrounds/abstract_1.jpg")
return room
class MainGame(arcade.Window):
def __init__(self):
super().__init__(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_TITLE)
file_path = os.path.dirname(os.path.abspath(__file__))
os.chdir(file_path)
# Sprites and set up player
self.player_list = self.rooms = self.player_sprite = self.physics_engine = None
self.current_room = self.view_left = self.view_bottom = self.collectedCoins = 0
self.game_over = False
# Load sounds
self.collect_goal_sound = arcade.load_sound(":resources:sounds/coin1.wav")
self.jump_sound = arcade.load_sound(":resources:sounds/jump1.wav")
def setup(self):
""" Set up the game and initialize the variables. """
# -- Set up the player
self.player_sprite = arcade.Sprite(":resources:images/animated_characters/female_person/femalePerson_idle.png",
SPRITE_SCALING)
# list of rooms
self.rooms = []
# Create the rooms
room = setup_room_1()
self.rooms.append(room)
room = setup_room_2()
self.rooms.append(room)
# Starting room number
self.current_room = 0
# Player start position according to room number
if self.current_room == 0:
self.player_sprite.center_x = 64
self.player_sprite.center_y = 270
elif self.current_room == 1:
self.player_sprite.center_x = 35
self.player_sprite.center_y = 55
self.player_list = arcade.SpriteList()
self.player_list.append(self.player_sprite)
# Create a physics engine
self.physics_engine = arcade.PhysicsEnginePlatformer(self.player_sprite, self.rooms[self.current_room].wall_list
)
# Set the background color
arcade.set_background_color(arcade.color.AMAZON)
def on_draw(self):
arcade.start_render()
self.rooms[self.current_room].wall_list.draw()
self.rooms[self.current_room].goal_list.draw()
self.rooms[self.current_room].enemy_list.draw()
self.rooms[self.current_room].victory_sprite.draw()
# Draw all the sprites.
self.player_list.draw()
def on_key_press(self, key, modifiers):
if key == arcade.key.UP:
if self.physics_engine.can_jump():
self.player_sprite.change_y = JUMP_SPEED
elif key == arcade.key.LEFT:
self.player_sprite.change_x = -MOVEMENT_SPEED
elif key == arcade.key.RIGHT:
self.player_sprite.change_x = MOVEMENT_SPEED
def on_key_release(self, key, modifiers):
if key == arcade.key.LEFT or key == arcade.key.RIGHT:
self.player_sprite.change_x = 0
def on_update(self, delta_time):
if not self.game_over:
# Move the enemies
self.rooms[self.current_room].enemy_list.update()
# Check each enemy
for enemy in self.rooms[self.current_room].enemy_list:
# If the enemy hit a wall, reverse
if len(arcade.check_for_collision_with_list(enemy, self.rooms[self.current_room].wall_list)) > 0:
enemy.change_x *= -1
# If the enemy hit the left boundary, reverse
elif enemy.boundary_left is not None and enemy.left < enemy.boundary_left:
enemy.change_x *= -1
# If the enemy hit the right boundary, reverse
elif enemy.boundary_right is not None and enemy.right > enemy.boundary_right:
enemy.change_x *= -1
# Update the player using the physics engine
self.physics_engine.update()
# See if we hit any coins
goal_hit_list = arcade.check_for_collision_with_list(self.player_sprite,
self.rooms[self.current_room].goal_list)
# Loop through each coin we hit (if any) and remove it
for goal in goal_hit_list:
# Remove the coin
goal.remove_from_sprite_lists()
# Play a sound
arcade.play_sound(self.collect_goal_sound)
# Count number of coins collected
self.collectedCoins += 1
if self.player_sprite.center_x <= -10 or self.player_sprite.center_x >= 800:
self.player_sprite.change_x = 0
self.player_sprite.change_y = 0
self.player_sprite.center_x = 64
self.player_sprite.center_y = 270
# See if the player hit a worm
if len(arcade.check_for_collision_with_list(self.player_sprite,
self.rooms[self.current_room].enemy_list)) > 0:
self.game_over = True
# See if the player hit the flag. If so, progress to round 2 ??????
if arcade.check_for_collision_with_list(self.player_sprite,
self.rooms[
self.current_room].victory_sprite) and self.collectedCoins == \
self.rooms[self.current_room].numCoins:
self.game_over = True
self.current_room += 1
def main():
window = MainGame()
window.setup()
arcade.run()
if __name__ == "__main__":
main()
If I delete self.gameover= True from the def update, the program transitions into room 2 but the sprites aren't loaded properly and player position is not reset.
replace self.game_over = True with self.setup()
Move creation of rooms from setup to __init__
Updated script:
import arcade
import os
import random
SPRITE_SCALING = 0.5
SPRITE_SCALING_COIN = 0.3
SPRITE_NATIVE_SIZE = 128
SPRITE_SIZE = int(SPRITE_NATIVE_SIZE * SPRITE_SCALING)
SCREEN_WIDTH = 800
SCREEN_HEIGHT = 600
SCREEN_TITLE = "Help Nick Adams!"
# Physics
MOVEMENT_SPEED = 5
JUMP_SPEED = 12
GRAVITY = 0.5
class Room:
# Class to hold info about rooms/levels
def __init__(self):
self.wall_list = self.goal_list = self.enemy_list = self.victory_sprite = None
self.collectedCoins = 0
self.numCoins = 0
def setup_room_1():
room = Room()
room.wall_list = arcade.SpriteList(use_spatial_hash=True)
room.enemy_list = arcade.SpriteList()
room.goal_list = arcade.SpriteList(use_spatial_hash=True)
room.victory_sprite = arcade.SpriteList(use_spatial_hash=True)
# Draw platforms and ground
for x in range(0, SCREEN_WIDTH, SPRITE_SIZE):
wall = arcade.Sprite(":resources:images/tiles/grassMid.png", SPRITE_SCALING)
wall.bottom = 0
wall.left = x
room.wall_list.append(wall)
for x in range(SPRITE_SIZE * 3, SPRITE_SIZE * 8, SPRITE_SIZE):
wall = arcade.Sprite(":resources:images/tiles/grassMid.png", SPRITE_SCALING)
wall.bottom = SPRITE_SIZE * 3
wall.left = x
room.wall_list.append(wall)
# Draw the crates
for x in range(0, SCREEN_WIDTH, SPRITE_SIZE * 5):
wall = arcade.Sprite(":resources:images/tiles/boxCrate_double.png", SPRITE_SCALING)
wall.bottom = SPRITE_SIZE
wall.left = x
room.wall_list.append(wall)
# Draw an enemy 1
enemy = arcade.Sprite(":resources:images/enemies/wormGreen.png", SPRITE_SCALING)
enemy.bottom = SPRITE_SIZE
enemy.left = SPRITE_SIZE * 2
enemy.change_x = 2
room.enemy_list.append(enemy)
# -- Draw enemy2 on the platform
enemy = arcade.Sprite(":resources:images/enemies/wormGreen.png", SPRITE_SCALING)
enemy.bottom = SPRITE_SIZE * 4
enemy.left = SPRITE_SIZE * 4
# Set boundaries for enemy
enemy.boundary_right = SPRITE_SIZE * 8
enemy.boundary_left = SPRITE_SIZE * 3
enemy.change_x = 2
room.enemy_list.append(enemy)
# Set up coins
for pos in [[128, 96], [418, 300], [670, 150]]:
goal = arcade.Sprite(":resources:images/items/coinGold.png", SPRITE_SCALING)
goal.center_x = pos[0]
goal.center_y = pos[1]
room.goal_list.append(goal)
room.numCoins += 1
# Set up checkpoint/level clear
flag = arcade.Sprite(":resources:images/tiles/signExit.png", SPRITE_SCALING)
flag.center_x = 770
flag.center_y = 96
room.victory_sprite.append(flag)
# Load the background image for this level.
room.background = arcade.load_texture(":resources:images/backgrounds/abstract_1.jpg")
return room
def setup_room_2():
room = Room()
room.wall_list = arcade.SpriteList(use_spatial_hash=True)
room.enemy_list = arcade.SpriteList()
room.goal_list = arcade.SpriteList(use_spatial_hash=True)
room.victory_sprite = arcade.SpriteList(use_spatial_hash=True)
# Set up walls
for y in range(0, 800, 200):
for x in range(100, 700, 64):
wall = arcade.Sprite(":resources:images/tiles/boxCrate_double.png", SPRITE_SCALING)
wall.center_x = x
wall.center_y = y
room.wall_list.append(wall)
for pos in [[35, 40], [765, 80], [35, 280], [765, 480]]:
wall = arcade.Sprite(":resources:images/tiles/grassHalf.png", SPRITE_SCALING)
wall.center_x = pos[0]
wall.center_y = pos[1]
room.wall_list.append(wall)
# Create the coins
for i in range(50):
# Create the coin instance
# Coin image from kenney.nl
goal = arcade.Sprite(":resources:images/items/coinGold.png", SPRITE_SCALING_COIN)
# Boolean variable if we successfully placed the coin
coin_placed_successfully = False
# Keep trying until success
while not coin_placed_successfully:
# Position the coin
goal.center_x = random.randrange(100, 700)
goal.center_y = random.randrange(SCREEN_HEIGHT)
# See if the coin is hitting a wall
wall_hit_list = arcade.check_for_collision_with_list(goal, room.wall_list)
# See if the coin is hitting another coin
coin_hit_list = arcade.check_for_collision_with_list(goal, room.goal_list)
if len(wall_hit_list) == 0 and len(coin_hit_list) == 0:
coin_placed_successfully = True
# Add the coin to the lists
room.goal_list.append(goal)
room.numCoins += 1
# Draw an enemy1
enemy = arcade.Sprite(":resources:images/enemies/fly.png", SPRITE_SCALING_COIN)
enemy.bottom = SPRITE_SIZE
enemy.left = SPRITE_SIZE * 2
enemy.boundary_right = SPRITE_SIZE * 8 + 60
enemy.boundary_left = SPRITE_SIZE * 1 + 60
enemy.change_x = 3
room.enemy_list.append(enemy)
# Draw a enemy2
enemy = arcade.Sprite(":resources:images/enemies/fly.png", SPRITE_SCALING_COIN)
enemy.bottom = SPRITE_SIZE * 4
enemy.left = SPRITE_SIZE * 4
enemy.boundary_right = SPRITE_SIZE * 8
enemy.boundary_left = SPRITE_SIZE * 3
enemy.change_x = 4
room.enemy_list.append(enemy)
# Draw a enemy3
enemy = arcade.Sprite(":resources:images/enemies/fly.png", SPRITE_SCALING_COIN)
enemy.bottom = SPRITE_SIZE * 7.2
enemy.left = SPRITE_SIZE * 4
enemy.boundary_right = SPRITE_SIZE * 8 + 80
enemy.boundary_left = SPRITE_SIZE * 3
enemy.change_x = 4.8
room.enemy_list.append(enemy)
# Draw victory point
flag = arcade.Sprite(":resources:images/tiles/signExit.png", SPRITE_SCALING)
flag.center_x = 765
flag.center_y = 545
room.victory_sprite.append(flag)
# Load the background image for this level.
room.background = arcade.load_texture(":resources:images/backgrounds/abstract_1.jpg")
return room
class MainGame(arcade.Window):
def __init__(self):
super().__init__(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_TITLE)
file_path = os.path.dirname(os.path.abspath(__file__))
os.chdir(file_path)
# Sprites and set up player
self.player_list = self.rooms = self.player_sprite = self.physics_engine = None
self.current_room = self.view_left = self.view_bottom = self.collectedCoins = 0
self.game_over = False
# Load sounds
self.collect_goal_sound = arcade.load_sound(":resources:sounds/coin1.wav")
self.jump_sound = arcade.load_sound(":resources:sounds/jump1.wav")
# Starting room number
self.current_room = 0
# list of rooms
self.rooms = []
# Create the rooms
room = setup_room_1()
self.rooms.append(room)
room = setup_room_2()
self.rooms.append(room)
def setup(self):
""" Set up the game and initialize the variables. """
# -- Set up the player
self.player_sprite = arcade.Sprite(":resources:images/animated_characters/female_person/femalePerson_idle.png", SPRITE_SCALING)
# Player start position according to room number
if self.current_room == 0:
self.player_sprite.center_x = 64
self.player_sprite.center_y = 270
elif self.current_room == 1:
self.player_sprite.center_x = 35
self.player_sprite.center_y = 55
self.player_list = arcade.SpriteList()
self.player_list.append(self.player_sprite)
# Create a physics engine
self.physics_engine = arcade.PhysicsEnginePlatformer(self.player_sprite, self.rooms[self.current_room].wall_list)
# Set the background color
arcade.set_background_color(arcade.color.AMAZON)
def on_draw(self):
arcade.start_render()
self.rooms[self.current_room].wall_list.draw()
self.rooms[self.current_room].goal_list.draw()
self.rooms[self.current_room].enemy_list.draw()
self.rooms[self.current_room].victory_sprite.draw()
# Draw all the sprites.
self.player_list.draw()
def on_key_press(self, key, modifiers):
if key == arcade.key.UP:
if self.physics_engine.can_jump():
self.player_sprite.change_y = JUMP_SPEED
elif key == arcade.key.LEFT:
self.player_sprite.change_x = -MOVEMENT_SPEED
elif key == arcade.key.RIGHT:
self.player_sprite.change_x = MOVEMENT_SPEED
def on_key_release(self, key, modifiers):
if key == arcade.key.LEFT or key == arcade.key.RIGHT:
self.player_sprite.change_x = 0
def on_update(self, delta_time):
if not self.game_over:
# Move the enemies
self.rooms[self.current_room].enemy_list.update()
# Check each enemy
for enemy in self.rooms[self.current_room].enemy_list:
# If the enemy hit a wall, reverse
if len(arcade.check_for_collision_with_list(enemy, self.rooms[self.current_room].wall_list)) > 0:
enemy.change_x *= -1
# If the enemy hit the left boundary, reverse
elif enemy.boundary_left is not None and enemy.left < enemy.boundary_left:
enemy.change_x *= -1
# If the enemy hit the right boundary, reverse
elif enemy.boundary_right is not None and enemy.right > enemy.boundary_right:
enemy.change_x *= -1
# Update the player using the physics engine
self.physics_engine.update()
# See if we hit any coins
goal_hit_list = arcade.check_for_collision_with_list(self.player_sprite, self.rooms[self.current_room].goal_list)
# Loop through each coin we hit (if any) and remove it
for goal in goal_hit_list:
# Remove the coin
goal.remove_from_sprite_lists()
# Play a sound
arcade.play_sound(self.collect_goal_sound)
# Count number of coins collected
self.collectedCoins += 1
if self.player_sprite.center_x <= -10 or self.player_sprite.center_x >= 800:
self.player_sprite.change_x = 0
self.player_sprite.change_y = 0
self.player_sprite.center_x = 64
self.player_sprite.center_y = 270
# See if the player hit a worm
if len(arcade.check_for_collision_with_list(self.player_sprite, self.rooms[self.current_room].enemy_list)) > 0:
self.game_over = True
# See if the player hit the flag. If so, progress to round 2 ??????
if arcade.check_for_collision_with_list(self.player_sprite, self.rooms[self.current_room].victory_sprite) and self.collectedCoins == self.rooms[self.current_room].numCoins:
# self.game_over = True
self.current_room += 1
self.setup()
def main():
window = MainGame()
window.setup()
arcade.run()
if __name__ == "__main__":
main()
I am having problems with the below code. Can someone please help and explain why the game over/reset and score functions are not working?
Below is the code im working from. My problem is that i can not see why the game over/reset function does not work. When the ship crashes into an astroid the game abruptly ends, but when it crashes into the barrier it does not indicate game over. Also, it's not reflecting the score.
Sorry if i wasn't clear before.
Here starts the code:
import kivy
kivy.require('1.8.0')
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.uix.label import Label
from kivy.uix.button import Button
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.image import Image
from kivy.properties import NumericProperty, ObjectProperty
from kivy.clock import Clock
from kivy.core.window import Window
from kivy.graphics import Rectangle, Color, Canvas
from kivy.config import Config
from functools import partial
from random import *
Config.set('graphics', 'resizable', 0)
Window.clearcolor = (0, 0, 0, 1.)
class MyButton(Button):
#class used to get uniform button styles
def __init__(self, **kwargs):
super(MyButton, self).__init__(**kwargs)
self.font_size = Window.width*0.018
class SmartMenu(Widget):
#the instance created by this class will appear
#when the game is started for the first time
buttonList = []
def __init__(self, **kwargs):
#create custom events first
self.register_event_type('on_button_release')
super(SmartMenu, self).__init__(**kwargs)
self.layout = BoxLayout(orientation = 'vertical')
self.layout.width = Window.width/2
self.layout.height = Window.height/2
self.layout.x = Window.width/2 - self.layout.width/2
self.layout.y = Window.height/2 - self.layout.height/2
self.add_widget(self.layout)
def on_button_release(self, *args):
#print 'The on_button_release event was just dispatched', args
#don't need to do anything here. needed for dispatch
pass
def callback(self,instance):
#print('The button %s is being pressed' % instance.text)
self.buttonText = instance.text
self.dispatch('on_button_release') #dispatching the callback event 'on_button_release' to tell teh parent instance to read the button text
def addButtons(self):
for k in self.buttonList:
tmpBtn = MyButton(text = k)
tmpBtn.background_color = [.4, .4, .4, .4]
tmpBtn.bind(on_release = self.callback) #when the button is released the callback function is called
self.layout.add_widget(tmpBtn)
def buildUp(self):
#self.colorWindow()
self.addButtons()
class SmartStartMenu(SmartMenu):
#setup the menu button names
buttonList = ['start', 'about']
def __init__(self, **kwargs):
super(SmartStartMenu, self).__init__(**kwargs)
self.layout = BoxLayout(orientation = 'vertical')
self.layout.width = Window.width/2
self.layout.height = Window.height/2
self.layout.x = Window.width/2 - self.layout.width/2
self.layout.y = Window.height/2 - self.layout.height/2
self.add_widget(self.layout)
self.msg = Label(text = 'Flappy Ship')
self.msg.font_size = Window.width*0.07
self.msg.pos = (Window.width*0.45,Window.height*0.75)
self.add_widget(self.msg)
self.img = Image(source = 'lens2.png')
self.img.size = (Window.width*1.5,Window.height*1.5)
self.img.pos = (-Window.width*0.2,-Window.height*0.2)
self.img.opacity = 0.35
self.add_widget(self.img)
class WidgetDrawer(Widget):
#This widget is used to draw all of the objects on the screen
#it handles the following:
# widget movement, size, positioning
def __init__(self, imageStr, **kwargs):
super(WidgetDrawer, self).__init__(**kwargs)
with self.canvas:
self.size = (Window.width*.002*25,Window.width*.002*25)
self.rect_bg=Rectangle(source=imageStr, pos=self.pos, size=self.size)
self.bind(pos=self.update_graphics_pos)
self.x = self.center_x
self.y = self.center_y
self.pos = (self.x, self.y)
self.rect_bg.pos = self.pos
def update_graphics_pos(self, instance, value):
self.rect_bg.pos = value
def setSize(self, width, height):
self.size = (width, height)
def setPos(self, xpos, ypos):
self.x = xpos
self.y = ypos
class ScoreWidget(Widget):
def __init__(self, **kwargs):
super(ScoreWidget, self).__init__(**kwargs)
self.asteroidScore = 0
self.currentScore = 0
with self.canvas:
tmpPos = (Window.width*0.25, Window.height*0.25)
tmpSize = (Window.width*0.5, Window.height*0.5)
Color(0.1, .1, .1)
self.scoreRect = Rectangle(pos=tmpPos, size=tmpSize)
def prepare(self):
#calculate the score
try:
self.finalScore = self.asteroidScore*100
except:
print 'problems getting score'
self.animateScore()
def animateScore(self):
#display score at 0 and every time interval add 100 until
#we reach the final score
#draw a score widget and schedule updates
scoreText = 'Score: 0'# + str(self.finalScore)
self.scoreLabel = Label(text=scoreText,font_size = '20sp')
self.scoreLabel.x = Window.width*0.3
self.scoreLabel.y = Window.height*0.3
self.add_widget(self.scoreLabel)
Clock.schedule_once(self.updateScore, .1)
self.drawStars()
def updateScore(self,dt):
self.currentScore = self.currentScore +100
self.scoreLabel.text = 'Score: ' + str(self.currentScore)
if self.currentScore < self.finalScore:
Clock.schedule_once(self.updateScore, 0.1)
def drawStars(self):
#0-10 asteroids 0 stars
#11-50 asteroids 1 star
#51-200 asteroids 2 stars
#201-500 asteroids 3 stars
#501-1000 asteroids 4 stars
#1001+ asteroids 5 stars
starNumber = 0
if self.asteroidScore > 10:
starNumber = 1
if self.asteroidScore > 50:
starNumber = 2
if self.asteroidScore > 200:
starNumber = 3
if self.asteroidScore > 500:
starNumber = 4
if self.asteroidScore > 1000:
starNumber = 5
with self.canvas:
#draw stars
#rect one
starPos = Window.width*0.27, Window.height*0.42
starSize = Window.width*0.06,Window.width*0.06
starString = 'gold_star.png'
if starNumber < 1:
starString = 'gray_star.png'
starRectOne = Rectangle(source=starString,pos=starPos, size = starSize)
#rect two
starPos = Window.width*0.37, Window.height*0.42
if starNumber < 2:
starString = 'gray_star.png'
starRectTwo = Rectangle(source=starString,pos=starPos, size = starSize)
#rect three
starPos = Window.width*0.47, Window.height*0.42
if starNumber < 3:
starString = 'gray_star.png'
starRectThree = Rectangle(source=starString,pos=starPos, size = starSize)
#rect four
starPos = Window.width*0.57, Window.height*0.42
if starNumber < 4:
starString = 'gray_star.png'
starRectFour = Rectangle(source=starString,pos=starPos, size = starSize)
#rect five
starPos = Window.width*0.67, Window.height*0.42
if starNumber < 5:
starString = 'gray_star.png'
starRectFive = Rectangle(source=starString,pos=starPos, size = starSize)
class Asteroid(WidgetDrawer):
#Asteroid class. The flappy ship will dodge these
imageStr = './sandstone_1.png'
rect_bg = Rectangle(source=imageStr)
velocity_x = NumericProperty(0)
velocity_y = NumericProperty(0)
def move(self):
self.x = self.x + self.velocity_x*5
self.y = self.y + self.velocity_y
def update(self):
self.move()
class Ship(WidgetDrawer):
#Ship class. This is for the main ship object.
#velocity of ship on x/y axis
#setup constants, health, etc
#choose default image:
impulse = 3
grav = -0.1
velocity_x = NumericProperty(0)
velocity_y = NumericProperty(0)
flameSize = (Window.width*.03, Window.width*.03)
def move(self):
self.x += self.velocity_x
self.y += self.velocity_y
#don't let the ship go too far
if self.y < Window.height*0.05:
#give upwards impulse
Clock.unschedule(self.update)
self.explode()
if self.y > Window.height*0.95:
Clock.unschedule(self.update)
self.explode()
def checkBulletNPCCollision(self, j):
if self.k.collide_widget(j):
j.health = j.health - self.k.bulletDamage
j.attackFlag = 'True'
#age the bullet
self.k.age = self.k.lifespan+10
def checkBulletStageCollision(self,q):
if self.k.collide_widget(q):
#if object type is asteorid
try:
if q.type == 'asteroid':
q.health = q.health - self.k.bulletDamage
self.k.age = self.k.lifespan+10
except:
print 'couldnt hit asteroid'
def determineVelocity(self):
#move the ship up and down
#we need to take into account our acceleration
#also want to look at gravity
self.grav = self.grav*1.05 #increase gravity
#set a grav limit
if self.grav < -4:
self.grav = -4
self.velocity_y = self.impulse + self.grav
self.impulse = 0.95*self.impulse
def drawArrow(self, *largs):
#draw the arrows directly onto the canvas
with self.canvas:
flamePos = (self.pos[0]-Window.width*.02, self.pos[1]+Window.width*.01)
flameRect = Rectangle(source='./flame.png', pos=flamePos, size=self.flameSize)
#schedule removal
def removeArrows(arrow, *largs):
self.canvas.remove(arrow)
Clock.schedule_once(partial(removeArrows, flameRect), .5)
Clock.schedule_once(partial(self.updateArrows, flameRect), 0.1)
def updateArrows(self, arrow, dt):
with self.canvas:
arrow.pos = (arrow.pos[0]-10, arrow.pos[1])
Clock.schedule_once(partial(self.updateArrows, arrow), 0.1)
return
def explode(self):
tmpSize = Window.width*0.25,Window.width*0.2
tmpPos = (self.x-Window.width*0.095, self.y-Window.width*0.08)
with self.canvas:
self.explosionRect = Rectangle(source ='./explosion1.png',pos=tmpPos,size=tmpSize)
def changeExplosion(rect, newSource, *largs):
rect.source = newSource
Clock.schedule_once(partial(changeExplosion, self.explosionRect, './explosion2.png'), 0.2)
Clock.schedule_once(partial(changeExplosion, self.explosionRect, './explosion3.png'), 0.4)
Clock.schedule_once(partial(changeExplosion, self.explosionRect, './explosion4.png'), 0.6)
Clock.schedule_once(partial(changeExplosion, self.explosionRect, './explosion5.png'), 0.8)
def removeExplosion(rect, *largs):
self.canvas.remove(rect)
Clock.schedule_once(partial(removeExplosion, self.explosionRect), 1)
def update(self):
self.determineVelocity()
self.move()
class GUI(Widget):
#this is the main widget that contains the game. This is the primary object
#that runs
asteroidList =[]
#important to use numericproperty here so we can bind a callback
#to use every time the number changes
asteroidScore = NumericProperty(0)
minProb = 1780
def __init__(self, **kwargs):
super(GUI, self).__init__(**kwargs)
#setup label for the score
self.score = Label(text = '0')
self.score.y = Window.height*0.8
self.score.x = Window.width*0.2
def check_score(self, obj):
#update credits
self.score.text = str(self.asteroidScore)
self.bind(asteroidScore = check_score)
self.add_widget(self.score)
#now we create a ship object
self.ship = Ship(imageStr = './ship.png')
self.ship.x = Window.width/4
self.ship.y = Window.height/2
self.add_widget(self.ship)
#self.ship.drawArrow()#start the flames
Clock.schedule_interval((self.ship.drawArrow), 0.1)
def addAsteroid(self):
#add an asteroid to the screen
#self.asteroid
imageNumber = randint(1, 4)
imageStr = './sandstone_'+str(imageNumber)+'.png'
tmpAsteroid = Asteroid(imageStr)
tmpAsteroid.x = Window.width*0.99
#randomize y position
ypos = randint(1, 16)
ypos = ypos*Window.height*.0625
tmpAsteroid.y = ypos
tmpAsteroid.velocity_y = 0
vel = 550#randint(10,25)
tmpAsteroid.velocity_x = -0.1*vel
self.asteroidList.append(tmpAsteroid)
self.add_widget(tmpAsteroid)
def drawTouchResponse(self,x,y):
#draw the arrows directly onto the canvas
with self.canvas:
tmpSize = Window.width*0.07, Window.width*0.07
tmpPos = (x-self.width/4,y-self.height/4)
self.arrowRect = Rectangle(source='./flame1.png',pos=tmpPos, size = tmpSize)
#schedule removal
def removeArrows(arrow, *largs):
self.canvas.remove(arrow)
def changeExplosion(rect, newSource, *largs):
rect.source = newSource
#schedule explosion two
Clock.schedule_once(partial(changeExplosion, self.arrowRect, './flame2.png'), 0.15)
#schedule explosion three
Clock.schedule_once(partial(changeExplosion, self.arrowRect, './flame3.png'), 0.3)
#schedule explosoin four
Clock.schedule_once(partial(changeExplosion, self.arrowRect, './flame4.png'), 0.45)
Clock.schedule_once(partial(removeArrows, self.arrowRect), 0.6)
#handle input events
def on_touch_down(self, touch):
self.ship.impulse = 3
self.ship.grav = -0.1
self.drawTouchResponse(touch.x, touch.y)
def showScore(self):
#this function will draw the score keeping widget, tabulate the score
#and rank with stars
self.scoreWidget = ScoreWidget()
self.scoreWidget.asteroidScore = self.asteroidScore #pass on score
self.scoreWidget.prepare()
self.add_widget(self.scoreWidget)
def removeScore(self):
self.remove_widget(self.scoreWidget)
def gameOver(self):
#add a restart button
restartButton = MyButton(text='Try Again')
#restartButton.background_color = (.5,.5,1,.2)
def restart_button(obj):
#reset game
self.removeScore()
for k in self.asteroidList:
self.remove_widget(k)
self.ship.xpos = Window.width*0.25
self.ship.ypos = Window.height*0.5
self.minProb = 1780
self.asteroidScore = 0
self.asteroidList = []
self.parent.remove_widget(restartButton)
Clock.unschedule(self.update)
Clock.schedule_interval(self.update, 1.0/60.0)
restartButton.size = (Window.width*.3,Window.width*.1)
restartButton.pos = Window.width*0.5-restartButton.width/2, Window.height*0.53
restartButton.bind(on_release=restart_button)
#we will want to bind the parent to listen for things from certain bubbles
#*** It's important that the parent get the button so you can click on it
#otherwise you can't click through the main game's canvas
self.parent.add_widget(restartButton)
#now draw the score widget
self.showScore()
def update(self, dt):
#This update function is the main update function for the game
#All of the game logic has its origin here
#events are setup here as well
#update game objects
#update ship
self.ship.update()
#update asteroids
#randomly add an asteroid
tmpCount = randint(1, 1800)
if tmpCount > self.minProb:
self.addAsteroid()
if self.minProb < 1300:
self.minProb = 1300
self.minProb -= 1
for k in self.asteroidList:
#check for collision with ship
if k.collide_widget(self.ship):
#game over routine
self.gameOver()
Clock.unschedule(self.update)
#add reset button
self.ship.explode()
k.update()
#check to see if asteroid is off of screen
if k.x < -100:
#since it's off the screen, remove the asteroid
self.remove_widget(k)
self.asteroidScore += 1
#remove asteroids off screen
tmpAsteroidList = self.asteroidList
tmpAsteroidList[:] = [x for x in tmpAsteroidList if (x.x > - 100)]
self.asteroidList = tmpAsteroidList
class ClientApp(App):
def build(self):
#this is where the root widget goes
#should be a canvas
self.parent = Widget() #
self.app = GUI()
#Start the game clock (runs update function once every (1/60) seconds
#Clock.schedule_interval(app.update, 1.0/60.0)
#add the start menu
self.sm = SmartStartMenu()
self.sm.buildUp()
def check_button(obj):
#check to see which button was pressed
if self.sm.buttonText == 'start':
#remove menu
self.parent.remove_widget(self.sm)
#start the game
print ' we should start the game now'
Clock.unschedule(self.app.update)
Clock.schedule_interval(self.app.update, 1.0/60.0)
try:
self.parent.remove_widget(self.aboutText)
except:
pass
if self.sm.buttonText == 'about':
self.aboutText = Label(text = 'Flappy Ship is made by Molecular Flow Games \n Check out: https://kivyspacegame.wordpress.com')
self.aboutText.pos = (Window.width*0.45,Window.height*0.35)
self.parent.add_widget(self.aboutText)
#bind a callback function that repsonds to event 'on_button_release' by calling function check_button
self.sm.bind(on_button_release = check_button)
#setup listeners for smartstartmenu
self.parent.add_widget(self.sm)
self.parent.add_widget(self.app) #use this hierarchy to make it easy to deal w/buttons
return self.parent
if __name__ == '__main__':
ClientApp().run()
I'm using a tutorial from arcade.academy and the game runs fine so far (a guy walking around collecting coins and scoring points) but I want to have an attack animation occur when the user presses Q so I can turn some of the coins into enemies and make a little RPG and increase my knowledge.
This is what I've got so far but for some reason the self.is_attacking boolean either doesn't trigger or isn't linked up properly.
Here's what I've got so far.
import arcade
import random
import os
SCREEN_WIDTH = 800
SCREEN_HEIGHT = 600
SCREEN_TITLE = "Move with a Sprite Animation Example"
COIN_SCALE = 0.5
COIN_COUNT = 50
CHARACTER_SCALING = 1
MOVEMENT_SPEED = 5
UPDATES_PER_FRAME = 7
# Constants used to track if the player is facing left or right
RIGHT_FACING = 0
LEFT_FACING = 1
def load_texture_pair(filename):
"""
Load a texture pair, with the second being a mirror image.
"""
return [
arcade.load_texture(filename, scale=CHARACTER_SCALING),
arcade.load_texture(filename, scale=CHARACTER_SCALING, mirrored=True)
]
class PlayerCharacter(arcade.Sprite):
def __init__(self):
# Set up parent class
super().__init__()
# Default to face-right
self.character_face_direction = RIGHT_FACING
# Used for flipping between image sequences
self.cur_texture = 0
self.attack_texture = 0
# Track our state
self.jumping = False
self.climbing = False
self.is_on_ladder = False
self.is_attacking = False
# Adjust the collision box. Default includes too much empty space
# side-to-side. Box is centered at sprite center, (0, 0)
self.points = [[-22, -64], [22, -64], [22, 28], [-22, 28]]
# --- Load Textures ---
# Images from Kenney.nl's Asset Pack 3
main_path = "images/Sprites/rogue like character/rogue like"
# main_path = "platform_tutorial/images/Female person/PNG/Poses/character_femalePerson"
# main_path = "platform_tutorial/images/Male person/PNG/Poses/character_malePerson"
# main_path = "platform_tutorial/images/Male adventurer/PNG/Poses/character_maleAdventurer"
# main_path = "platform_tutorial/images/Zombie/PNG/Poses/character_zombie"
# main_path = "platform_tutorial/images/Robot/PNG/Poses/character_robot"
# Load textures for idle standing
self.idle_texture_pair = load_texture_pair(f"{main_path} idle_Animation 1_0.png")
# Load textures for walking
self.walk_textures = []
for i in range(6):
texture = load_texture_pair(f"{main_path} run_Animation 1_{i}.png")
self.walk_textures.append(texture)
# Load textures for attacking
self.attack_textures = []
for i in range(10):
texture = load_texture_pair(f"{main_path} attack_Animation 1_{i}.png")
self.attack_textures.append(texture)
def update_animation(self, delta_time: float = 1/60):
# Figure out if we need to flip face left or right
if self.change_x < 0 and self.character_face_direction == RIGHT_FACING:
self.character_face_direction = LEFT_FACING
elif self.change_x > 0 and self.character_face_direction == LEFT_FACING:
self.character_face_direction = RIGHT_FACING
# Idle animation
if self.change_x == 0 and self.change_y == 0:
self.texture = self.idle_texture_pair[self.character_face_direction]
return
# Walking animation
self.cur_texture += 1
if self.cur_texture > 5 * UPDATES_PER_FRAME:
self.cur_texture = 0
self.texture = self.walk_textures[self.cur_texture // UPDATES_PER_FRAME][self.character_face_direction]
# Attacking animation
if self.is_attacking:
self.cur_texture += 1
if self.cur_texture > 9 * UPDATES_PER_FRAME:
self.cur_texture = 0
self.is_attacking = False
self.texture = self.attack_textures[self.cur_texture // UPDATES_PER_FRAME][self.character_face_direction]
class MyGame(arcade.Window):
# Main application class.
def __init__(self, width, height, title):
# Initializer
super().__init__(width, height, title)
# Set the working directory (where we expect to find files) to the same
# directory this .py file is in. You can leave this out of your own
# code, but it is needed to easily run the examples using "python -m"
# as mentioned at the top of this program.
file_path = os.path.dirname(os.path.abspath(__file__))
os.chdir(file_path)
# Set up the game and initialize the variables.
# Sprite lists
self.player_list = None
self.coin_list = None
# Set up the player
self.score = 0
self.player = None
self.is_attacking = False
def setup(self):
self.player_list = arcade.SpriteList()
self.coin_list = arcade.SpriteList()
# Set up the player
self.score = 0
self.player = PlayerCharacter()
self.player.center_x = SCREEN_WIDTH // 2
self.player.center_y = SCREEN_HEIGHT // 2
self.player.scale = 0.8
self.player_list.append(self.player)
for i in range(COIN_COUNT):
coin = arcade.AnimatedTimeSprite(scale=0.5)
coin.center_x = random.randrange(SCREEN_WIDTH)
coin.center_y = random.randrange(SCREEN_HEIGHT)
coin.textures = []
coin.textures.append(arcade.load_texture("images/items/Coingold.png", scale=COIN_SCALE))
coin.textures.append(arcade.load_texture("images/items/Coingold.png", scale=COIN_SCALE))
coin.textures.append(arcade.load_texture("images/items/Coingold.png", scale=COIN_SCALE))
coin.textures.append(arcade.load_texture("images/items/Coingold.png", scale=COIN_SCALE))
coin.textures.append(arcade.load_texture("images/items/Coingold.png", scale=COIN_SCALE))
coin.textures.append(arcade.load_texture("images/items/Coingold.png", scale=COIN_SCALE))
coin.cur_texture_index = random.randrange(len(coin.textures))
self.coin_list.append(coin)
# Set the background color
arcade.set_background_color(arcade.color.AMAZON)
def on_draw(self):
# Render the screen.
# This command has to happen before we start drawing
arcade.start_render()
# Draw all the sprites.
self.coin_list.draw()
self.player_list.draw()
# Put the text on the screen.
output = f"Score: {self.score}"
arcade.draw_text(output, 10, 20, arcade.color.WHITE, 14)
def on_key_press(self, key, modifiers):
# Called whenever a key is pressed.
if key == arcade.key.UP:
self.player.change_y = MOVEMENT_SPEED
elif key == arcade.key.DOWN:
self.player.change_y = -MOVEMENT_SPEED
elif key == arcade.key.LEFT:
self.player.change_x = -MOVEMENT_SPEED
elif key == arcade.key.RIGHT:
self.player.change_x = MOVEMENT_SPEED
elif key == arcade.key.Q:
self.is_attacking = True
def on_key_release(self, key, modifiers):
# Called when the user releases a key.
if key == arcade.key.UP or key == arcade.key.DOWN:
self.player.change_y = 0
elif key == arcade.key.LEFT or key == arcade.key.RIGHT:
self.player.change_x = 0
elif key == arcade.key.Q:
self.is_attacking = False
def on_update(self, delta_time):
# Movement and game logic
self.coin_list.update()
self.coin_list.update_animation()
self.player_list.update()
self.player_list.update_animation()
# Generate a list of all sprites that collided with the player.
hit_list = arcade.check_for_collision_with_list(self.player, self.coin_list)
# Loop through each colliding sprite, remove it, and add to the score.
for coin in hit_list:
coin.remove_from_sprite_lists()
self.score += 1
def main():
# Main method
window = MyGame(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_TITLE)
window.setup()
arcade.run()
if __name__ == "__main__":
main()
You can try setting
self.player.is_attacking=True
I am making a memory game and I can't get the program to check if the tiles match and if they do match get the tiles to stay exposed, and keep the tiles exposed for one second if the tiles don't match. lines 116-122 I think that part of the program is supposed to check but it never returns true for is_matching(). I feel like I am supposed to check if the actual tiles themselves are equal to each other but to me, that seems counterproductive because the tile is just a location on the grid and the image is what's drawn on the tile??
thanks in advance
# Code Example 2
#
import pygame
import random
import time
# User-defined functions
def main():
# initialize all pygame modules (some need initialization)
pygame.init()
# create a pygame display window
pygame.display.set_mode((500, 400))
# set the title of the display window
pygame.display.set_caption('Tic Tac Toe')
# get the display surface
w_surface = pygame.display.get_surface()
# create a game object
game = Game(w_surface)
# start the main game loop by calling the play method on the game object
game.play()
# quit pygame and clean up the pygame window
pygame.quit()
# User-defined classes
class Game:
# An object in this class represents a complete game.
def __init__(self, surface):
# Initialize a Game.
# - self is the Game to initialize
# - surface is the display window surface object
# === objects that are part of every game that we will discuss
self.surface = surface
self.bg_color = pygame.Color('black')
self.FPS = 60
self.game_Clock = pygame.time.Clock()
self.close_clicked = False
self.continue_game = True
# === game specific objects
self.board = []
self.score = [0]
self.board_size = 4
self.create_board()
self.click = 0
self.exposed = 0
self.first_image= None
self.second_image= None
self.tile1 = None
self.tile2 = None
self.match = None
def create_board(self):
Tile.set_surface(self.surface)
# width = self.surface.get_width()//self.board_size
# height = self.surface.get_height() // self.board_size
# image is of type surface
self.images = []
new_image =['image1.bmp','image2.bmp','image3.bmp','image4.bmp', 'image5.bmp','image6.bmp','image7.bmp',
'image8.bmp','image1.bmp','image2.bmp','image3.bmp','image4.bmp', 'image5.bmp','image6.bmp',
'image7.bmp','image8.bmp']
for file_name in new_image:
image = pygame.image.load(file_name)
self.images.append(image)
# random.shuffle(self.images)
cover = pygame.image.load('image0.bmp')
#image1 = pygame.image.load(images_list)
width = image.get_width()
height = image.get_height()
for row_index in range(0, self.board_size):
row = []
for col_index in range(0, self.board_size):
x = width * col_index
y = height * row_index
imageindex = row_index * self.board_size + col_index
image = self.images[imageindex]
tile = Tile(x,y,image,cover)
row.append(tile)
self.board.append(row)
def play(self):
# Play the game until the player presses the close box.
# - self is the Game that should be continued or not.
while not self.close_clicked: # until player clicks close box
# play frame
self.handle_events()
self.draw()
if self.continue_game:
self.update()
self.decide_continue()
self.game_Clock.tick(self.FPS) # run at most with FPS Frames Per Second
def handle_events(self):
# Handle each user event by changing the game state appropriately.
# - self is the Game whose events will be handled
events = pygame.event.get()
for event in events:
if event.type == pygame.QUIT:
self.close_clicked = True
if event.type == pygame.MOUSEBUTTONUP and self.continue_game == True:
self.handle_mouse_up(event)
def update(self):
# Update the game objects for the next frame.
# - self is the Game to update
self.score[0] = pygame.time.get_ticks() // 1000
if self.first_image != None and self.match:
print(self.check_matching())
self.first_image = None
self.tile1 = None
self.second_image = None
self.tile2 = None
self.exposed += 1
print(self.exposed)
if self.first_image != None:
if self.second_image != None and not self.match:
# time.sleep(1)
print(self.check_matching())
self.tile1.hide_tile()
self.tile2.hide_tile()
self.second_image = None
self.tile2 = None
self.first_image = None
self.tile1 = None
def handle_mouse_up(self,event):
for row in self.board:
for tile in row:
valid_click = tile.select(event.pos)
if valid_click == True:
# self.number_exposed += 1
# time.sleep(1)
tile.expose_tile()
print(self.click)
if self.click == 0:
self.first_image = tile.image
self.tile1 = tile
elif self.click == 1:
self.second_image = tile.image
self.tile2 = tile
self.click += 1
print(self.first_image)
print(self.second_image)
if self.click > 1:
self.click = 0
def draw(self):
# Draw all game objects.
# - self is thae Game to draw
# draw tiles
self.surface.fill(self.bg_color) # clear the display surface first
for each_row in self.board:
for each_tile in each_row:
each_tile.draw()
self.draw_score()
pygame.display.update() # make the updated surface appear on the display
def draw_score(self):
# 1. Set the color
size = self.surface.get_width()
fg_color = pygame.Color('white')
# 2.create the font object
font = pygame.font.SysFont('', 70)
# 3 Create a text box by rendering the font
text_string = '' + str(self.score[0])
text_box = font.render(text_string, True, fg_color, self.bg_color)
surface_height = self.surface.get_width()
text_box_height = text_box.get_width()
location = (surface_height - text_box_height, 0)
# 4 Compute the location of the text box
#location = (430, 0)
# 5 Blit or pin the text box on the surface
self.surface.blit(text_box, location)
def decide_continue(self):
if self.exposed >= 1:
self.continue_game = False
def check_matching(self):
self.match = self.first_image == self.second_image
return self.match
# Check and remember if the game should continue
# - self is the Game to check
class Tile:
surface = None
border_size = 3
border_color = pygame.Color('black')
# An object in this class represents a Dot that moves
#classmethod
def set_surface(cls,game_surface):
cls.surface = game_surface
# instance method
def __init__(self,x , y, image, cover):
self.image = image
self.cover = cover
self.covered = True
width = self.image.get_width()
height = self.image.get_height()
self.rect = pygame.Rect(x, y, width, height)
def draw(self):
pygame.draw.rect(Tile.surface,Tile.border_color,self.rect,Tile.border_size)
Tile.surface.blit(self.image,self.rect)
if self.covered:
Tile.surface.blit(self.cover, self.rect)
else:
Tile.surface.blit(self.image, self.rect)
# Draw the dot on the surface
# - self is the Dot
def select(self, position):
valid_click = False
if self.rect.collidepoint(position):
if self.covered:
valid_click = True
self.expose_tile()
else:
valid_click = False
return valid_click
def expose_tile(self):
# if a tile is clicked this method will show the picture underneath that tile
self.covered = False
def hide_tile(self):
self.covered = True
def __eq__(self, other_tile):
if self.first_image == other_tile.image:
return True
else:
return False
main()
The tiles do not match, because what you actually do is to compare image objects:
self.match = self.first_image == self.second_image
but each image is loaded twice. For each image are generated to different objects, so they will never match.
Load each image once and use it for 2 matching tiles:
# define unique image names
new_image =['image1.bmp','image2.bmp','image3.bmp','image4.bmp',
'image5.bmp','image6.bmp','image7.bmp','image8.bmp']
# load each unique image
for file_name in new_image:
image = pygame.image.load(file_name)
self.images.append(image)
# create a list where each loaded image object is used twice
self.images = self.images + self.images
Furthermore, since the image names just differ in the number, the definition of the name list can be simplified:
new_image = ['image' + str(i) + '.bmp' for i in range(1,9)]
Extension according to the commend
what about the time delay
Completely remove self.first_image and self.second_image. Adapt Tile:
class Tile:
# [...]
def __eq__(self, other_tile):
return self.image == other_tile.image
Once tiles have been clicked then keep them stated in self.tile1 and self.tile2. When the 1st click occurs, then hide the exposed tiles, if they do not match:
if self.click == 0:
if self.tile1 != self.tile2:
if self.tile1:
self.tile1.hide_tile()
if self.tile2:
self.tile2.hide_tile()
When the 2nd click occurs then set the time (e.g. pygame.time.get_ticks() + 2000) when they have to be covered automatically:
elif self.click == 1:
self.tile2 = tile
self.hide_time = pygame.time.get_ticks() + 2000
Evaluate if the tiles have to be covered in update:
ticks = pygame.time.get_ticks()
if self.tile1 and self.tile2:
if self.tile1 != self.tile2 and self.hide_time > 0 and ticks > self.hide_time:
self.tile1.hide_tile()
self.tile2.hide_tile()
Changes to your code:
class Game:
def __init__(self, surface):
# [...]
self.hide_time = 0
# [...]
def update(self):
ticks = pygame.time.get_ticks()
self.score[0] = ticks // 1000
if self.tile1 and self.tile2:
if self.tile1 != self.tile2 and self.hide_time > 0 and ticks > self.hide_time:
self.tile1.hide_tile()
self.tile2.hide_tile()
def handle_mouse_up(self,event):
self.hide_time = 0
if self.click == 0:
if self.tile1 != self.tile2:
if self.tile1:
self.tile1.hide_tile()
if self.tile2:
self.tile2.hide_tile()
tiles = [t for row in self.board for t in row if t.select(event.pos) and not t.covered]
if any(tiles):
tile = tiles[0]
if self.click == 0:
self.tile1 = tile
elif self.click == 1:
self.tile2 = tile
self.hide_time = pygame.time.get_ticks() + 2000
tile.expose_tile()
self.click += 1
if self.click > 1:
self.click = 0
# [...]
def check_matching(self):
self.match = self.tile1.image == self.tile2.image
return self.match