Skip to content

Commit

Permalink
chore: update
Browse files Browse the repository at this point in the history
  • Loading branch information
ufocoder committed May 14, 2024
1 parent f16b736 commit 71b16de
Show file tree
Hide file tree
Showing 18 changed files with 262 additions and 124 deletions.
4 changes: 2 additions & 2 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@
}
#app {
position: absolute;
width: 640px;
height: 480px;
width: 800px;
height: 600px;
}
</style>
</head>
Expand Down
14 changes: 12 additions & 2 deletions src/global.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,12 +52,22 @@ interface SoundPreset {
volume?: number;
}

interface Texture {
interface AnimationSpritePreset {
id: string;
imageData: ImageData;
frames: string[]
}

interface TextureBitmap {
width: number;
height: number;
colors: Color[][];
}

interface Color {
r: number;
g: number;
b: number;
a: number;
}

type Sprite = Texture
27 changes: 12 additions & 15 deletions src/levels/base.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,23 @@
import { Color } from "src/managers/TextureManager";

const random = (from: number, to: number) => {
return from + Math.random() * (to - from);
};

const generateEnemies = (limit: number) => {
return new Array(limit).fill(0).map(() => ({
x: random(2, 4),
y: random(3, 8),
angle: 45,
health: 100,
sprite: "soldier",
radius: 0.4,
}))
}
x: random(2, 4),
y: random(3, 8),
angle: 45,
health: 100,
sprite: "zombie",
radius: 0.4,
}));
};

const level: Level = {
world: {
colors: {
top: new Color(0, 0, 0, 255),
bottom: new Color(84, 98, 92, 255),
top: { r: 0, g: 0, b: 0, a: 255 },
bottom: { r: 84, g: 98, b: 92, a: 255 },
},
},
map: [
Expand All @@ -45,8 +43,8 @@ const level: Level = {
angle: 0,
health: 100,
},
enemies: generateEnemies(10)
/*
enemies: generateEnemies(10),
/*
[
{
x: 3,
Expand All @@ -57,7 +55,6 @@ const level: Level = {
radius: 0.4,
},
]*/
,
exit: {
x: 4,
y: 5,
Expand Down
2 changes: 2 additions & 0 deletions src/lib/ecs/components/AIComponent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import { Component } from "src/lib/ecs/Component";

export default class AIComponent implements Component {
distance: number;
lastAttackTime: number = 0;
damagePerSecond: number = 5;

constructor(distance: number) {
this.distance = distance;
Expand Down
11 changes: 0 additions & 11 deletions src/lib/ecs/components/AnimatedSpriteComponent.ts

This file was deleted.

36 changes: 36 additions & 0 deletions src/lib/ecs/components/AnimationComponent.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { Component } from "src/lib/ecs/Component";

export default class AnimatedSpriteComponent implements Component {

states: Record<string, TextureBitmap[]> = {};
currentState: string;
currentFrame: number;
sprite: TextureBitmap;
animationSpeed: number = 0.2;
timeSinceLastFrame: number = 0;

constructor(initialState: string, states: Record<string, TextureBitmap[]>) {
this.states = states;
this.currentFrame = 0;
this.currentState = initialState;
this.sprite = states[initialState][0];
}

// @TODO: improve
update(dt: number) {
const frames = this.states[this.currentState];
this.timeSinceLastFrame += dt;

if (this.timeSinceLastFrame > this.animationSpeed) {
this.currentFrame = (this.currentFrame + 1) % frames.length;
this.sprite = frames[this.currentFrame];
this.timeSinceLastFrame = 0;
}
}

switchState(stateName: string) {
if (stateName in this.states) {
this.currentState = stateName;
}
}
}
39 changes: 29 additions & 10 deletions src/lib/ecs/systems/AISystem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,17 @@ import PositionComponent from "src/lib/ecs/components/PositionComponent";
import QuerySystem from "../lib/QuerySystem";
import AIComponent from "../components/AIComponent";
import CameraComponent from "../components/CameraComponent";
import CircleComponent from "../components/CircleComponent";
import HealthComponent from "../components/HealthComponent";
import AnimatedSpriteComponent from "../components/AnimationComponent";

export default class AISystem extends System {
requiredComponents = [AIComponent, PositionComponent];
requiredComponents = [AIComponent, CircleComponent, PositionComponent];
camera: Entity;

constructor(querySystem: QuerySystem) {
super(querySystem);
const [camera] = this.querySystem.query([CameraComponent]);
const [camera] = this.querySystem.query([HealthComponent, CircleComponent, CameraComponent]);

this.camera = camera;
}
Expand All @@ -20,26 +23,42 @@ export default class AISystem extends System {

update(dt: number, entities: Entity[]) {
const cameraPosition = this.camera.getComponent(PositionComponent);
const cameraCircle = this.camera.getComponent(CircleComponent);
const cameraHealth = this.camera.getComponent(HealthComponent);

entities.forEach((entity: Entity) => {
const entityAI = entity.getComponent(AIComponent);
const entityPosition = entity.getComponent(PositionComponent);
const entityCircle = entity.getComponent(CircleComponent);
const entityAnimation = entity.getComponent(AnimatedSpriteComponent);

const dx = cameraPosition.x - entityPosition.x;
const dy = cameraPosition.y - entityPosition.y;

const distance = Math.sqrt(dx**2 + dy**2);
const distance = Math.sqrt(dx**2 + dy**2) - cameraCircle.radius - entityCircle.radius;

// @TODO: move to move system
if (entityAI.distance > distance) {
this.moveAI(dt, dx, dy, entity);
entityAnimation.switchState('walk');
entityPosition.x += dx * dt
entityPosition.y += dy * dt
} else {
entityAnimation.switchState('idle');
}

if (distance < 0) {
entityAI.lastAttackTime += dt;
} else {
entityAI.lastAttackTime = 0;
}
});
}

moveAI(dt:number, dx: number, dy: number, entity: Entity) {
entity.getComponent(PositionComponent).x += dx * dt
entity.getComponent(PositionComponent).y += dy * dt
if (entityAI.lastAttackTime >= 1) {
cameraHealth.current -= entityAI.damagePerSecond;
entityAI.lastAttackTime = 0;
}
});
}

destroy(){}
}

}
18 changes: 18 additions & 0 deletions src/lib/ecs/systems/AnimationSystem.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import Entity from "src/lib/ecs/Entity";
import System from "src/lib/ecs/System";
import AnimatedSpriteComponent from "../components/AnimationComponent";


export default class AnimationSystem extends System {
requiredComponents = [AnimatedSpriteComponent];

start(): void {}

update(dt: number, entities: Entity[]) {
entities.forEach((entity) => {
entity.getComponent(AnimatedSpriteComponent).update(dt);
});
}

destroy(): void {}
}
3 changes: 2 additions & 1 deletion src/lib/ecs/systems/MinimapSystem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export default class MinimapSystem extends System {
this.canvas = new Canvas({
height: rows * this.scale,
width: cols * this.scale,
});
});
}

start() {
Expand All @@ -37,6 +37,7 @@ export default class MinimapSystem extends System {

update(_: number, entities: Entity[]) {
this.canvas.clear();
this.canvas.drawBackground('green');

entities.forEach((entity) => {
const { x, y } = entity.getComponent(PositionComponent);
Expand Down
4 changes: 2 additions & 2 deletions src/lib/ecs/systems/MoveSystem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,11 +101,11 @@ export default class MoveSystem extends System {
const newX = positionComponent.x + k * playerCos * moveComponent.moveSpeed * dt;
const newY = positionComponent.y + k * playerSin * moveComponent.moveSpeed * dt;

if (newX < 0 || newX > this.cols) {
if (newX <= 0 || newX > this.cols) {
return
}

if (newY < 0 || newY > this.rows) {
if (newY <= 0 || newY > this.rows) {
return
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,9 @@ import QuerySystem from "../lib/QuerySystem";
import SpriteComponent from "../components/SpriteComponent";
import TextureManager from "src/managers/TextureManager";
import PolarMap, { PolarPosition } from "../lib/PolarMap";
import AnimatedSpriteComponent from "../components/AnimationComponent";

export default class CameraSystem extends System {
export default class RenderSystem extends System {
requiredComponents = [CameraComponent, PositionComponent];

protected walls: PositionMap<Entity>;
Expand Down Expand Up @@ -107,12 +108,12 @@ export default class CameraSystem extends System {
rayX += incrementRayX;
rayY += incrementRayY;

if (rayX < 0 || rayX > this.walls.cols) {
if (rayX < 0 || rayX > this.walls.rows) {
isPropogating = false;
continue;
}

if (rayY < 0 || rayY > this.walls.rows) {
if (rayY < 0 || rayY > this.walls.cols) {
isPropogating = false;
continue;
}
Expand Down Expand Up @@ -205,24 +206,27 @@ export default class CameraSystem extends System {
}

_drawSpriteLine(screenX: number, rayAngle: number, polarEntity: PolarPosition){
const animateComponent = polarEntity.entity.getComponent(AnimatedSpriteComponent).sprite;
const spriteComponent = polarEntity.entity.getComponent(SpriteComponent).sprite;
const projectionHeight = Math.floor(this.height / 2 / polarEntity.distance);

const sprite = animateComponent || spriteComponent;

const a1 = normalizeAngle(rayAngle - polarEntity.angleFrom);
const a2 = normalizeAngle(polarEntity.angleTo - polarEntity.angleFrom);
const xTexture = Math.floor(a1 / a2 * spriteComponent.width)
const xTexture = Math.floor(a1 / a2 * sprite.width)

const yIncrementer = (projectionHeight * 2) / spriteComponent.height;
const yIncrementer = (projectionHeight * 2) / sprite.height;

let y = this.height / 2 - projectionHeight;

for (let i = 0; i < spriteComponent.height; i++) {
for (let i = 0; i < sprite.height; i++) {
if (y > -yIncrementer && y < this.height) {
this.canvas.drawVerticalLine({
x: screenX,
y1: y,
y2: Math.floor(y + yIncrementer),
color: spriteComponent.colors[i][xTexture],
color: sprite.colors[i][xTexture],
});
}
y += yIncrementer;
Expand Down
55 changes: 55 additions & 0 deletions src/lib/image.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
export async function extractTextureBitmap(url: string) {
const image = await loadImage(url);
const imageData = await extractImageData(image);
const colors = await extractColors(image.height, image.width, imageData.data);

return {
height: image.height,
width: image.width,
colors,
} as TextureBitmap;
}

async function loadImage(url: string): Promise<HTMLImageElement> {
return new Promise((resolve, reject) => {
const element = document.createElement("img");

element.src = url;
element.onerror = () => reject();
element.onload = () => resolve(element);
});
}

async function extractImageData(image: HTMLImageElement) {
const canvas = document.createElement("canvas");
canvas.width = image.width;
canvas.height = image.height;

const context = canvas.getContext("2d")!;

context.drawImage(image, 0, 0, image.width, image.height);

return context.getImageData(0, 0, image.width, image.height);
}

async function extractColors(
height: number,
width: number,
imageData: Uint8ClampedArray
) {
const colors: Color[][] = [];
for (let y = 0; y < height; y++) {
const row: Color[] = [];
for (let x = 0; x < width; x++) {
const i = x * 4 + y * width * 4;
row.push({
r: imageData[i],
g: imageData[i + 1],
b: imageData[i + 2],
a: imageData[i + 3],
});
}
colors.push(row);
}
return colors;
}
Loading

0 comments on commit 71b16de

Please sign in to comment.