WIP: ECS / Network System #1
|
@ -6,6 +6,7 @@ class ComponentType(str, Enum):
|
||||||
POSITION = "POSITION"
|
POSITION = "POSITION"
|
||||||
CONTROLLABLE = "CONTROLLABLE"
|
CONTROLLABLE = "CONTROLLABLE"
|
||||||
MARKOV = "MARKOV"
|
MARKOV = "MARKOV"
|
||||||
|
SPRITESHEET = "SPRITESHEET"
|
||||||
|
|
||||||
|
|
||||||
class Component:
|
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.position import Position
|
||||||
|
from kennel.engine.components.sprite_sheet import SpriteSheet, SpriteSpec
|
||||||
|
from enum import Enum
|
||||||
from .entity import Entity, EntityType
|
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):
|
class Cat(Entity):
|
||||||
def __init__(self, id: str):
|
def __init__(self, id: str, spritesheet_source: str):
|
||||||
components = [Position(0, 0)]
|
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)
|
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
|
# # 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)]
|
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)]
|
added_cats = [cats_table[id] for id in cat_ids.difference(self.last_seen)]
|
||||||
logger.info(f"removing {removed_cats}")
|
logger.info(f"removing {removed_cats}, adding {added_cats}")
|
||||||
logger.info(f"adding {added_cats}")
|
|
||||||
|
|
||||||
for removed in removed_cats:
|
for removed in removed_cats:
|
||||||
self.entity_manager.remove_entity(removed)
|
self.entity_manager.remove_entity(removed)
|
||||||
|
@ -113,7 +112,7 @@ class KennelCatsManager:
|
||||||
self.network_system.server_global_event(entity_death)
|
self.network_system.server_global_event(entity_death)
|
||||||
|
|
||||||
for added in added_cats:
|
for added in added_cats:
|
||||||
new_cat = Cat(added.id)
|
new_cat = Cat(added.id, added.spritesheet)
|
||||||
self.entity_manager.add_entity(new_cat)
|
self.entity_manager.add_entity(new_cat)
|
||||||
entity_born = EntityBornEvent(new_cat)
|
entity_born = EntityBornEvent(new_cat)
|
||||||
self.network_system.server_global_event(entity_born)
|
self.network_system.server_global_event(entity_born)
|
||||||
|
|
|
@ -43,4 +43,7 @@ class KennelCatService:
|
||||||
def get_kennel(self) -> List[KennelCat]:
|
def get_kennel(self) -> List[KennelCat]:
|
||||||
response = requests.get(f"{self.hc_endpoint}/kennel")
|
response = requests.get(f"{self.hc_endpoint}/kennel")
|
||||||
response.raise_for_status()
|
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",
|
POSITION = "POSITION",
|
||||||
RENDERABLE = "RENDERABLE",
|
RENDERABLE = "RENDERABLE",
|
||||||
TRAILING_POSITION = "TRAILING_POSITION",
|
TRAILING_POSITION = "TRAILING_POSITION",
|
||||||
|
SPRITESHEET = "SPRITESHEET",
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Component {
|
export interface Component {
|
||||||
|
@ -22,3 +23,24 @@ export interface TrailingPositionComponent extends Component {
|
||||||
export interface RenderableComponent extends Component {
|
export interface RenderableComponent extends Component {
|
||||||
name: ComponentType.RENDERABLE;
|
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(
|
constructor(
|
||||||
private readonly publisher: (data: T) => void | Promise<void>,
|
private readonly publisher: (data: T) => void | Promise<void>,
|
||||||
private readonly debounce_ms = 100,
|
private readonly debounce_ms = 150,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
public start() {
|
public start() {
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
import {
|
import {
|
||||||
Component,
|
Component,
|
||||||
ComponentType,
|
ComponentType,
|
||||||
PositionComponent,
|
|
||||||
RenderableComponent,
|
RenderableComponent,
|
||||||
TrailingPositionComponent,
|
TrailingPositionComponent,
|
||||||
} from "./component";
|
} from "./component";
|
||||||
|
@ -36,10 +35,5 @@ export const create_cat = (base: Entity) => {
|
||||||
name: ComponentType.RENDERABLE,
|
name: ComponentType.RENDERABLE,
|
||||||
};
|
};
|
||||||
base.components[ComponentType.RENDERABLE] = 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;
|
return base;
|
||||||
};
|
};
|
||||||
|
|
|
@ -10,7 +10,7 @@ import { NetworkSystem } from "./engine/network";
|
||||||
import { RenderSystem } from "./engine/render";
|
import { RenderSystem } from "./engine/render";
|
||||||
import { InputSystem } from "./engine/input";
|
import { InputSystem } from "./engine/input";
|
||||||
import { TrailingPositionSystem } from "./engine/trailing_position";
|
import { TrailingPositionSystem } from "./engine/trailing_position";
|
||||||
import { drainPoints, setDelay } from "laser-pen";
|
import { drainPoints, setDelay, setRoundCap } from "laser-pen";
|
||||||
|
|
||||||
$(async () => {
|
$(async () => {
|
||||||
const client_id = await fetch("/assign", {
|
const client_id = await fetch("/assign", {
|
||||||
|
@ -32,6 +32,7 @@ $(async () => {
|
||||||
const input_system = new InputSystem(publisher, gamecanvas);
|
const input_system = new InputSystem(publisher, gamecanvas);
|
||||||
|
|
||||||
setDelay(500);
|
setDelay(500);
|
||||||
|
setRoundCap(true);
|
||||||
const render_system = new RenderSystem(gamecanvas);
|
const render_system = new RenderSystem(gamecanvas);
|
||||||
|
|
||||||
const trailing_position = new TrailingPositionSystem(drainPoints);
|
const trailing_position = new TrailingPositionSystem(drainPoints);
|
||||||
|
|
Loading…
Reference in New Issue