3
\$\begingroup\$

This is a simple game I am making in the arcade library of Python. I am quite new to object-oriented programming as well as game development. I feel like a lot of the code is inefficient, so I was hoping to get some improvements on the code. Any kind of suggestion is appreciated.

import os
import random
import arcade
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
 self.background = None
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
 room.numCoins += 1
 # Add the coin to the lists
 room.goal_list.append(goal)
 # 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 = 5.2
 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
def setup_room_3():
 room = Room()
 room.wall_list = arcade.SpriteList(use_spatial_hash=True)
 room.goal_list = arcade.SpriteList()
 room.victory_sprite = arcade.SpriteList(use_spatial_hash=True)
 # Draw boundaries
 for y in (0, SCREEN_HEIGHT - SPRITE_SIZE):
 # Loop for each box going across
 for x in range(0, SCREEN_WIDTH, SPRITE_SIZE):
 wall = arcade.Sprite(":resources:images/tiles/stoneCenter.png", SPRITE_SCALING)
 wall.left = x
 wall.bottom = y
 room.wall_list.append(wall)
 # Create left and right column of boxes
 for x in (0, SCREEN_WIDTH - SPRITE_SIZE):
 # Loop for each box going across
 for y in range(SPRITE_SIZE, SCREEN_HEIGHT - SPRITE_SIZE, SPRITE_SIZE):
 wall = arcade.Sprite(":resources:images/tiles/stoneCenter.png", SPRITE_SCALING)
 wall.left = x
 wall.bottom = y
 room.wall_list.append(wall)
 # Create boxes in the middle
 for x in range(128, SCREEN_WIDTH, 134):
 for y in range(140, SCREEN_HEIGHT - 50, 170):
 wall = arcade.Sprite(":resources:images/tiles/brickGrey.png", 0.4)
 wall.center_x = x
 wall.center_y = y
 # wall.angle = 45
 room.wall_list.append(wall)
 # Create coins
 for i in range(50):
 coin = arcade.Sprite(":resources:images/enemies/fishPink.png", 0.25)
 coin.center_x = random.randrange(100, 700)
 coin.center_y = random.randrange(100, 500)
 while coin.change_x == 0 and coin.change_y == 0:
 coin.change_x = random.randrange(-4, 5)
 coin.change_y = random.randrange(-4, 5)
 room.goal_list.append(coin)
 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 = self.score = 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 = 2
 # list of rooms
 self.rooms = []
 # Create the rooms
 room = setup_room_1()
 self.rooms.append(room)
 room = setup_room_2()
 self.rooms.append(room)
 room = setup_room_3()
 self.rooms.append(room)
 self.totalScore = 0
 self.set_mouse_visible(False)
 def setup(self):
 """ Set up the game and initialize the variables. """
 self.score = 0
 # -- 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)
 if self.current_room == 2:
 self.player_sprite = arcade.Sprite(":resources:images/animated_characters/female_person"
 "/femalePerson_climb0.png", SPRITE_SCALING)
 self.player_sprite.center_x = 340
 self.player_sprite.center_y = 300
 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)
 def on_draw(self):
 arcade.start_render()
 arcade.draw_lrwh_rectangle_textured(0, 0,
 SCREEN_WIDTH, SCREEN_HEIGHT,
 self.rooms[self.current_room].background)
 self.rooms[self.current_room].wall_list.draw()
 self.rooms[self.current_room].goal_list.draw()
 if self.current_room != 2:
 self.rooms[self.current_room].enemy_list.draw()
 self.rooms[self.current_room].victory_sprite.draw()
 if self.current_room == 0:
 arcade.draw_text("Help Nick collect items for his coffee!", 250, 570, arcade.color.BLACK, 20)
 elif self.current_room == 1:
 arcade.draw_text("Help Nick collect grasshoppers!", 250, 570, arcade.color.BLACK, 20)
 elif self.current_room == 2:
 arcade.draw_text("Help Nick collect all the fish (use your mouse to catch them)", 250, 570,
 arcade.color.BLACK, 20)
 output1 = f"Score: {self.score}"
 arcade.draw_text(output1, 10, 560, arcade.color.WHITE, 14)
 output2 = f"Total Score: {self.totalScore}"
 arcade.draw_text(output2, 10, 540, arcade.color.WHITE, 14)
 # 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_mouse_motion(self, x, y, dx, dy):
 if self.current_room == 2:
 self.player_sprite.center_x = x
 self.player_sprite.center_y = y
 def on_update(self, delta_time):
 if not self.game_over:
 if self.current_room == 0 or self.current_room == 1:
 # 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
 self.score += 1
 self.totalScore += 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 next level
 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()
 elif self.current_room == 2:
 for coin in self.rooms[self.current_room].goal_list:
 coin.center_x += coin.change_x
 walls_hit = arcade.check_for_collision_with_list(coin, self.rooms[self.current_room].wall_list)
 for wall in walls_hit:
 if coin.change_x > 0:
 coin.right = wall.left
 elif coin.change_x < 0:
 coin.left = wall.right
 if len(walls_hit) > 0:
 coin.change_x *= -1
 coin.center_y += coin.change_y
 walls_hit = arcade.check_for_collision_with_list(coin, self.rooms[self.current_room].wall_list)
 for wall in walls_hit:
 if coin.change_y > 0:
 coin.top = wall.bottom
 elif coin.change_y < 0:
 coin.bottom = wall.top
 if len(walls_hit) > 0:
 coin.change_y *= -1
 # Generate a list of all sprites that collided with the player.
 hit_list = arcade.check_for_collision_with_list(self.player_sprite,
 self.rooms[self.current_room].goal_list)
 # Loop through each colliding sprite, remove it, and add to the score.
 for coin in hit_list:
 coin.remove_from_sprite_lists()
 arcade.play_sound(self.collect_goal_sound)
 self.score += 1
 self.totalScore += 1
 if self.score >= 50:
 self.game_over = True
 self.current_room = 0
 self.setup()
def main():
 window = MainGame()
 window.setup()
 arcade.run()
if __name__ == "__main__":
 main()
asked Nov 9, 2020 at 10:45
\$\endgroup\$

1 Answer 1

1
\$\begingroup\$

All the range(0, number) can be simplified to just range(number).


You can change

if self.current_room == 0 or self.current_room == 1:

to

if self.current_room in [0, 1]:

if len(wall_hit_list) == 0 and len(coin_hit_list) == 0:

can be

if not wall_hit_list and not coin_hit_list:

You can change

if len(arcade.check_for_collision_with_list(self.player_sprite,
 self.rooms[self.current_room].enemy_list)) > 0:
 self.game_over = True

to

if arcade.check_for_collision_with_list(self.player_sprite, self.rooms[self.current_room].enemy_list):
 self.game_over = True

answered Nov 9, 2020 at 15:42
\$\endgroup\$
1
  • \$\begingroup\$ if not (wall_hit_list or coin_hit_list): using de morgan's law \$\endgroup\$ Commented Nov 10, 2020 at 10:27

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.