Skip to content

Commit

Permalink
Merge branch 'master' into systems
Browse files Browse the repository at this point in the history
  • Loading branch information
mflerackers committed Dec 17, 2024
2 parents a91a83e + 784115a commit 5db6753
Show file tree
Hide file tree
Showing 9 changed files with 175 additions and 42 deletions.
12 changes: 5 additions & 7 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,11 @@
- Added `ellipse()` component.
- Circle area is no longer a box.
- Added restitution and friction.
- Objects can switch parent by assigning the parent property or using setParent.
- Added a fake cursor API.

```js
const myCursor = add([
fakeMouse(),
sprite("kat"),
pos(100, 100),
]);
const myCursor = add([fakeMouse(), sprite("kat"), pos(100, 100)]);

myCursor.press(); // trigger onClick events if the mouse is over
myCursor.release();
Expand All @@ -25,7 +23,7 @@
- Added many JSDoc specifiers on many functions (@require, @deprecated, @since,
@group, etc)
- Added `getLayers()` to get the layers list
- Added `getDefaulLayer()` to get the default layer
- Added `getDefaultLayer()` to get the default layer
- Deprecated camera methods `camScale()`, `camPos()` and `camRot()` in favor of
`setCamScale()`, `getCamScale()`, `setCamPos()`, `getCamPos()`, `setCamRot()`
and `getCamRot`.
Expand Down Expand Up @@ -724,7 +722,7 @@ player.onBeforePhysicsResolve((collision) => {
`stay(["gameover", "menu"])`
- (**BREAK**) changed `SpriteComp#flipX` and `SpriteComp#flipY` to properties
instead of functions
- (**BEARK**) `sprite.onAnimStart()` and `sprite.onAnimEnd()` now triggers on
- (**BREAK**) `sprite.onAnimStart()` and `sprite.onAnimEnd()` now triggers on
any animation

```js
Expand Down
56 changes: 56 additions & 0 deletions examples/parenttest.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
kaplay();

loadBean();

const centerBean = add([
pos(center()),
anchor("center"),
sprite("bean"),
area(),
rotate(0),
scale(2),
{
update() {
this.angle += 20 * dt();
},
},
]);

const orbitingBean = centerBean.add([
pos(vec2(100, 0)),
anchor("center"),
sprite("bean"),
area(),
rotate(0),
scale(1),
color(),
{
update() {
this.angle = -this.parent.transform.getRotation();
if (this.isHovering()) {
this.color = RED;
}
else {
this.color = WHITE;
}
},
},
]);

onMousePress(() => {
if (orbitingBean.parent === centerBean /* && orbitingBean.isHovering()*/) {
orbitingBean.setParent(getTreeRoot(), { keep: KeepFlags.All });
}
});

onMouseMove((pos, delta) => {
if (orbitingBean.parent !== centerBean) {
orbitingBean.pos = orbitingBean.pos.add(delta);
}
});

onMouseRelease(() => {
if (orbitingBean.parent !== centerBean) {
orbitingBean.setParent(centerBean, { keep: KeepFlags.All });
}
});
10 changes: 5 additions & 5 deletions src/components/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
export * from './draw';
export * from './level';
export * from './misc';
export * from './physics';
export * from './transform';
export * from "./draw";
export * from "./level";
export * from "./misc";
export * from "./physics";
export * from "./transform";
16 changes: 10 additions & 6 deletions src/components/physics/effectors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ export function surfaceEffector(
speedVariation: opts.speedVariation ?? 0,
forceScale: opts.speedVariation ?? 0.9,
add(this: GameObj<AreaComp | SurfaceEffectorComp>) {
this.onCollideUpdate("body", (obj, col) => {
this.onCollideUpdate((obj, col) => {
if (!obj.has("body")) return;
const dir = col?.normal.normal();
const currentVel = obj.vel.project(dir);
const wantedVel = dir?.scale(this.speed);
Expand Down Expand Up @@ -57,7 +58,8 @@ export function areaEffector(opts: AreaEffectorCompOpt): AreaEffectorComp {
linearDrag: opts.linearDrag ?? 0,
useGlobalAngle: opts.useGlobalAngle ?? true,
add(this: GameObj<AreaComp | AreaEffectorComp>) {
this.onCollideUpdate("body", obj => {
this.onCollideUpdate(obj => {
if (!obj.has("body")) return;
obj.addForce(
this.useGlobalAngle
? this.force
Expand Down Expand Up @@ -97,15 +99,16 @@ export function pointEffector(opts: PointEffectorCompOpt): PointEffectorComp {
linearDrag: opts.linearDrag ?? 0,
// angularDrag: opts.angularDrag ?? 0,
add(this: GameObj<PointEffectorComp | AreaComp | PosComp>) {
this.onCollideUpdate("body", (obj, col) => {
this.onCollideUpdate((obj, col) => {
if (!obj.has("body")) return;
const dir = this.pos.sub(obj.pos);
const length = dir.len();
const distance = length * this.distanceScale / 10;
const forceScale = this.forceMode === "constant"
? 1
: this.forceMode === "inverseLinear"
? 1 / distance
: 1 / distance ** 2;
? 1 / distance
: 1 / distance ** 2;
const force = dir.scale(
this.forceMagnitude * forceScale / length,
);
Expand Down Expand Up @@ -249,7 +252,8 @@ export function buoyancyEffector(
flowMagnitude: opts.flowMagnitude ?? 0,
flowVariation: opts.flowVariation ?? 0,
add(this: GameObj<AreaComp | BuoyancyEffectorComp>) {
this.onCollideUpdate("body", (obj, col) => {
this.onCollideUpdate((obj, col) => {
if (!obj.has("body")) return;
const o = obj as GameObj<BodyComp | AreaComp>;
const shape = o.worldArea();
const polygon: Polygon = shape instanceof Polygon
Expand Down
64 changes: 56 additions & 8 deletions src/game/make.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,18 @@ import {
type Tag,
} from "../types";
import { KEventController, KEventHandler, uid } from "../utils";
import type { Game } from "./game";

export enum KeepFlags {
Pos = 1,
Angle = 2,
Scale = 4,
All = 7,
}

export type SetParentOpt = {
keep: KeepFlags;
};

export function make<T>(comps: CompList<T> = []): GameObj<T> {
const compStates = new Map<string, Comp>();
Expand All @@ -39,6 +51,7 @@ export function make<T>(comps: CompList<T> = []): GameObj<T> {
const treatTagsAsComponents = _k.globalOpt.tagsAsComponents;
let onCurCompCleanup: Function | null = null;
let paused = false;
let _parent: GameObj;

// the game object without the event methods, added later
const obj: Omit<GameObj, keyof typeof evs> = {
Expand All @@ -47,7 +60,42 @@ export function make<T>(comps: CompList<T> = []): GameObj<T> {
hidden: false,
transform: new Mat23(),
children: [],
parent: null,

get parent() {
return _parent!;
},

set parent(p: GameObj) {
if (_parent === p) return;
const index = _parent
? _parent.children.indexOf(this as GameObj)
: -1;
if (index !== -1) {
_parent.children.splice(index, 1);
}
_parent = p;
p.children.push(this as GameObj);
},

setParent(p: GameObj, opt: SetParentOpt) {
if (_parent === p) return;
const oldTransform = _parent.transform;
const newTransform = p.transform;
if ((opt.keep & KeepFlags.Pos) && this.pos !== undefined) {
oldTransform.transformPoint(this.pos, this.pos);
newTransform.inverse.transformPoint(this.pos, this.pos);
}
if ((opt.keep & KeepFlags.Angle) && this.angle !== undefined) {
this.angle += newTransform.getRotation()
- oldTransform.getRotation();
}
if ((opt.keep & KeepFlags.Scale) && this.scale !== undefined) {
this.scale = this.scale.scale(
oldTransform.getScale().invScale(newTransform.getScale()),
);
}
this.parent = p;
},

set paused(p) {
if (p === paused) return;
Expand Down Expand Up @@ -254,15 +302,15 @@ export function make<T>(comps: CompList<T> = []): GameObj<T> {
comp[k]?.();
onCurCompCleanup = null;
}
: comp[<keyof typeof comp>k];
gc.push(this.on(k, <any>func).cancel);
: comp[<keyof typeof comp> k];
gc.push(this.on(k, <any> func).cancel);
}
else {
if (this[k] === undefined) {
// assign comp fields to game obj
Object.defineProperty(this, k, {
get: () => comp[<keyof typeof comp>k],
set: (val) => comp[<keyof typeof comp>k] = val,
get: () => comp[<keyof typeof comp> k],
set: (val) => comp[<keyof typeof comp> k] = val,
configurable: true,
enumerable: true,
});
Expand All @@ -274,9 +322,9 @@ export function make<T>(comps: CompList<T> = []): GameObj<T> {
)?.id;
throw new Error(
`Duplicate component property: "${k}" while adding component "${comp.id}"`
+ (originalCompId
? ` (originally added by "${originalCompId}")`
: ""),
+ (originalCompId
? ` (originally added by "${originalCompId}")`
: ""),
);
}
}
Expand Down
2 changes: 2 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,9 +109,11 @@ export type {
Game,
GameObjEventMap,
GameObjEventNames,
KeepFlags,
LevelOpt,
SceneDef,
SceneName,
SetParentOpt,
TupleWithoutFirst,
} from "./game";
export type {
Expand Down
2 changes: 2 additions & 0 deletions src/kaplay.ts
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,7 @@ import {
go,
initEvents,
initGame,
KeepFlags,
layers,
make,
on,
Expand Down Expand Up @@ -1540,6 +1541,7 @@ const kaplay = <
KEvent,
KEventHandler,
KEventController,
KeepFlags,
cancel: () => EVENT_CANCEL_SYMBOL,
};

Expand Down
36 changes: 21 additions & 15 deletions src/math/math.ts
Original file line number Diff line number Diff line change
Expand Up @@ -125,8 +125,8 @@ export class Vec2 {
return Math.abs(this.x) > Math.abs(this.y)
? this.x < 0 ? Vec2.LEFT : Vec2.RIGHT
: this.y < 0
? Vec2.UP
: Vec2.DOWN;
? Vec2.UP
: Vec2.DOWN;
}

/** Clone the vector */
Expand Down Expand Up @@ -259,6 +259,12 @@ export class Vec2 {
return out;
}

/** Scale by the inverse of another vector. or a single number */
invScale(...args: Vec2Args): Vec2 {
const s = vec2(...args);
return new Vec2(this.x / s.x, this.y / s.y);
}

/** Get distance between another vector */
dist(...args: Vec2Args): number {
const p2 = vec2(...args);
Expand Down Expand Up @@ -1379,7 +1385,7 @@ export class Mat4 {
const r = Math.sqrt(this.m[0] * this.m[0] + this.m[1] * this.m[1]);
return new Vec2(
Math.atan(this.m[0] * this.m[4] + this.m[1] * this.m[5])
/ (r * r),
/ (r * r),
0,
);
}
Expand All @@ -1388,7 +1394,7 @@ export class Mat4 {
return new Vec2(
0,
Math.atan(this.m[0] * this.m[4] + this.m[1] * this.m[5])
/ (s * s),
/ (s * s),
);
}
else {
Expand Down Expand Up @@ -1927,7 +1933,7 @@ export function testPolygonPoint(poly: Polygon, pt: Vec2): boolean {
((p[i].y > pt.y) != (p[j].y > pt.y))
&& (pt.x
< (p[j].x - p[i].x) * (pt.y - p[i].y) / (p[j].y - p[i].y)
+ p[i].x)
+ p[i].x)
) {
c = !c;
}
Expand All @@ -1945,7 +1951,7 @@ export function testEllipsePoint(ellipse: Ellipse, pt: Vec2): boolean {
const vx = pt.x * c + pt.y * s;
const vy = -pt.x * s + pt.y * c;
return vx * vx / (ellipse.radiusX * ellipse.radiusX)
+ vy * vy / (ellipse.radiusY * ellipse.radiusY) < 1;
+ vy * vy / (ellipse.radiusY * ellipse.radiusY) < 1;
}

export function testEllipseCircle(ellipse: Ellipse, circle: Circle): boolean {
Expand Down Expand Up @@ -2882,7 +2888,7 @@ export class Ellipse {
const vx = point.x * c + point.y * s;
const vy = -point.x * s + point.y * c;
return vx * vx / (this.radiusX * this.radiusX)
+ vy * vy / (this.radiusY * this.radiusY) < 1;
+ vy * vy / (this.radiusY * this.radiusY) < 1;
}
raycast(origin: Vec2, direction: Vec2): RaycastResult {
return raycastEllipse(origin, direction, this);
Expand Down Expand Up @@ -3281,21 +3287,21 @@ export function kochanekBartels(
const hx = h(
pt2.x,
0.5 * (1 - tension) * (1 + bias) * (1 + continuity) * (pt2.x - pt1.x)
+ 0.5 * (1 - tension) * (1 - bias) * (1 - continuity)
* (pt3.x - pt2.x),
+ 0.5 * (1 - tension) * (1 - bias) * (1 - continuity)
* (pt3.x - pt2.x),
0.5 * (1 - tension) * (1 + bias) * (1 - continuity) * (pt3.x - pt2.x)
+ 0.5 * (1 - tension) * (1 - bias) * (1 + continuity)
* (pt4.x - pt3.x),
+ 0.5 * (1 - tension) * (1 - bias) * (1 + continuity)
* (pt4.x - pt3.x),
pt3.x,
);
const hy = h(
pt2.y,
0.5 * (1 - tension) * (1 + bias) * (1 + continuity) * (pt2.y - pt1.y)
+ 0.5 * (1 - tension) * (1 - bias) * (1 - continuity)
* (pt3.y - pt2.y),
+ 0.5 * (1 - tension) * (1 - bias) * (1 - continuity)
* (pt3.y - pt2.y),
0.5 * (1 - tension) * (1 + bias) * (1 - continuity) * (pt3.y - pt2.y)
+ 0.5 * (1 - tension) * (1 - bias) * (1 + continuity)
* (pt4.y - pt3.y),
+ 0.5 * (1 - tension) * (1 - bias) * (1 + continuity)
* (pt4.y - pt3.y),
pt3.y,
);
return (t: number) => {
Expand Down
Loading

0 comments on commit 5db6753

Please sign in to comment.