Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Replaces the broad phase collision detection, introduces a new renderer and has numerous optimizations #456

Merged
merged 16 commits into from
Oct 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion examples/bench.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ for (let i = 0; i < 5000; i++) {
sprite(i % 2 === 0 ? "bean" : "bag"),
pos(rand(0, width()), rand(0, height())),
anchor("center"),
]);
]).paused = true;
}

onDraw(() => {
Expand Down
127 changes: 67 additions & 60 deletions src/components/draw/particles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,11 @@ class Particle {
angle: number = 0;
angularVelocity: number = 0;
damping: number = 0;
t: number;
t: number = 0;
lt: number | null = null;
gc: boolean;
gc: boolean = true;

constructor() {
this.t = 0;
this.gc = true;
}

get progress() {
Expand All @@ -44,7 +42,7 @@ class Particle {
*/
export type EmitterOpt = {
/*
* Shape of the emitter. If given, particles spwan within this shape.
* Shape of the emitter. If given, particles spawn within this shape.
*/
shape?: ShapeType;
/*
Expand Down Expand Up @@ -140,7 +138,7 @@ export interface ParticlesComp extends Comp {
export function particles(popt: ParticlesOpt, eopt: EmitterOpt): ParticlesComp {
let emitterLifetime = eopt.lifetime;

const particles: Particle[] = [];
const particles: Particle[] = new Array<Particle>(popt.max);
const colors = popt.colors || [Color.WHITE];
const opacities = popt.opacities || [1];
const quads = popt.quads || [new Quad(0, 0, 1, 1)];
Expand All @@ -155,7 +153,12 @@ export function particles(popt: ParticlesOpt, eopt: EmitterOpt): ParticlesComp {
const dampingRange = popt.damping || [0, 0];

const indices: number[] = new Array<number>(popt.max * 6);
const vertices: Vertex[] = new Array<Vertex>(popt.max * 4);
const attributes = {
pos: new Array<number>(popt.max * 4 * 2),
uv: new Array<number>(popt.max * 4 * 2),
color: new Array<number>(popt.max * 4 * 3),
opacity: new Array<number>(popt.max * 4),
};
let count = 0;
let time = 0;

Expand All @@ -167,14 +170,11 @@ export function particles(popt: ParticlesOpt, eopt: EmitterOpt): ParticlesComp {
indices[i * 6 + 4] = i * 4 + 2;
indices[i * 6 + 5] = i * 4 + 3;

for (let j = 0; j < 4; j++) {
vertices[i * 4 + j] = {
pos: new Vec2(0, 0),
uv: new Vec2(0, 0),
color: rgb(255, 255, 255),
opacity: 1,
};
}
attributes.pos.fill(0);
attributes.uv.fill(0);
attributes.color.fill(255);
attributes.opacity.fill(1);

particles[i] = new Particle();
}

Expand Down Expand Up @@ -241,6 +241,7 @@ export function particles(popt: ParticlesOpt, eopt: EmitterOpt): ParticlesComp {
if (emitterLifetime !== undefined && emitterLifetime <= 0) {
return;
}

const DT = dt();
// Update all particles
for (let i = 0; i < particles.length; i++) {
Expand Down Expand Up @@ -287,10 +288,10 @@ export function particles(popt: ParticlesOpt, eopt: EmitterOpt): ParticlesComp {
for (let i = 0; i < particles.length; i++) {
const p = particles[i];
if (p.gc) {
vertices[i * 4].opacity = 0;
vertices[i * 4 + 1].opacity = 0;
vertices[i * 4 + 2].opacity = 0;
vertices[i * 4 + 3].opacity = 0;
attributes.opacity[i * 4] = 0;
attributes.opacity[i * 4 + 1] = 0;
attributes.opacity[i * 4 + 2] = 0;
attributes.opacity[i * 4 + 3] = 0;
continue;
}
const progress = p.progress;
Expand Down Expand Up @@ -327,60 +328,66 @@ export function particles(popt: ParticlesOpt, eopt: EmitterOpt): ParticlesComp {
const quad = quads[quadIndex];
const scaleIndex = Math.floor(progress * scales.length);
const scale = scales[scaleIndex];
// TODO: lerp scale
const angle = deg2rad(p.angle);
const c = Math.cos(angle);
const s = Math.sin(angle);

const hw = popt.texture.width * quad.w
/ 2;
const hh = popt.texture.height * quad.h
/ 2;
const hw = popt.texture.width * quad.w / 2;
const hh = popt.texture.height * quad.h / 2;

let j = i * 4;
// Left top
let v = vertices[j];
v.pos.x = p.pos.x + (-hw) * scale * c - (-hh) * scale * s;
v.pos.y = p.pos.y + (-hw) * scale * s + (-hh) * scale * c;
v.uv.x = quad.x;
v.uv.y = quad.y;
v.color.r = color.r;
v.color.g = color.g;
v.color.b = color.b;
v.opacity = opacity;
attributes.pos[j * 2] = p.pos.x + (-hw) * scale * c
- (-hh) * scale * s;
attributes.pos[j * 2 + 1] = p.pos.y + (-hw) * scale * s
+ (-hh) * scale * c;
attributes.uv[j * 2] = quad.x;
attributes.uv[j * 2 + 1] = quad.y;
attributes.color[j * 3] = color.r;
attributes.color[j * 3 + 1] = color.g;
attributes.color[j * 3 + 2] = color.b;
attributes.opacity[j] = opacity;
// Right top
v = vertices[j + 1];
v.pos.x = p.pos.x + hw * scale * c - (-hh) * scale * s;
v.pos.y = p.pos.y + hw * scale * s + (-hh) * scale * c;
v.uv.x = quad.x + quad.w;
v.uv.y = quad.y;
v.color.r = color.r;
v.color.g = color.g;
v.color.b = color.b;
v.opacity = opacity;
j++;
attributes.pos[j * 2] = p.pos.x + hw * scale * c
- (-hh) * scale * s;
attributes.pos[j * 2 + 1] = p.pos.y + hw * scale * s
+ (-hh) * scale * c;
attributes.uv[j * 2] = quad.x + quad.w;
attributes.uv[j * 2 + 1] = quad.y;
attributes.color[j * 3] = color.r;
attributes.color[j * 3 + 1] = color.g;
attributes.color[j * 3 + 2] = color.b;
attributes.opacity[j] = opacity;
// Right bottom
v = vertices[j + 2];
v.pos.x = p.pos.x + hw * scale * c - hh * scale * s;
v.pos.y = p.pos.y + hw * scale * s + hh * scale * c;
v.uv.x = quad.x + quad.w;
v.uv.y = quad.y + quad.h;
v.color.r = color.r;
v.color.g = color.g;
v.color.b = color.b;
v.opacity = opacity;
j++;
attributes.pos[j * 2] = p.pos.x + hw * scale * c
- hh * scale * s;
attributes.pos[j * 2 + 1] = p.pos.y + hw * scale * s
+ hh * scale * c;
attributes.uv[j * 2] = quad.x + quad.w;
attributes.uv[j * 2 + 1] = quad.y + quad.h;
attributes.color[j * 3] = color.r;
attributes.color[j * 3 + 1] = color.g;
attributes.color[j * 3 + 2] = color.b;
attributes.opacity[j] = opacity;
// Left bottom
v = vertices[j + 3];
v.pos.x = p.pos.x + (-hw) * scale * c - hh * scale * s;
v.pos.y = p.pos.y + (-hw) * scale * s + hh * scale * c;
v.uv.x = quad.x;
v.uv.y = quad.y + quad.h;
v.color.r = color.r;
v.color.g = color.g;
v.color.b = color.b;
v.opacity = opacity;
j++;
attributes.pos[j * 2] = p.pos.x + (-hw) * scale * c
- hh * scale * s;
attributes.pos[j * 2 + 1] = p.pos.y + (-hw) * scale * s
+ hh * scale * c;
attributes.uv[j * 2] = quad.x;
attributes.uv[j * 2 + 1] = quad.y + quad.h;
attributes.color[j * 3] = color.r;
attributes.color[j * 3 + 1] = color.g;
attributes.color[j * 3 + 2] = color.b;
attributes.opacity[j] = opacity;
}

drawRaw(
vertices,
attributes,
indices,
(this as any).fixed,
popt.texture,
Expand Down
6 changes: 3 additions & 3 deletions src/components/physics/area.ts
Original file line number Diff line number Diff line change
Expand Up @@ -539,15 +539,15 @@ export function area(opt: AreaCompOpt = {}): AreaComp {

const transform = this.transform
.clone()
.translate(this.area.offset)
.scale(vec2(this.area.scale ?? 1));
.translateSelfV(this.area.offset)
.scaleSelfV(vec2(this.area.scale ?? 1));

if (localArea instanceof k.Rect) {
const offset = anchorPt(this.anchor || DEF_ANCHOR)
.add(1, 1)
.scale(-0.5)
.scale(localArea.width, localArea.height);
transform.translate(offset);
transform.translateSelfV(offset);
}

return localArea.transform(transform) as Polygon;
Expand Down
8 changes: 3 additions & 5 deletions src/components/physics/body.ts
Original file line number Diff line number Diff line change
Expand Up @@ -236,8 +236,8 @@ export function body(opt: BodyCompOpt = {}): BodyComp {
other.pos = other.pos.add(
col.displacement.scale(-this.mass / tmass),
);
this.transform = calcTransform(this);
other.transform = calcTransform(other);
calcTransform(this, this.transform);
calcTransform(other, other.transform);
}
else {
// if one is static and on is not, resolve the non static one
Expand All @@ -247,9 +247,7 @@ export function body(opt: BodyCompOpt = {}): BodyComp {
col2.source.pos = col2.source.pos.add(
col2.displacement,
);
col2.source.transform = calcTransform(
col2.source,
);
calcTransform(col2.source, col2.source.transform);
}

col.resolved = true;
Expand Down
8 changes: 5 additions & 3 deletions src/components/transform/pos.ts
Original file line number Diff line number Diff line change
Expand Up @@ -115,22 +115,24 @@ export function pos(...args: Vec2Args): PosComp {
}
else {
return this.parent
? this.parent.transform.multVec2(this.pos)
? this.parent.transform.transformPoint(this.pos, vec2())
: this.pos;
}
},

// Transform a local point to a world point
toWorld(this: GameObj<PosComp>, p: Vec2): Vec2 {
return this.parent
? this.parent.transform.multVec2(this.pos.add(p))
? this.parent.transform.transformPoint(this.pos.add(p), vec2())
: this.pos.add(p);
},

// Transform a world point (relative to the root) to a local point (relative to this)
fromWorld(this: GameObj<PosComp>, p: Vec2): Vec2 {
return this.parent
? this.parent.transform.invert().multVec2(p).sub(this.pos)
? this.parent.transform.inverse.transformPoint(p, vec2()).sub(
this.pos,
)
: p.sub(this.pos);
},

Expand Down
8 changes: 4 additions & 4 deletions src/game/camera.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { color, fixed, opacity, rect } from "../components";
import { center, height, width } from "../gfx";
import { game } from "../kaplay";
import { type Color, rgb } from "../math/color";
import { type Mat4, type Vec2, vec2, type Vec2Args } from "../math/math";
import { type Mat23, type Vec2, vec2, type Vec2Args } from "../math/math";
import { destroy } from ".";

export function camPos(...pos: Vec2Args): Vec2 {
Expand Down Expand Up @@ -41,7 +41,7 @@ export function camFlash(
return fade;
}

export function camTransform(): Mat4 {
export function camTransform(): Mat23 {
return game.cam.transform.clone();
}

Expand All @@ -50,9 +50,9 @@ export function shake(intensity: number = 12) {
}

export function toScreen(p: Vec2): Vec2 {
return game.cam.transform.multVec2(p);
return game.cam.transform.transformPoint(p, vec2());
}

export function toWorld(p: Vec2): Vec2 {
return game.cam.transform.invert().multVec2(p);
return game.cam.transform.inverse.transformPoint(p, vec2());
}
4 changes: 2 additions & 2 deletions src/game/game.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { TimerComp } from "../components";
import { Mat4, Vec2 } from "../math/math";
import { Mat23, Vec2 } from "../math/math";
import { type GameObj, type Key, type MouseButton } from "../types";
import { KEventHandler } from "../utils";
import type { GameObjEventMap } from "./events";
Expand Down Expand Up @@ -65,7 +65,7 @@ export const initGame = () => {
scale: new Vec2(1),
angle: 0,
shake: 0,
transform: new Mat4(),
transform: new Mat23(),
},
};

Expand Down
2 changes: 1 addition & 1 deletion src/game/level.ts
Original file line number Diff line number Diff line change
Expand Up @@ -353,7 +353,7 @@ export function addLevel(

obj.tilePos = p;
// Stale, so recalculate
obj.transform = calcTransform(obj);
calcTransform(obj, obj.transform);

if (spatialMap) {
insertIntoSpatialMap(obj);
Expand Down
Loading