render the spritesheet spec in the render system
continuous-integration/drone/pr Build is failing
Details
continuous-integration/drone/pr Build is failing
Details
This commit is contained in:
parent
f7e7121fce
commit
8ac11eda05
|
@ -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()
|
||||
},
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
),
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
},
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue