def __init__(self, graphics): self.__log = get_logger("world") self.graphics = graphics self.entity_manager = EntityManager(self) self.team_manager = TeamManager() self.action_manager = ActionManager() self.__cfg_header = "header" self.__cfg_entities = "entities" self.__cfg_map = "map" self.__started = False
def handle_event(self, evt, game_events): if evt.type == pygame.QUIT or (evt.type == pygame.KEYDOWN and evt.key == pygame.K_ESCAPE): self.consume(evt) self._finished = True return self.frame.handle_event(evt, game_events) # if absolutely nothing handled the event, the user has tried to do some kind of interaction # with the map itself if not self.is_consumed(evt): if evt.type == pygame.MOUSEBUTTONDOWN: self.consume(evt) self.current_mode.on_map_mousedown(evt, pygame.mouse.get_pos()) elif evt.type == pygame.MOUSEMOTION and pygame.mouse.get_pressed( )[0]: self.consume(evt) self.current_mode.on_map_motion(evt, pygame.mouse.get_pos()) elif evt.type == pygame.KEYDOWN and evt.key == pygame.K_t: # copy level state -> we don't want the actual movement and deaths of entities to be reflected # in our copy of the level # easiest way to handle this is to serialize our level, then load it rather than some # complicated deepcopy incomplementation stats = copy.copy(self.level.stats) test_level = Level(self.assets, EntityManager.create_default(), stats) test_level.deserialize(self.level.serialize()) test_level.position = self.level.position state_stack.push( PerformanceMeasurement( state_stack, self.game_events, RunLevel(self.game_events, self.assets, test_level, stats))) if evt.type == pygame.MOUSEBUTTONUP: self.current_mode.on_map_mouseup(evt, pygame.mouse.get_pos())
def main(): """ The main method. Handles initial startup arguments and sets up the game object """ entityManager = EntityManager.EntityManager() componentManager = ComponentManager.ComponentManager() systemManager = SystemManager.SystemManager(entityManager, componentManager) clock = pygame.time.Clock() # TODO - create a massive JSON file with data on all entities, including base components and default values createPlayer(entityManager, componentManager, systemManager) while (True): systemManager.update() clock.tick(30) input("Press the enter key to continue")
def __init__(self): super().__init__() self.entity_manager = EntityManager() self.entity_manager.add(Player(100, 100)) self.add_bawx(-100, -100, 500, 500)
class GameState(State): def __init__(self): super().__init__() self.entity_manager = EntityManager() self.entity_manager.add(Player(100, 100)) self.add_bawx(-100, -100, 500, 500) def add_phorm(self, px, py, pw): self.entity_manager.add(Platform(px, py, pw, 5)) def add_bawx(self, bx, by, bw, bh): self.entity_manager.add(Platform(bx, by, bw, 5)) self.entity_manager.add(Platform(bx, by, 5, bh)) self.entity_manager.add(Platform(bx + bw, by, 5, bh + 5)) self.entity_manager.add(Platform(bx, by + bh, bw + 5, 5)) def tick(self): self.entity_manager.tick(self) def draw(self, screen): self.entity_manager.draw(screen)
class World(object): # pylint: disable=R0902 """Stores the information about the environment and terrain""" def __init__(self, graphics): self.__log = get_logger("world") self.graphics = graphics self.entity_manager = EntityManager(self) self.team_manager = TeamManager() self.action_manager = ActionManager() self.__cfg_header = "header" self.__cfg_entities = "entities" self.__cfg_map = "map" self.__started = False def start(self): """Initializes or restart the World values""" if self.__started: return self.entity_manager.start() self.team_manager.start() self.action_manager.start() self.redraw_map = True self.redraw_minimap = True self.map = [] self.map_name = None self.set_folder(MAP_FOLDER) self.__queue_map = deque() self.__queue_minimap = deque() self.__started = True def close(self): """Called when the World is asked to close""" if not self.__started: return self.entity_manager.close() self.team_manager.close() self.action_manager.close() self.map = None self.map_name = None self.__folder = None self.__queue_map = None self.__queue_minimap = None self.__started = False def restart(self): """Restarts the world""" self.close() self.start() def update(self): """Sends the update call to entity manager and the rest of systems""" if self.__started: self.entity_manager.update() # Check the deleted entities and propagate the update() call self.__action_update() # Handle the pending actions def submit_action(self, action): """Called when game related action has ocurred and must be added to action manager""" self.action_manager.new_action(action) def __action_update(self): """Called when we need to handle game actions""" # TODO: handle actions when actions code is done # for action in self.action_manager: # Read any pending action # atype = action.type # pass pass def get_folder(self): """Returns the current World load/save folder""" return self.__folder def set_folder(self, folder): """Sets the current World load/save folder""" self.__folder = get_base_dir() + sep + folder def list(self): """Returns the maps in current selected folder""" files = {} files_names = [] files_full = [] folder = self.get_folder() check_dir(folder) for name in listdir(folder): full = folder + sep + name if isfile(full): files[name] = full files_names.append(name) files_full.append(full) return files, files_names, files_full def load(self, filename): """Loads the text map data and deserializes entities""" self.map_name = filename file_path = self.get_folder() + sep + filename config = SafeConfigParser() if not config.read(file_path): raise IOError("Map filename '%s' doesn't exist" % file_path) # Get the save header s = self.__cfg_header version = float(config.get(s, "version")) if version != WORLD_VERSION: self.__log.warning("Version mismatch, save is %s, and internal version is %s" % (version, WORLD_VERSION)) # Deserialize and load each entity s = self.__cfg_entities for uid in config.options(s): data = chr_bytes(config.get(s, uid)) self.entity_manager.deserialize_entity(int(uid), data) s = self.__cfg_map self.map = [] for str_x in config.options(s): x = int(str_x) while len(self.map) <= x: self.map.append(None) # Fill the unnallocated space y = config.get(s, str_x) self.map[x] = y for x, line in enumerate(self.map): if line == None: raise ParsingError("Missing map line definition at line %s" % x) self.redraw_map = True self.redraw_minimap = True self.__log.info("Loaded world %s" % filename) def save(self, filename): """Saves the text map and serialized entities""" folder = self.get_folder() check_dir(folder) file_path = folder + sep + filename config = SafeConfigParser() # Add the save header s = self.__cfg_header config.add_section(s) config.set(s, "version", str(WORLD_VERSION)) # Serialize and save each entity s = self.__cfg_entities config.add_section(s) for entity in self.entity_manager.get_entities().values(): uid = entity.get_uid() data = self.entity_manager.serialize_entity(uid) config.set(s, str(uid), ord_bytes(data)) # Add the map content s = self.__cfg_map config.add_section(s) for x, y in enumerate(self.map): config.set(s, str(x), y) cfg_file = open(file_path, "w") config.write(cfg_file) cfg_file.close() self.redraw_map = True self.redraw_minimap = True self.__log.info("Saved world %s" % filename) def get_size(self): """Returns the size of the map""" sx = len(self.map) try: sy = len(self.map[0]) except IndexError: sy = 0 return (sx, sy) def get_cell(self, pos): """Returns the cell value in the specified position""" x, y = pos return self.map[x][y] def set_cell(self, pos, value): """Sets the cell value in the specified position""" x, y = pos line = self.map[x] self.map[x] = line[:y] + value + line[y+1:] def draw_cell(self, cell, pos, size): """Draws a single cell""" color = CELL_COLORS[cell] x, y = pos self.graphics.draw_rect(color, [ceil(x), ceil(y), ceil(size[0]), ceil(size[1])], 0) def draw(self): """Draws the map""" if len(self.__queue_map): return self.draw_map_queue() elif not self.redraw_map: self.graphics.draw_preset("world-map") return False else: self.redraw_map = False size = (WORLD_CELL_SIZE, WORLD_CELL_SIZE) # Center the map for y, line in enumerate(self.map): if line == None: continue for x, char in enumerate(line): cell = CELL_TYPES_INVERSE[char] data = (cell, (x, y), size) self.__queue_map.append(data) self.graphics.use_preset("world-map") self.graphics.draw_fill(COLOR_BLACK) # Cleans the preset before start drawing self.graphics.use_preset(None) return self.draw_map_queue() self.entity_manager.draw() # Propagate the draw() call def draw_map_queue(self): """Handles the queue of cells to be drawed in map, returns if drawing time was exceeded""" start_time = time() self.graphics.use_preset("world-map") exceeded = False while not exceeded: if len(self.__queue_map) == 0: break elif time() - start_time > MAP_DRAW_TIME: exceeded = True else: cell, pos, size = self.__queue_map.pop() self.draw_minicell(cell, pos, size) self.graphics.use_preset(None) return exceeded def draw_minicell(self, cell, pos, size): """Draws a single pixel cell""" color = CELL_COLORS[cell] x, y = pos if (size[0] < 1 or size[1] < 1) and self.graphics.get_implementation() == "pygame": self.graphics.draw_circle(color, [int(ceil(x)), int(ceil(y))], 0, 0) else: self.graphics.draw_rect(color, [ceil(x), ceil(y), ceil(size[0]), ceil(size[1])], 0) def draw_minimap(self, rect): # pylint: disable=R0914 """Draws the minimap, returns if drawing didn't finished""" if len(self.__queue_minimap): return self.draw_minimap_queue() elif not self.redraw_minimap: self.graphics.draw_preset("world-minimap", rect) return False else: self.redraw_minimap = False self.graphics.use_preset("world-minimap") self.graphics.draw_fill(COLOR_BLACK) # Cleans the preset before start drawing self.graphics.use_preset(None) mx, my = self.get_size() if mx == 0 or my == 0: return True # Not loaded px, py, sx, sy = rect sx, sy = sx - 2, sy - 2 biggest = float(max(mx, my)) smallest = min(mx, my) cell_size = (sx / biggest, sy / biggest) # Center the minimap bx = px + (((mx - smallest) / 2.0) * cell_size[0]) by = py + (((my - smallest) / 2.0) * cell_size[1]) for y, line in enumerate(self.map): if line == None: continue for x, char in enumerate(line): cell = CELL_TYPES_INVERSE[char] data = (cell, (bx + (x * cell_size[0]), by + (y * cell_size[1])), cell_size) self.__queue_minimap.append(data) return True def draw_minimap_queue(self): """Handles the queue of cells to be drawed in minimap, returns if drawing time was exceeded""" start_time = time() self.graphics.use_preset("world-minimap") exceeded = False while not exceeded: if len(self.__queue_minimap) == 0: break elif time() - start_time > MINIMAP_DRAW_TIME: exceeded = True else: cell, pos, size = self.__queue_minimap.pop() self.draw_minicell(cell, pos, size) self.graphics.use_preset(None) return exceeded def started(self): """Returns the started flag""" return self.__started
import time from sys import stdin import ids from barfly import BarFly from entities import EntityManager from messages import MessageDispatcher from miner import Miner from minerswife import MinersWife entities = EntityManager() messages = MessageDispatcher(entities) entities.register(Miner(messages, ids.MINER)) entities.register(MinersWife(messages, ids.ELSA)) entities.register(BarFly(messages, ids.BAR_FLY)) while True: for i in range(10): [e.update() for e in entities] time.sleep(1) messages.dispatch_delayed_messages() print("Enter to continue") stdin.readline()
def __init__(self, assets): super().__init__() self.assets = assets # type: AssetManager self.entity_manager = EntityManager( [constants.Interface], [constants.Interface]) # own manager for interface # create a level to edit self.level = Level(assets, EntityManager.create_editor(), Statistics(Labels())) # shim to create a callback before UI draws self.entity_manager.register(_ModeDrawHelper(self.on_pre_ui_draw)) # frame to contain all other windows self.frame = Frame(make_vector(0, 0), config.screen_rect.size) self.entity_manager.register(self.frame) # scrollbars to move map self.scroll_map_horizontal = create_slider( self.assets.gui_atlas, make_vector(*config.screen_rect.bottomleft) + make_vector(10, -20), config.screen_rect.width - 20, 0, self.level.tile_map.width * self.level.tile_map.tileset.tile_width, on_value_changed=bind_callback_parameters( self.on_horizontal_scroll), thumb=self.assets.gui_atlas.load_static("sb_thumb"), thumb_mo=self.assets.gui_atlas.load_static("sb_thumb_light"), sb_type=ScrollbarType.HORIZONTAL) self.scroll_map_vertical = create_slider( self.assets.gui_atlas, make_vector(*config.screen_rect.topright) + make_vector(-20, 10), config.screen_rect.height - 40, 0, self.level.tile_map.height * self.level.tile_map.tileset.tile_height, on_value_changed=bind_callback_parameters(self.on_vertical_scroll), thumb=self.assets.gui_atlas.load_static("sb_thumb"), thumb_mo=self.assets.gui_atlas.load_static("sb_thumb_light"), sb_type=ScrollbarType.VERTICAL) self.frame.add_child(self.scroll_map_horizontal) self.frame.add_child(self.scroll_map_vertical) # ... the various dialogs used by editor self.entity_tool_dialog = EntityToolDialog(self.assets.gui_atlas) self.frame.add_child(self.entity_tool_dialog) self.tile_dialog = TilePickerDialog(self.assets) self.frame.add_child(self.tile_dialog) self.config_dialog = LevelConfigDialog(self.level, self.assets.gui_atlas) self.frame.add_child(self.config_dialog) self.entity_dialog = EntityPickerDialog(self.level) self.frame.add_child(self.entity_dialog) self.entity_tools = EntityToolDialog # editor states to handle relevant actions self.current_mode = None self.place_mode = PlaceMode(self.tile_dialog, self.level) self.passable_mode = PassableMode(self.level) self.config_mode = ConfigMode() self.entity_mode = EntityMode(self.entity_dialog, self.entity_tool_dialog, self.level) self.set_mode(self.place_mode) self.mode_dialog = ModeDialog( self.assets.gui_atlas, on_tile_mode_callback=bind_callback_parameters( self.set_mode, self.place_mode), on_passable_mode_callback=bind_callback_parameters( self.set_mode, self.passable_mode), on_config_mode_callback=bind_callback_parameters( self.set_mode, self.config_mode), on_entity_mode_callback=bind_callback_parameters( self.set_mode, self.entity_mode)) self.frame.add_child(self.mode_dialog) self._finished = False
class EditorState(GameState, EventHandler): def __init__(self, assets): super().__init__() self.assets = assets # type: AssetManager self.entity_manager = EntityManager( [constants.Interface], [constants.Interface]) # own manager for interface # create a level to edit self.level = Level(assets, EntityManager.create_editor(), Statistics(Labels())) # shim to create a callback before UI draws self.entity_manager.register(_ModeDrawHelper(self.on_pre_ui_draw)) # frame to contain all other windows self.frame = Frame(make_vector(0, 0), config.screen_rect.size) self.entity_manager.register(self.frame) # scrollbars to move map self.scroll_map_horizontal = create_slider( self.assets.gui_atlas, make_vector(*config.screen_rect.bottomleft) + make_vector(10, -20), config.screen_rect.width - 20, 0, self.level.tile_map.width * self.level.tile_map.tileset.tile_width, on_value_changed=bind_callback_parameters( self.on_horizontal_scroll), thumb=self.assets.gui_atlas.load_static("sb_thumb"), thumb_mo=self.assets.gui_atlas.load_static("sb_thumb_light"), sb_type=ScrollbarType.HORIZONTAL) self.scroll_map_vertical = create_slider( self.assets.gui_atlas, make_vector(*config.screen_rect.topright) + make_vector(-20, 10), config.screen_rect.height - 40, 0, self.level.tile_map.height * self.level.tile_map.tileset.tile_height, on_value_changed=bind_callback_parameters(self.on_vertical_scroll), thumb=self.assets.gui_atlas.load_static("sb_thumb"), thumb_mo=self.assets.gui_atlas.load_static("sb_thumb_light"), sb_type=ScrollbarType.VERTICAL) self.frame.add_child(self.scroll_map_horizontal) self.frame.add_child(self.scroll_map_vertical) # ... the various dialogs used by editor self.entity_tool_dialog = EntityToolDialog(self.assets.gui_atlas) self.frame.add_child(self.entity_tool_dialog) self.tile_dialog = TilePickerDialog(self.assets) self.frame.add_child(self.tile_dialog) self.config_dialog = LevelConfigDialog(self.level, self.assets.gui_atlas) self.frame.add_child(self.config_dialog) self.entity_dialog = EntityPickerDialog(self.level) self.frame.add_child(self.entity_dialog) self.entity_tools = EntityToolDialog # editor states to handle relevant actions self.current_mode = None self.place_mode = PlaceMode(self.tile_dialog, self.level) self.passable_mode = PassableMode(self.level) self.config_mode = ConfigMode() self.entity_mode = EntityMode(self.entity_dialog, self.entity_tool_dialog, self.level) self.set_mode(self.place_mode) self.mode_dialog = ModeDialog( self.assets.gui_atlas, on_tile_mode_callback=bind_callback_parameters( self.set_mode, self.place_mode), on_passable_mode_callback=bind_callback_parameters( self.set_mode, self.passable_mode), on_config_mode_callback=bind_callback_parameters( self.set_mode, self.config_mode), on_entity_mode_callback=bind_callback_parameters( self.set_mode, self.entity_mode)) self.frame.add_child(self.mode_dialog) self._finished = False def draw(self, screen): screen.fill(self.level.background_color) self.level.draw(screen) self.entity_manager.draw(screen, self.level.view_rect, False) def set_mode(self, new_mode): if new_mode is self.place_mode: # turn on/off relevant dialogs self.tile_dialog.enabled = True self.entity_tool_dialog.enabled = False self.config_dialog.enabled = False self.entity_dialog.enabled = False elif new_mode is self.passable_mode: self.tile_dialog.enabled = False self.entity_tool_dialog.enabled = False self.config_dialog.enabled = False self.entity_dialog.enabled = False elif new_mode is self.config_mode: self.tile_dialog.enabled = False self.entity_tool_dialog.enabled = False self.config_dialog.enabled = True self.entity_dialog.enabled = False elif new_mode is self.entity_mode: self.tile_dialog.enabled = False self.entity_tool_dialog.enabled = True self.config_dialog.enabled = False self.entity_dialog.enabled = True else: raise NotImplementedError # unknown mode self.current_mode = new_mode def update(self, dt): self.entity_manager.update(dt, self.level.view_rect, False) @property def finished(self): return self._finished def on_pre_ui_draw(self, screen): self.current_mode.draw(screen) def activated(self): self.game_events.register(self) def deactivated(self): self.game_events.unregister(self) def handle_event(self, evt, game_events): if evt.type == pygame.QUIT or (evt.type == pygame.KEYDOWN and evt.key == pygame.K_ESCAPE): self.consume(evt) self._finished = True return self.frame.handle_event(evt, game_events) # if absolutely nothing handled the event, the user has tried to do some kind of interaction # with the map itself if not self.is_consumed(evt): if evt.type == pygame.MOUSEBUTTONDOWN: self.consume(evt) self.current_mode.on_map_mousedown(evt, pygame.mouse.get_pos()) elif evt.type == pygame.MOUSEMOTION and pygame.mouse.get_pressed( )[0]: self.consume(evt) self.current_mode.on_map_motion(evt, pygame.mouse.get_pos()) elif evt.type == pygame.KEYDOWN and evt.key == pygame.K_t: # copy level state -> we don't want the actual movement and deaths of entities to be reflected # in our copy of the level # easiest way to handle this is to serialize our level, then load it rather than some # complicated deepcopy incomplementation stats = copy.copy(self.level.stats) test_level = Level(self.assets, EntityManager.create_default(), stats) test_level.deserialize(self.level.serialize()) test_level.position = self.level.position state_stack.push( PerformanceMeasurement( state_stack, self.game_events, RunLevel(self.game_events, self.assets, test_level, stats))) if evt.type == pygame.MOUSEBUTTONUP: self.current_mode.on_map_mouseup(evt, pygame.mouse.get_pos()) # don't consume this event def on_horizontal_scroll(self, new_val): existing = self.level.position existing.x = new_val self.level.position = existing self.scroll_map_horizontal.max_value = self.level.tile_map.width * self.level.tile_map.tile_width def on_vertical_scroll(self, new_val): existing = self.level.position existing.y = new_val self.level.position = existing self.scroll_map_vertical.max_value = self.level.tile_map.height * self.level.tile_map.height