aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorElizabeth Hunt <elizabeth.hunt@simponic.xyz>2024-09-15 17:38:02 -0700
committerElizabeth Hunt <elizabeth.hunt@simponic.xyz>2024-09-15 17:38:02 -0700
commit8ac11eda05e7159a7f762d3396cf7bb8ee51534b (patch)
tree6e1214ceebd209f3829aac73b2dd330452079d84
parentf7e7121fce7bd3f7fdabe836955e43b3d194c1c6 (diff)
downloadkennel.hatecomputers.club-8ac11eda05e7159a7f762d3396cf7bb8ee51534b.tar.gz
kennel.hatecomputers.club-8ac11eda05e7159a7f762d3396cf7bb8ee51534b.zip
render the spritesheet spec in the render systemHEADmain
-rw-r--r--kennel/engine/components/sprite_sheet.py17
-rw-r--r--kennel/engine/entities/cat.py35
-rw-r--r--static/src/engine/component.ts2
-rw-r--r--static/src/engine/debounce_publisher.ts2
-rw-r--r--static/src/engine/render.ts84
-rw-r--r--static/src/engine/trailing_position.ts20
6 files changed, 136 insertions, 24 deletions
diff --git a/kennel/engine/components/sprite_sheet.py b/kennel/engine/components/sprite_sheet.py
index 5730085..3a01f5b 100644
--- a/kennel/engine/components/sprite_sheet.py
+++ b/kennel/engine/components/sprite_sheet.py
@@ -18,6 +18,19 @@ class SpriteSpec:
self.end_x = end_x
self.end_y = end_y
+ def to_dict(self) -> dict:
+ return {
+ "ms_per_frame": self.ms_per_frame,
+ "top_x": self.top_x,
+ "top_y": self.top_y,
+ "end_x": self.end_x,
+ "end_y": self.end_y,
+ "frames": self.frames,
+ }
+
+ def __repr__(self) -> str:
+ return f"SpriteSpec(ms_per_frame={self.ms_per_frame}, top_x={self.top_x}, top_y={self.top_y}, end_x={self.end_x}, end_y={self.end_y}, frames={self.frames})"
+
class SpriteSheet(Component):
def __init__(
@@ -44,5 +57,7 @@ class SpriteSheet(Component):
"current_frame": self.current_frame,
"last_update": self.last_update,
"current_state": self.initial_state,
- "state_to_spritespec": self.state_to_spritespec,
+ "state_to_spritespec": {
+ k: v.to_dict() for k, v in self.state_to_spritespec.items()
+ },
}
diff --git a/kennel/engine/entities/cat.py b/kennel/engine/entities/cat.py
index b5a8c6c..c0acfd8 100644
--- a/kennel/engine/entities/cat.py
+++ b/kennel/engine/entities/cat.py
@@ -4,7 +4,7 @@ from enum import Enum
from .entity import Entity, EntityType
-class CatState(Enum):
+class CatState(str, Enum):
IDLE = "IDLE"
FROLICKING = "FROLICKING"
EEPY = "EEPY"
@@ -13,20 +13,47 @@ class CatState(Enum):
CHASING_CAT = "CHASING_CAT"
SCRATCHING = "SCRATCHING"
ITCHY = "ITCHY"
+ MAKING_BISCUITS = "MAKING_BISCUITS"
+
+
+class CatSpriteState(str, Enum):
+ ALERT = "ALERT"
+ MAKING_BISCUITS = "MAKING_BISCUITS"
class Cat(Entity):
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),
+ Position(50, 50),
+ SpriteSheet(
+ spritesheet_source, state_to_spritespec, CatSpriteState.MAKING_BISCUITS
+ ),
]
super().__init__(EntityType.CAT, id, components)
def get_state_to_spritespec(self):
- return {CatState.ALERT: SpriteSpec(100, 0, 0, 200, 40, 5)}
+ creature_width = 32
+ creature_height = 32
+ return {
+ CatSpriteState.ALERT: SpriteSpec(
+ 100,
+ creature_width * 7,
+ creature_height * 3,
+ creature_width * 8,
+ creature_height * 4,
+ 1,
+ ),
+ CatSpriteState.MAKING_BISCUITS: SpriteSpec(
+ 300,
+ 0,
+ 0,
+ creature_width,
+ creature_height * 2,
+ 2,
+ ),
+ }
#
diff --git a/static/src/engine/component.ts b/static/src/engine/component.ts
index a16215b..eb6fdd6 100644
--- a/static/src/engine/component.ts
+++ b/static/src/engine/component.ts
@@ -36,7 +36,7 @@ export interface SpriteSpec {
export interface SpriteSheetComponent extends Component {
name: ComponentType.SPRITESHEET;
source: string;
- sheet: HTMLImageElement;
+ sheet?: HTMLImageElement;
current_frame: number;
last_update: number;
diff --git a/static/src/engine/debounce_publisher.ts b/static/src/engine/debounce_publisher.ts
index bc5e95f..8ee4bb0 100644
--- a/static/src/engine/debounce_publisher.ts
+++ b/static/src/engine/debounce_publisher.ts
@@ -5,7 +5,7 @@ export class DebouncePublisher<T> {
constructor(
private readonly publisher: (data: T) => void | Promise<void>,
- private readonly debounce_ms = 150,
+ private readonly debounce_ms = 100,
) {}
public start() {
diff --git a/static/src/engine/render.ts b/static/src/engine/render.ts
index 8f0343a..4ff1ec0 100644
--- a/static/src/engine/render.ts
+++ b/static/src/engine/render.ts
@@ -2,6 +2,8 @@ import {
ComponentType,
PositionComponent,
TrailingPositionComponent,
+ SpriteSheetComponent,
+ SpriteSpec,
} from "./component";
import { Game } from "./game";
import { System, SystemType } from "./system";
@@ -17,7 +19,7 @@ export class RenderSystem extends System {
this.canvas.height = height;
}
- public update(_dt: number, game: Game) {
+ public update(dt: number, game: Game) {
const ctx = this.canvas.getContext("2d");
if (ctx === null) return;
ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
@@ -32,15 +34,87 @@ export class RenderSystem extends System {
return;
}
- if (ComponentType.POSITION in entity.components) {
+ if (
+ ComponentType.POSITION in entity.components &&
+ ComponentType.SPRITESHEET in entity.components
+ ) {
const position = entity.components[
ComponentType.POSITION
] as PositionComponent;
- ctx.beginPath();
- ctx.arc(position.x, position.y, 50, 0, 2 * Math.PI);
- ctx.stroke();
+ const spritesheet = entity.components[
+ ComponentType.SPRITESHEET
+ ] as SpriteSheetComponent;
+
+ if (typeof spritesheet.sheet === "undefined") {
+ const img = new Image();
+ img.src = spritesheet.source;
+ spritesheet.sheet = img;
+ }
+ const spritespec =
+ spritesheet.state_to_spritespec[spritesheet.current_state];
+
+ this.blit_sprite(ctx, spritesheet, position);
+
+ spritesheet.last_update += dt;
+ if (spritesheet.last_update > spritespec.ms_per_frame) {
+ spritesheet.current_frame++;
+ spritesheet.current_frame %= spritespec.frames;
+ spritesheet.last_update = 0;
+ }
+
return;
}
});
}
+
+ private blit_sprite(
+ ctx: CanvasRenderingContext2D,
+ spritesheet: SpriteSheetComponent,
+ position: { x: number; y: number },
+ ) {
+ ctx.save();
+ ctx.translate(position.x, position.y);
+ ctx.translate(-position.x, -position.y);
+
+ if (typeof spritesheet.sheet === "undefined") return;
+
+ const spritespec =
+ spritesheet.state_to_spritespec[spritesheet.current_state];
+
+ ctx.drawImage(
+ spritesheet.sheet,
+ ...this.get_sprite_args(spritesheet.current_frame, spritespec),
+ ...this.get_draw_args(spritespec, position),
+ );
+
+ ctx.restore();
+ }
+
+ private get_sprite_args(
+ current_frame: number,
+ sprite_spec: SpriteSpec,
+ ): [sx: number, sy: number, sw: number, sh: number] {
+ const [width, height] = this.get_dimensions(sprite_spec);
+ return [
+ sprite_spec.top_x,
+ sprite_spec.top_y + current_frame * height,
+ width,
+ height,
+ ];
+ }
+
+ private get_draw_args(
+ sprite_spec: SpriteSpec,
+ position: { x: number; y: number },
+ ): [dx: number, dy: number, dw: number, dh: number] {
+ const [width, height] = this.get_dimensions(sprite_spec);
+ return [position.x - width / 2, position.y - height / 2, width, height];
+ }
+
+ private get_dimensions(sprite_spec: SpriteSpec): [number, number] {
+ return [
+ sprite_spec.end_x - sprite_spec.top_x,
+ (sprite_spec.end_y - sprite_spec.top_y) / sprite_spec.frames,
+ ];
+ }
}
diff --git a/static/src/engine/trailing_position.ts b/static/src/engine/trailing_position.ts
index 1ea22d3..5b41682 100644
--- a/static/src/engine/trailing_position.ts
+++ b/static/src/engine/trailing_position.ts
@@ -2,19 +2,15 @@ import { ComponentType, TrailingPositionComponent } from "./component";
import { Game } from "./game";
import { System, SystemType } from "./system";
+interface Point {
+ x: number;
+ y: number;
+ time: number;
+}
+
export class TrailingPositionSystem extends System {
constructor(
- private readonly point_filter: (
- trail_point: {
- x: number;
- y: number;
- time: number;
- }[],
- ) => {
- x: number;
- y: number;
- time: number;
- }[],
+ private readonly point_filter: (trail_point: Array<Point>) => Array<Point>
) {
super(SystemType.TRAILING_POSITION);
}
@@ -27,7 +23,7 @@ export class TrailingPositionSystem extends System {
ComponentType.TRAILING_POSITION
] as TrailingPositionComponent;
trailing_position.trails = this.point_filter(trailing_position.trails);
- },
+ }
);
}
}