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