Separating game/scene logic

This commit is contained in:
duckduckdoof 2025-02-05 15:33:07 -05:00
parent ebb1460e25
commit 455f392965
9 changed files with 334 additions and 225 deletions

61
lib/engine/game_board.py Normal file
View file

@ -0,0 +1,61 @@
"""
game_board.py
author: Caleb Scott
Representation of the game board/space. Ideally, this module can be
modified/swapped if the geometry of the game changes (2D-3D, etc.)
"""
# CLASSES -----------------------------------------------------------
class FlatWorld:
def __init__(self, init_space: list):
# We assume that the initial space is a rectangular 2D array
# Initialize the world space (2D array)
self.space = init_space
self.width = len(init_space[0])
self.height = len(init_space)
def get_at(self, x, y):
"""
Returns object located at (x,y) coordinate of space.
"""
if (x >= 0 and x < self.width) and (y >= 0 and y < self.height):
return self.space[x][y]
else:
return None
def set_at(self, x, y, object):
"""
Sets object located at (x,y) coordinate of space.
"""
if (x >= 0 and x < self.width) and (y >= 0 and y < self.height):
self.space[x][y] = object
return True
else:
return False
class LayeredFlatWorld:
def __init__(self, layers: dict):
# We assume that layers is a dictionary of 2D arrays.
# Initialize the layers of 2D space
self.layers = {}
for layer in layers.keys():
self.layers[layer] = FlatWorld(layers[layer])
def get_at(self, x, y, layer):
"""
Gets object at (x,y) coordinate at layer
"""
return self.layers[layer].get_at(x, y)
def set_at(self, x, y, layer, object):
"""
Sets object located at (x,y) coordinate at layer
"""
self.layers[layer].set_at(x, y, object)

View file

@ -7,4 +7,21 @@ Configuration file for game objects (like setting default rates, types, etc.).
This is not the same as scene_config.py, which configures the scene (visuals, sprites, etc.).
"""
# CONSTANTS ---------------------------------------------------------
# CONSTANTS ---------------------------------------------------------
# Game Starting Resources
STARTING_RESOURCES = {
"people": 10,
"food": 200,
"metal": 50,
"wood": 100,
"rock": 100
}
# Resource types
RESOURCE_MANPOWER = "Manpower"
RESOURCE_WATER = "Water"
RESOURCE_METALS = "Metals"
RESOURCE_ROCKS = "Rocks"
RESOURCE_WOOD = "Wood"
RESOURCE_POWER = "Power"

View file

@ -9,100 +9,108 @@ visual elements; this is handles in the scene/ python files
# IMPORTS -----------------------------------------------------------
import arcade
from lib.scene.scene_config import *
from lib.scene.scene_tiles import *
from lib.engine.game_config import *
from lib.engine.game_board import LayeredFlatWorld
# FUNCTIONS ---------------------------------------------------------
def init_gb_from_scene_info(scene_info: dict):
"""
Takes a dictionary of 2D arrays (organized by layer name), and
converts them into their proper game board of game objects.
"""
# CLASSES -----------------------------------------------------------
class GameLogic:
def __init__(self, scene, starting_resources):
def __init__(self, layers, starting_resources=STARTING_RESOURCES):
# Initializes the game board (from arcade Scene)
# and starting resources
self.scene = scene
self.game_board = LayeredFlatWorld(layers)
self.resources = starting_resources
def place_structure(self, struct_type, x, y):
"""
Game logic for placing a structure, if valid.
"""
# First check and see if we already have a structure there.
s_tiles = arcade.get_sprites_at_point((x,y), self.scene[LAYER_STRUCTURES])
if len(s_tiles) == 1:
return "Structure already in this space."
# def place_structure(self, struct_type, x, y):
# """
# Game logic for placing a structure, if valid.
# """
# # First check and see if we already have a structure there.
# s_tiles = arcade.get_sprites_at_point((x,y), self.scene[LAYER_STRUCTURES])
# if len(s_tiles) == 1:
# return "Structure already in this space."
# Get the centered location of the tile chosen
# We use the environment layer instead to determine if placement
# is legal.
e_tiles = arcade.get_sprites_at_point((x,y), self.scene[LAYER_ENVIRONMENT])
if len(e_tiles) == 1:
print(e_tiles[0].properties)
env_tile_type = e_tiles[0].properties['class']
c_x, c_y = e_tiles[0].center_x, e_tiles[0].center_y
# # Get the centered location of the tile chosen
# # We use the environment layer instead to determine if placement
# # is legal.
# e_tiles = arcade.get_sprites_at_point((x,y), self.scene[LAYER_ENVIRONMENT])
# if len(e_tiles) == 1:
# print(e_tiles[0].properties)
# env_tile_type = e_tiles[0].properties['class']
# c_x, c_y = e_tiles[0].center_x, e_tiles[0].center_y
# Determine what sprite object to place
if struct_type == LOGGER:
if env_tile_type == TREES:
logger_sprite = LoggerTile(c_x, c_y)
self.scene.add_sprite(LAYER_STRUCTURES, logger_sprite)
return ""
else:
return "Logger must be placed on trees tile."
elif struct_type == CROPS:
if env_tile_type == GROUND:
crops_sprite = CropsTile(c_x, c_y)
self.scene.add_sprite(LAYER_STRUCTURES, crops_sprite)
return ""
else:
return "Crops must be placed on a ground tile."
elif struct_type == HYDROPOWER:
if env_tile_type == WATER:
hydro_sprite = HyroPowerTile(c_x, c_y)
self.scene.add_sprite(LAYER_STRUCTURES, hydro_sprite)
return ""
else:
return "Hydro Power must be placed on a water tile."
elif struct_type == HOUSING:
if env_tile_type == GROUND:
housing_sprite = HousingTile(c_x, c_y)
self.scene.add_sprite(LAYER_STRUCTURES, housing_sprite)
return ""
else:
return "Housing must be placed on a ground tile."
elif struct_type == MINER:
if env_tile_type == IRON:
miner_sprite = MinerTile(c_x, c_y)
self.scene.add_sprite(LAYER_STRUCTURES, miner_sprite)
return ""
else:
return "Miner must be placed on an iron tile."
elif struct_type == FACTORY:
if env_tile_type == GROUND:
factory_sprite = FactoryTile(c_x, c_y)
self.scene.add_sprite(LAYER_STRUCTURES, factory_sprite)
return ""
else:
return "Factory must be placed on a ground tile."
elif struct_type == JUNCTION:
if env_tile_type == GROUND:
junction_sprite = JunctionTile(c_x, c_y)
self.scene.add_sprite(LAYER_STRUCTURES, junction_sprite)
return ""
else:
return "Junctions must be placed on a ground tile."
else:
return ""
# # Determine what sprite object to place
# if struct_type == LOGGER:
# if env_tile_type == TREES:
# logger_sprite = LoggerTile(c_x, c_y)
# self.scene.add_sprite(LAYER_STRUCTURES, logger_sprite)
# return ""
# else:
# return "Logger must be placed on trees tile."
# elif struct_type == CROPS:
# if env_tile_type == GROUND:
# crops_sprite = CropsTile(c_x, c_y)
# self.scene.add_sprite(LAYER_STRUCTURES, crops_sprite)
# return ""
# else:
# return "Crops must be placed on a ground tile."
# elif struct_type == HYDROPOWER:
# if env_tile_type == WATER:
# hydro_sprite = HyroPowerTile(c_x, c_y)
# self.scene.add_sprite(LAYER_STRUCTURES, hydro_sprite)
# return ""
# else:
# return "Hydro Power must be placed on a water tile."
# elif struct_type == HOUSING:
# if env_tile_type == GROUND:
# housing_sprite = HousingTile(c_x, c_y)
# self.scene.add_sprite(LAYER_STRUCTURES, housing_sprite)
# return ""
# else:
# return "Housing must be placed on a ground tile."
# elif struct_type == MINER:
# if env_tile_type == IRON:
# miner_sprite = MinerTile(c_x, c_y)
# self.scene.add_sprite(LAYER_STRUCTURES, miner_sprite)
# return ""
# else:
# return "Miner must be placed on an iron tile."
# elif struct_type == FACTORY:
# if env_tile_type == GROUND:
# factory_sprite = FactoryTile(c_x, c_y)
# self.scene.add_sprite(LAYER_STRUCTURES, factory_sprite)
# return ""
# else:
# return "Factory must be placed on a ground tile."
# elif struct_type == JUNCTION:
# if env_tile_type == GROUND:
# junction_sprite = JunctionTile(c_x, c_y)
# self.scene.add_sprite(LAYER_STRUCTURES, junction_sprite)
# return ""
# else:
# return "Junctions must be placed on a ground tile."
# else:
# return ""
def delete_structure(self, x, y):
"""
Game logic for deleting a structure, if valid.
"""
s_tiles = arcade.get_sprites_at_point((x,y), self.scene[LAYER_STRUCTURES])
if len(s_tiles) == 1:
struct_sprites = self.scene[LAYER_STRUCTURES]
struct_sprites.remove(s_tiles[0])
return ""
else:
return "No structure on that space."
# def delete_structure(self, x, y):
# """
# Game logic for deleting a structure, if valid.
# """
# s_tiles = arcade.get_sprites_at_point((x,y), self.scene[LAYER_STRUCTURES])
# if len(s_tiles) == 1:
# struct_sprites = self.scene[LAYER_STRUCTURES]
# struct_sprites.remove(s_tiles[0])
# return ""
# else:
# return "No structure on that space."

View file

@ -12,14 +12,50 @@ between the game scene/rendering and game logic/objects.
import math
# CONSTANTS ---------------------------------------------------------
from lib.engine.game_config import *
from global_config import *
MANPOWER = "Manpower"
WATER = "Water"
METALS = "Metals"
ROCKS = "Rocks"
WOOD = "Wood"
POWER = "Power"
# FUNCTIONS ---------------------------------------------------------
def str_to_game_object(game_obj_str: str):
"""
Factory method: given a game object string
(usually from tileset arrays), return the corresponding object.
"""
if game_obj_str == JUNCTION:
return Junction()
elif game_obj_str == HOUSING:
return Housing()
elif game_obj_str == ROCKSILO:
return Silo(RESOURCE_ROCKS)
elif game_obj_str == METALSILO:
return Silo(RESOURCE_METALS)
elif game_obj_str == WOODSILO:
return Silo(RESOURCE_WOOD)
elif game_obj_str == WATER_TOWER:
return WaterTower()
elif game_obj_str == CAPACITOR:
return Capacitor()
elif game_obj_str == HYDRO_POWER:
return HydroPower()
elif game_obj_str == CROPS:
return Crops()
elif game_obj_str == FACTORY:
return Factory()
elif game_obj_str == FOUNDATION:
return Foundation()
elif game_obj_str == WATER:
return Water()
elif game_obj_str == TREES:
return Trees()
elif game_obj_str == GROUND:
return Ground()
elif game_obj_str == METAL:
return Metals()
elif game_obj_str == ROCKS:
return Rocks()
else:
return None
# CLASSES -----------------------------------------------------------
@ -55,17 +91,17 @@ class Junction(GameObject):
class Housing(Storage):
def __init__(self):
super().__init__("Housing", MANPOWER, 20.0)
super().__init__("Housing", RESOURCE_MANPOWER, 20.0)
class WaterTower(Storage):
def __init__(self):
super().__init__("WaterTower", WATER, 600.0)
super().__init__("WaterTower", RESOURCE_WATER, 600.0)
class Capacitor(Storage):
def __init__(self):
super().__init__("Capacitor", POWER, 100.0)
super().__init__("Capacitor", RESOURCE_POWER, 100.0)
class Silo(Storage):
@ -94,6 +130,16 @@ class Quarry(Producer):
def __init__(self):
super().__init__("Quarry", 0.0)
class Crops(Producer):
def __init__(self):
super().__init__("Crops", 0.0)
class Factory(Producer):
def __init__(self):
super().__init__("Factory", 0.0)
## LAYER: Foundations
class Foundation(GameObject):
@ -105,7 +151,7 @@ class Foundation(GameObject):
class Water(Storage):
def __init__(self):
super().__init__("Water", WATER, math.inf, math.inf)
super().__init__("Water", RESOURCE_WATER, math.inf, math.inf)
class Ground(GameObject):
@ -115,14 +161,14 @@ class Ground(GameObject):
class Trees(Storage):
def __init__(self):
super().__init__("Trees", WOOD, 500.0, 500.0)
super().__init__("Trees", RESOURCE_WOOD, 500.0, 500.0)
class Metals(Storage):
def __init__(self):
super().__init__("Metals", METALS, 500.0, 500.0)
super().__init__("Metals", RESOURCE_METALS, 500.0, 500.0)
class Rocks(Storage):
def __init__(self):
super().__init__("Rocks", ROCKS, 500.0, 500.0)
super().__init__("Rocks", RESOURCE_ROCKS, 500.0, 500.0)