WIP: ECS / Network System #1
			
				
			
		
		
		
	|  | @ -6,6 +6,7 @@ class ComponentType(str, Enum): | |||
|     POSITION = "POSITION" | ||||
|     CONTROLLABLE = "CONTROLLABLE" | ||||
|     MARKOV = "MARKOV" | ||||
|     SPRITESHEET = "SPRITESHEET" | ||||
| 
 | ||||
| 
 | ||||
| class Component: | ||||
|  |  | |||
|  | @ -0,0 +1,48 @@ | |||
| from .component import Component, ComponentType | ||||
| 
 | ||||
| 
 | ||||
| class SpriteSpec: | ||||
|     def __init__( | ||||
|         self, | ||||
|         ms_per_frame: int, | ||||
|         top_x: int, | ||||
|         top_y: int, | ||||
|         end_x: int, | ||||
|         end_y: int, | ||||
|         frames: int, | ||||
|     ): | ||||
|         self.ms_per_frame = ms_per_frame | ||||
|         self.frames = frames | ||||
|         self.top_x = top_x | ||||
|         self.top_y = top_y | ||||
|         self.end_x = end_x | ||||
|         self.end_y = end_y | ||||
| 
 | ||||
| 
 | ||||
| class SpriteSheet(Component): | ||||
|     def __init__( | ||||
|         self, | ||||
|         source: str, | ||||
|         state_to_spritespec: dict[str, SpriteSpec], | ||||
|         initial_state: str, | ||||
|     ): | ||||
|         super().__init__(ComponentType.SPRITESHEET) | ||||
|         self.source = source | ||||
|         self.state_to_spritespec = state_to_spritespec | ||||
| 
 | ||||
|         # these are only really used for client initialization | ||||
|         self.initial_state = initial_state | ||||
|         self.current_frame = 0 | ||||
|         self.last_update = 0 | ||||
| 
 | ||||
|     def __repr__(self) -> str: | ||||
|         return f"SpriteSheet(source={self.source}, state_to_spritespec={self.state_to_spritespec}, initial_state={self.initial_state}, current_frame={self.current_frame}, last_update={self.last_update})" | ||||
| 
 | ||||
|     def to_dict(self) -> dict: | ||||
|         return { | ||||
|             "source": self.source, | ||||
|             "current_frame": self.current_frame, | ||||
|             "last_update": self.last_update, | ||||
|             "current_state": self.initial_state, | ||||
|             "state_to_spritespec": self.state_to_spritespec, | ||||
|         } | ||||
|  | @ -1,14 +1,33 @@ | |||
| from kennel.engine.components.position import Position | ||||
| 
 | ||||
| from kennel.engine.components.sprite_sheet import SpriteSheet, SpriteSpec | ||||
| from enum import Enum | ||||
| from .entity import Entity, EntityType | ||||
| 
 | ||||
| 
 | ||||
| class CatState(Enum): | ||||
|     IDLE = "IDLE" | ||||
|     FROLICKING = "FROLICKING" | ||||
|     EEPY = "EEPY" | ||||
|     ALERT = "ALERT" | ||||
|     CHASING_CURSOR = "CHASING_CURSOR" | ||||
|     CHASING_CAT = "CHASING_CAT" | ||||
|     SCRATCHING = "SCRATCHING" | ||||
|     ITCHY = "ITCHY" | ||||
| 
 | ||||
| 
 | ||||
| class Cat(Entity): | ||||
|     def __init__(self, id: str): | ||||
|         components = [Position(0, 0)] | ||||
|     def __init__(self, id: str, spritesheet_source: str): | ||||
|         state_to_spritespec = self.get_state_to_spritespec() | ||||
|         components = [ | ||||
|             Position(0, 0), | ||||
|             SpriteSheet(spritesheet_source, state_to_spritespec, CatState.ALERT), | ||||
|         ] | ||||
| 
 | ||||
|         super().__init__(EntityType.CAT, id, components) | ||||
| 
 | ||||
|     def get_state_to_spritespec(self): | ||||
|         return {CatState.ALERT: SpriteSpec(100, 0, 0, 200, 40, 5)} | ||||
| 
 | ||||
| 
 | ||||
| # | ||||
| # # IDLE, FROLICKING, EEPY, ALERT, CHASING_CURSOR, CHASING_CAT, SCRATCHING, ITCHY | ||||
|  | @ -32,14 +51,6 @@ class Cat(Entity): | |||
| # ] | ||||
| # | ||||
| # | ||||
| # class CatState(Enum): | ||||
| #     IDLE = 0 | ||||
| #     FROLICKING = 1 | ||||
| #     EEPY = 2 | ||||
| #     ALERT = 3 | ||||
| #     CHASING_CURSOR = 4 | ||||
| #     CHASING_CAT = 5 | ||||
| #     SCRATCHING = 6 | ||||
| #     ITCHY = 7 | ||||
| 
 | ||||
| # | ||||
| # | ||||
|  |  | |||
|  | @ -104,8 +104,7 @@ class KennelCatsManager: | |||
| 
 | ||||
|             removed_cats = [cats_table[id] for id in self.last_seen.difference(cat_ids)] | ||||
|             added_cats = [cats_table[id] for id in cat_ids.difference(self.last_seen)] | ||||
|             logger.info(f"removing {removed_cats}") | ||||
|             logger.info(f"adding {added_cats}") | ||||
|             logger.info(f"removing {removed_cats}, adding {added_cats}") | ||||
| 
 | ||||
|             for removed in removed_cats: | ||||
|                 self.entity_manager.remove_entity(removed) | ||||
|  | @ -113,7 +112,7 @@ class KennelCatsManager: | |||
|                 self.network_system.server_global_event(entity_death) | ||||
| 
 | ||||
|             for added in added_cats: | ||||
|                 new_cat = Cat(added.id) | ||||
|                 new_cat = Cat(added.id, added.spritesheet) | ||||
|                 self.entity_manager.add_entity(new_cat) | ||||
|                 entity_born = EntityBornEvent(new_cat) | ||||
|                 self.network_system.server_global_event(entity_born) | ||||
|  |  | |||
|  | @ -43,4 +43,7 @@ class KennelCatService: | |||
|     def get_kennel(self) -> List[KennelCat]: | ||||
|         response = requests.get(f"{self.hc_endpoint}/kennel") | ||||
|         response.raise_for_status() | ||||
|         return [KennelCat.from_dict(cat) for cat in response.json()] | ||||
|         cats = [KennelCat.from_dict(cat) for cat in response.json()] | ||||
|         for cat in cats: | ||||
|             cat.spritesheet = self.hc_endpoint + cat.spritesheet | ||||
|         return cats | ||||
|  |  | |||
|  | @ -2,6 +2,7 @@ export enum ComponentType { | |||
|   POSITION = "POSITION", | ||||
|   RENDERABLE = "RENDERABLE", | ||||
|   TRAILING_POSITION = "TRAILING_POSITION", | ||||
|   SPRITESHEET = "SPRITESHEET", | ||||
| } | ||||
| 
 | ||||
| export interface Component { | ||||
|  | @ -22,3 +23,24 @@ export interface TrailingPositionComponent extends Component { | |||
| export interface RenderableComponent extends Component { | ||||
|   name: ComponentType.RENDERABLE; | ||||
| } | ||||
| 
 | ||||
| export interface SpriteSpec { | ||||
|   ms_per_frame: number; | ||||
|   frames: number; | ||||
|   top_x: number; | ||||
|   top_y: number; | ||||
|   end_x: number; | ||||
|   end_y: number; | ||||
| } | ||||
| 
 | ||||
| export interface SpriteSheetComponent extends Component { | ||||
|   name: ComponentType.SPRITESHEET; | ||||
|   source: string; | ||||
|   sheet: HTMLImageElement; | ||||
| 
 | ||||
|   current_frame: number; | ||||
|   last_update: number; | ||||
|   current_state: string; | ||||
| 
 | ||||
|   state_to_spritespec: Record<string, SpriteSpec>; | ||||
| } | ||||
|  |  | |||
|  | @ -5,7 +5,7 @@ export class DebouncePublisher<T> { | |||
| 
 | ||||
|   constructor( | ||||
|     private readonly publisher: (data: T) => void | Promise<void>, | ||||
|     private readonly debounce_ms = 100, | ||||
|     private readonly debounce_ms = 150, | ||||
|   ) {} | ||||
| 
 | ||||
|   public start() { | ||||
|  |  | |||
|  | @ -1,7 +1,6 @@ | |||
| import { | ||||
|   Component, | ||||
|   ComponentType, | ||||
|   PositionComponent, | ||||
|   RenderableComponent, | ||||
|   TrailingPositionComponent, | ||||
| } from "./component"; | ||||
|  | @ -36,10 +35,5 @@ export const create_cat = (base: Entity) => { | |||
|     name: ComponentType.RENDERABLE, | ||||
|   }; | ||||
|   base.components[ComponentType.RENDERABLE] = renderable; | ||||
|   base.components[ComponentType.POSITION] = { | ||||
|     component: ComponentType.POSITION, | ||||
|     x: Math.random() * 1_000, | ||||
|     y: Math.random() * 1_000, | ||||
|   } as unknown as PositionComponent; // TODO: hack
 | ||||
|   return base; | ||||
| }; | ||||
|  |  | |||
|  | @ -10,7 +10,7 @@ import { NetworkSystem } from "./engine/network"; | |||
| import { RenderSystem } from "./engine/render"; | ||||
| import { InputSystem } from "./engine/input"; | ||||
| import { TrailingPositionSystem } from "./engine/trailing_position"; | ||||
| import { drainPoints, setDelay } from "laser-pen"; | ||||
| import { drainPoints, setDelay, setRoundCap } from "laser-pen"; | ||||
| 
 | ||||
| $(async () => { | ||||
|   const client_id = await fetch("/assign", { | ||||
|  | @ -32,6 +32,7 @@ $(async () => { | |||
|   const input_system = new InputSystem(publisher, gamecanvas); | ||||
| 
 | ||||
|   setDelay(500); | ||||
|   setRoundCap(true); | ||||
|   const render_system = new RenderSystem(gamecanvas); | ||||
| 
 | ||||
|   const trailing_position = new TrailingPositionSystem(drainPoints); | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue