Skip to content

Commit bd02921

Browse files
committed
added additional part functionality
1 parent c675e70 commit bd02921

File tree

16 files changed

+852
-529
lines changed

16 files changed

+852
-529
lines changed

Parts/Children/AnimatedSprite.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ export class AnimatedSprite extends Renderer {
3636
this.onAnimationComplete = onAnimationComplete; // Set the callback for animation completion
3737
this.webEngine = webEngine; // Set the web engine flag
3838
this.type = "AnimatedSprite";
39+
this.base = "Renderer";
3940
}
4041
clone(memo = new Map()): this {
4142
if (memo.has(this)) {

Parts/Children/BoxCollider.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ export class BoxCollider extends Collider {
2020
this.realWorldStart = this.start; // Will be updated in act(), onMount()
2121
this.realWorldEnd = this.end; // Will be updated in act(), onMount()
2222
this.type = "BoxCollider";
23+
this.base = "Collider";
2324
}
2425
onMount(parent: Part) {
2526
super.onMount(parent);

Parts/Children/Button.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ export class Button extends Renderer {
4949
this.hoverSound = hoverSound;
5050
this.activeSound = activeSound;
5151
this.type = "Button";
52-
52+
this.base = "Renderer"
5353
this.onclick = (event: MouseEvent, input: any) => {
5454
if (this.onClickHandler) {
5555
this.onClickHandler();

Parts/Children/Collider.ts

Lines changed: 95 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import type { Vector } from "../../engine/bundle";
1+
import { Vector } from "../../Math/Vector";
2+
import type { Camera } from "../Camera";
23
import { Part } from "../Part";
34
import type { Transform } from "./Transform";
45

@@ -8,6 +9,7 @@ export class Collider extends Part {
89
constructor() {
910
super({ name: "Collider" });
1011
this.type = "Collider";
12+
this.base = "Collider";
1113
}
1214

1315
clone(memo = new Map()): this {
@@ -68,4 +70,95 @@ export class Collider extends Part {
6870
this.hoverbug = `${this.colliding ? "🟥" : "🟩"} - ${Array.from(this.collidingWith).map(o => o.name).join(",")} objects`
6971

7072
}
71-
}
73+
74+
isVisible(camera: Camera): boolean {
75+
if (!this.top) {
76+
throw new Error("Collider cannot calculate visibility without a 'top' (Game instance).");
77+
}
78+
79+
// 1. Get camera's view boundaries in world space.
80+
const { offset, scale } = camera.getViewMatrix();
81+
// cameraPos is the world coordinate at the center of the camera's view.
82+
const cameraPos = offset.multiply(-1);
83+
84+
const screenWidth = this.top.width;
85+
const screenHeight = this.top.height;
86+
87+
// Calculate the width and height of the camera's view in world units.
88+
const viewWidth = screenWidth / scale.x;
89+
const viewHeight = screenHeight / scale.y;
90+
91+
// 2. Get collider's AABB in world space.
92+
const vertices = this.vertices;
93+
if (vertices.length === 0) {
94+
return false; // No vertices means it has no shape to be visible.
95+
}
96+
97+
const transform = this.sibling<Transform>("Transform");
98+
if (!transform) {
99+
throw new Error("Can not calculate visibility if transform sibling is not present");
100+
}
101+
102+
const worldVertices = vertices.map(vertex => {
103+
return vertex.add(transform.position)
104+
});
105+
106+
const cameraVertices = [
107+
new Vector(cameraPos.x - viewWidth / 2, cameraPos.y - viewHeight / 2),
108+
new Vector(cameraPos.x + viewWidth / 2, cameraPos.y - viewHeight / 2),
109+
new Vector(cameraPos.x + viewWidth / 2, cameraPos.y + viewHeight / 2),
110+
new Vector(cameraPos.x - viewWidth / 2, cameraPos.y + viewHeight / 2)
111+
]
112+
113+
114+
return this.checkVerticesAgainstVertices(worldVertices, cameraVertices);
115+
}
116+
117+
protected checkVerticesAgainstVertices(vertices1: Vector[], vertices2: Vector[]) {
118+
const axes1 = this.getAxes(vertices1);
119+
const axes2 = this.getAxes(vertices2);
120+
121+
const axes = axes1.concat(axes2);
122+
123+
for(const axis of axes) {
124+
const projection1 = this.project(vertices1, axis);
125+
const projection2 = this.project(vertices2, axis);
126+
127+
if (!this.overlap(projection1, projection2)) {
128+
return false;
129+
}
130+
}
131+
132+
return true;
133+
}
134+
// Helper to get axes (normals) of a polygon's edges
135+
protected getAxes(vertices: Vector[]): Vector[] {
136+
const axes: Vector[] = [];
137+
for (let i = 0; i < vertices.length; i++) {
138+
const p1 = vertices[i];
139+
const p2 = vertices[i === vertices.length - 1 ? 0 : i + 1];
140+
const edge = p2.subtract(p1);
141+
const normal = new Vector(-edge.y, edge.x).normalize(); // Perpendicular vector (normal)
142+
axes.push(normal);
143+
}
144+
return axes;
145+
}
146+
// Helper to project a polygon onto an axis
147+
protected project(vertices: Vector[], axis: Vector): { min: number, max: number } {
148+
let min = axis.dot(vertices[0]);
149+
let max = min;
150+
for (let i = 1; i < vertices.length; i++) {
151+
const p = axis.dot(vertices[i]);
152+
if (p < min) {
153+
min = p;
154+
} else if (p > max) {
155+
max = p;
156+
}
157+
}
158+
return { min, max };
159+
}
160+
// Helper to check if two projections overlap
161+
protected overlap(proj1: { min: number, max: number }, proj2: { min: number, max: number }): boolean {
162+
return proj1.max >= proj2.min && proj2.max >= proj1.min;
163+
}
164+
}

Parts/Children/ColorRender.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ export class ColorRender extends Renderer {
2222
this.color = color;
2323
this.debugEmoji = "🎨";
2424
this.type = "ColorRender";
25+
this.base = "Renderer";
2526
this.vertices = vertices || [];
2627
if (this.vertices.length === 0) {
2728
this.vertices = [

Parts/Children/PolygonCollider.ts

Lines changed: 0 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ import { Part } from "../Part";
33
import { Collider } from "./Collider";
44
import type { Transform } from "./Transform";
55
import { Game } from "../Game";
6-
import { drawBox } from "../../helpers"; // For debug drawing AABB of polygon
76
import { BoxCollider } from "./BoxCollider"; // For collision with BoxCollider
87

98
export class PolygonCollider extends Collider {
@@ -163,36 +162,5 @@ export class PolygonCollider extends Collider {
163162
return true; // No separating axis found, they are colliding
164163
}
165164

166-
// Helper to get axes (normals) of a polygon's edges
167-
private getAxes(vertices: Vector[]): Vector[] {
168-
const axes: Vector[] = [];
169-
for (let i = 0; i < vertices.length; i++) {
170-
const p1 = vertices[i];
171-
const p2 = vertices[i === vertices.length - 1 ? 0 : i + 1];
172-
const edge = p2.subtract(p1);
173-
const normal = new Vector(-edge.y, edge.x).normalize(); // Perpendicular vector (normal)
174-
axes.push(normal);
175-
}
176-
return axes;
177-
}
178165

179-
// Helper to project a polygon onto an axis
180-
private project(vertices: Vector[], axis: Vector): { min: number, max: number } {
181-
let min = axis.dot(vertices[0]);
182-
let max = min;
183-
for (let i = 1; i < vertices.length; i++) {
184-
const p = axis.dot(vertices[i]);
185-
if (p < min) {
186-
min = p;
187-
} else if (p > max) {
188-
max = p;
189-
}
190-
}
191-
return { min, max };
192-
}
193-
194-
// Helper to check if two projections overlap
195-
private overlap(proj1: { min: number, max: number }, proj2: { min: number, max: number }): boolean {
196-
return proj1.max >= proj2.min && proj2.max >= proj1.min;
197-
}
198166
}

Parts/Children/Renderer.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ export class Renderer extends Part {
1414
this.disableAntiAliasing = disableAntiAliasing || false; // Default to false if not provided
1515
this.debugEmoji = "🎨"; // Emoji for debugging Renderer
1616
this.type = "Renderer";
17+
this.base = "Rednerer";
1718
}
1819

1920
face(direction: Vector) {

Parts/Children/SpriteRender.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ export class SpriteRender extends Renderer {
1010
super({ width, height });
1111
this.name = "SpriteRender";
1212
this.type = "SpriteRender";
13+
this.base = "Renderer";
1314
this.ready = false;
1415
this.imageSource = imageSource;
1516
this.debugEmoji = "🖼️"; // Default emoji for debugging the sprite render

Parts/Children/TextRender.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ export class TextRender extends Renderer {
1616
this.color = color || 'black'; // Default color if not specified
1717
this.debugEmoji = "🅰️";
1818
this.type = "TextRender";
19+
this.base = "Renderer";
1920
}
2021
onMount(parent: Part) {
2122
super.onMount(parent);

Parts/Game.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,8 @@ export class Game extends Part {
175175
this._isRunning = true;
176176
this._isPaused = false;
177177
this._lastUpdateTime = performance.now();
178+
this.onStart();
179+
178180
SoundManager.startGame();
179181
this.loop();
180182
}
@@ -194,6 +196,7 @@ export class Game extends Part {
194196
this.currentScene.debugTreeRender(this.canvas.width / 2, 10, { x: 10, y: 40 });
195197
this.context.restore();
196198
this.currentScene.act(delta);
199+
this.currentScene.frameEnd(delta);
197200
this.updateDebugToolTip();
198201
this.context.fillStyle = "red";
199202
this.context.fillRect(this.canvas.width / 2 - 2, this.canvas.height / 2 - 2, 4, 4);
@@ -267,7 +270,6 @@ export class Game extends Part {
267270
this.currentScene = scene;
268271
} else {
269272
console.error('Set unknown scene type- neither string nor Scene instance');
270-
console.log(scene);
271273
let json;
272274
try {
273275
json = JSON.stringify(scene);
@@ -277,7 +279,7 @@ export class Game extends Part {
277279
this.debug(`Trying to set scene to unknown type- neither string nor Scene instance. Got ${typeof scene} - ${json}`);
278280
}
279281
}
280-
warn (...args: any[]) {
282+
warn(...args: any[]) {
281283
if (this.messageHook && typeof this.messageHook === "function") {
282284
this.messageHook("warn", ...args);
283285
return true;
@@ -286,7 +288,7 @@ export class Game extends Part {
286288
return false;
287289
}
288290
}
289-
error (...args: any[]) {
291+
error(...args: any[]) {
290292
if (this.messageHook && typeof this.messageHook === "function") {
291293
this.messageHook("error", ...args);
292294
return true;
@@ -295,7 +297,7 @@ export class Game extends Part {
295297
return false;
296298
}
297299
}
298-
debug (...args: any[]) {
300+
debug(...args: any[]) {
299301
if (this.messageHook && typeof this.messageHook === "function") {
300302
this.messageHook("debug", ...args);
301303
return true;

0 commit comments

Comments
 (0)