BrickDisplay system
This commit is contained in:
parent
32927d5623
commit
4a5f0b3757
|
|
@ -1,7 +1,6 @@
|
||||||
import { render } from "preact";
|
|
||||||
import type { ReactElement } from "preact/compat";
|
|
||||||
import { clamp, range } from "@common/utils";
|
import { clamp, range } from "@common/utils";
|
||||||
import clsx from "clsx";
|
import clsx from "clsx";
|
||||||
|
import { render, type ComponentChildren } from "preact";
|
||||||
|
|
||||||
import styles from './assets/brick.module.css';
|
import styles from './assets/brick.module.css';
|
||||||
import "./assets/lcd.font.css";
|
import "./assets/lcd.font.css";
|
||||||
|
|
@ -12,10 +11,16 @@ const FIELD_HEIGHT = 20;
|
||||||
const MINI_FIELD_WIDTH = 4;
|
const MINI_FIELD_WIDTH = 4;
|
||||||
const MINI_FIELD_HEIGHT = 4;
|
const MINI_FIELD_HEIGHT = 4;
|
||||||
|
|
||||||
export interface BrickDisplayImage {
|
export class BrickDisplayImage {
|
||||||
image: boolean[];
|
public image: boolean[];
|
||||||
width: number;
|
public width: number;
|
||||||
height: number;
|
public height: number;
|
||||||
|
|
||||||
|
constructor(image: boolean[] = [], width: number = 0, height: number = 0) {
|
||||||
|
this.image = image;
|
||||||
|
this.width = width;
|
||||||
|
this.height = height;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class BrickDisplay {
|
export class BrickDisplay {
|
||||||
|
|
@ -26,7 +31,7 @@ export class BrickDisplay {
|
||||||
#level: number = 1;
|
#level: number = 1;
|
||||||
public pause: boolean = false;
|
public pause: boolean = false;
|
||||||
public gameOver: boolean = false;
|
public gameOver: boolean = false;
|
||||||
public helpText: string | ReactElement = '';
|
public helpText: ComponentChildren = '';
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
this.update();
|
this.update();
|
||||||
|
|
@ -37,7 +42,7 @@ export class BrickDisplay {
|
||||||
}
|
}
|
||||||
|
|
||||||
set score(value) {
|
set score(value) {
|
||||||
this.#score = Math.max(0, (value | 0) % 1000000000);
|
this.#score = Math.max(0, (value | 0) % 1_000_000_000);
|
||||||
}
|
}
|
||||||
|
|
||||||
get speed() {
|
get speed() {
|
||||||
|
|
@ -243,11 +248,7 @@ export class BrickDisplay {
|
||||||
}
|
}
|
||||||
|
|
||||||
static convertImage(image: HTMLImageElement): BrickDisplayImage {
|
static convertImage(image: HTMLImageElement): BrickDisplayImage {
|
||||||
const result: BrickDisplayImage = {
|
const result = new BrickDisplayImage();
|
||||||
image: [],
|
|
||||||
width: 0,
|
|
||||||
height: 0,
|
|
||||||
}
|
|
||||||
|
|
||||||
const canvas = document.createElement('canvas');
|
const canvas = document.createElement('canvas');
|
||||||
result.width = canvas.width = image.naturalWidth;
|
result.width = canvas.width = image.naturalWidth;
|
||||||
|
|
@ -267,7 +268,7 @@ export class BrickDisplay {
|
||||||
|
|
||||||
static extractSprite(image: BrickDisplayImage, x: number, y: number, w: number, h: number): BrickDisplayImage {
|
static extractSprite(image: BrickDisplayImage, x: number, y: number, w: number, h: number): BrickDisplayImage {
|
||||||
if (w <= 0 || h <= 0 || x >= image.width || y >= image.height) {
|
if (w <= 0 || h <= 0 || x >= image.width || y >= image.height) {
|
||||||
return { image: [], width: 0, height: 0 };
|
return new BrickDisplayImage();
|
||||||
}
|
}
|
||||||
|
|
||||||
x = clamp(x | 0, 0, image.width);
|
x = clamp(x | 0, 0, image.width);
|
||||||
|
|
@ -276,11 +277,7 @@ export class BrickDisplay {
|
||||||
w = clamp(w | 0, 1, image.width - x);
|
w = clamp(w | 0, 1, image.width - x);
|
||||||
h = clamp(h | 0, 1, image.height - y);
|
h = clamp(h | 0, 1, image.height - y);
|
||||||
|
|
||||||
const result: BrickDisplayImage = {
|
const result = new BrickDisplayImage(new Array(w * h), w, h);
|
||||||
image: new Array(w * h),
|
|
||||||
width: w,
|
|
||||||
height: h,
|
|
||||||
}
|
|
||||||
|
|
||||||
for (let j = 0; j < h; j++) {
|
for (let j = 0; j < h; j++) {
|
||||||
for (let i = 0; i < w; i++) {
|
for (let i = 0; i < w; i++) {
|
||||||
|
|
@ -320,11 +317,11 @@ export class BrickDisplay {
|
||||||
static rotateSprite(image: BrickDisplayImage, angle: 0 | 90 | 180 | 270): BrickDisplayImage {
|
static rotateSprite(image: BrickDisplayImage, angle: 0 | 90 | 180 | 270): BrickDisplayImage {
|
||||||
if (angle === 0) return this.copySprite(image);
|
if (angle === 0) return this.copySprite(image);
|
||||||
|
|
||||||
const newImage: BrickDisplayImage = {
|
const newImage = new BrickDisplayImage(
|
||||||
image: new Array(image.width * image.height),
|
new Array(image.width * image.height),
|
||||||
width: angle === 180 ? image.width : image.height,
|
angle === 180 ? image.width : image.height,
|
||||||
height: angle === 180 ? image.height : image.width,
|
angle === 180 ? image.height : image.width,
|
||||||
}
|
);
|
||||||
|
|
||||||
for (let j = 0; j < image.height; j++) {
|
for (let j = 0; j < image.height; j++) {
|
||||||
for (let i = 0; i < image.width; i++) {
|
for (let i = 0; i < image.width; i++) {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
import { Component } from "@common/rpg/core/world";
|
||||||
|
import { component } from "@common/rpg/utils/decorators";
|
||||||
|
|
||||||
|
@component
|
||||||
|
export class BrickSprite extends Component<{ xor: boolean, miniDisplay: boolean }> {
|
||||||
|
constructor(miniDisplay: boolean, xor: boolean) {
|
||||||
|
super({ xor, miniDisplay });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
import { BrickDisplay, BrickDisplayImage } from "@common/display/brick";
|
||||||
|
import { Position } from "@common/rpg/components/position";
|
||||||
|
import { BrickSprite } from "@common/rpg/components/render/brick";
|
||||||
|
import { Hidden, Sprite } from "@common/rpg/components/sprite";
|
||||||
|
import { System, World } from "@common/rpg/core/world";
|
||||||
|
import { Resources } from "@common/rpg/utils/resources";
|
||||||
|
|
||||||
|
export class BrickDisplaySystem extends System {
|
||||||
|
public readonly display: BrickDisplay;
|
||||||
|
|
||||||
|
constructor(display?: BrickDisplay) {
|
||||||
|
super();
|
||||||
|
this.display = display ?? new BrickDisplay();
|
||||||
|
}
|
||||||
|
|
||||||
|
override update(world: World) {
|
||||||
|
const sprites = Array.from(world.query(Sprite, Position)).sort((a, b) => a[2].state.z - b[2].state.z);
|
||||||
|
for (const [e, sprite, pos] of sprites) {
|
||||||
|
if (e.has(Hidden)) continue;
|
||||||
|
|
||||||
|
const { xor = false, miniDisplay = false } = e.get(BrickSprite)?.state ?? {};
|
||||||
|
|
||||||
|
const { x, y } = pos.state;
|
||||||
|
|
||||||
|
const data = Resources.get(BrickDisplayImage, sprite.image);
|
||||||
|
if (!data) {
|
||||||
|
throw new Error('No image data found for sprite');
|
||||||
|
}
|
||||||
|
this.display.drawImage(data, x, y, miniDisplay, xor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue