From 6a11afd9516ab0c17df2e793b1989125025ed118 Mon Sep 17 00:00:00 2001 From: waynemwashuma <94756970+waynemwashuma@users.noreply.github.com> Date: Thu, 18 Sep 2025 00:20:55 +0300 Subject: [PATCH 1/5] Change `Orientation2D` to type `Rotary` --- src/transform/components/2d/orientation.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/transform/components/2d/orientation.js b/src/transform/components/2d/orientation.js index 77012b7d..12e54544 100644 --- a/src/transform/components/2d/orientation.js +++ b/src/transform/components/2d/orientation.js @@ -1,3 +1,3 @@ -import { Angle } from '../../../math/index.js' +import { Rotary } from '../../../math/index.js' -export class Orientation2D extends Angle{} \ No newline at end of file +export class Orientation2D extends Rotary {} \ No newline at end of file From 8550eec8deec7870ab829dc022c2698e9ae97e50 Mon Sep 17 00:00:00 2001 From: waynemwashuma <94756970+waynemwashuma@users.noreply.github.com> Date: Thu, 18 Sep 2025 00:21:09 +0300 Subject: [PATCH 2/5] Add `Rotary.slerp` --- src/math/core/angles/rotary.js | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/math/core/angles/rotary.js b/src/math/core/angles/rotary.js index 377fbad3..231eb0ed 100644 --- a/src/math/core/angles/rotary.js +++ b/src/math/core/angles/rotary.js @@ -313,6 +313,21 @@ export class Rotary { return TAU - angle } + /** + * @param {Rotary} a + * @param {Rotary} b + * @param {number} t + */ + static slerp(a,b,t, out = new Rotary()){ + const x = (a.cos + b.cos) * t + const y = (a.sin + b.sin) * t + const length = Math.sqrt(x * x + y * y) + + out.cos = x / length + out.sin = y / length + return out + } + /** * @param {Rotary} rot1 * @param {Rotary} rot2 From bb769977012745bcd2ffa98f7d0476a4ed5c2c6d Mon Sep 17 00:00:00 2001 From: waynemwashuma <94756970+waynemwashuma@users.noreply.github.com> Date: Thu, 18 Sep 2025 00:21:15 +0300 Subject: [PATCH 3/5] Update functionality using `Orientation2D` --- demos/demos/transform/2d/lookat.js | 6 +++--- demos/demos/transform/2d/propagate.js | 9 +++++---- src/animation/core/animationeffector.js | 3 ++- src/integrator/systems/euler.js | 5 +++-- src/integrator/systems/verlet.js | 4 ++-- src/movable/prefabs/movable2d.js | 4 ++-- src/movable/prefabs/movable3d.js | 4 ++-- src/physics/systems/physics.js | 3 ++- src/render-core/prefabs/camera2d.js | 4 ++-- src/render-core/prefabs/camera3d.js | 21 ++++++++------------- src/transform/prefabs/transform.js | 2 +- src/transform/systems/remote.js | 2 +- src/transform/systems/transform.js | 2 +- src/tween/plugin.js | 4 ++-- 14 files changed, 36 insertions(+), 37 deletions(-) diff --git a/demos/demos/transform/2d/lookat.js b/demos/demos/transform/2d/lookat.js index e462a3e8..000aecf4 100644 --- a/demos/demos/transform/2d/lookat.js +++ b/demos/demos/transform/2d/lookat.js @@ -95,7 +95,8 @@ function updateLookers(world) { target[0].x, target[0].y ) - + const offset = Rotary.fromAngle(-HALF_PI) + lookers.each(([orientation, transform]) => { const position = new Vector2( transform.x, @@ -105,9 +106,8 @@ function updateLookers(world) { // eslint-disable-next-line no-unused-vars const [_, finalOrientation] = lookAt.decompose() - const angle = Rotary.toAngle(finalOrientation) - orientation.value = angle - HALF_PI + orientation.copy(finalOrientation.multiply(offset)) }) } diff --git a/demos/demos/transform/2d/propagate.js b/demos/demos/transform/2d/propagate.js index 3a6df752..24cd89d4 100644 --- a/demos/demos/transform/2d/propagate.js +++ b/demos/demos/transform/2d/propagate.js @@ -18,7 +18,8 @@ import { without, has, PI, - QUARTER_PI + QUARTER_PI, + Rotary } from 'wima' import { addDefaultCamera2D } from '../../utils.js' @@ -85,7 +86,7 @@ function update(world) { if(!parent || !child || !grandChild) return - parent[0].value += QUARTER_PI * delta - child[0].value += QUARTER_PI * delta - grandChild[0].value += PI * delta + parent[0].multiply(Rotary.fromAngle(QUARTER_PI * delta)) + child[0].multiply(Rotary.fromAngle(QUARTER_PI * delta)) + grandChild[0].multiply(Rotary.fromAngle(PI * delta)) } \ No newline at end of file diff --git a/src/animation/core/animationeffector.js b/src/animation/core/animationeffector.js index bb5e8a40..6e575b3e 100644 --- a/src/animation/core/animationeffector.js +++ b/src/animation/core/animationeffector.js @@ -1,5 +1,6 @@ /** @import { Entity } from '../../ecs/index.js' */ import { World } from '../../ecs/registry.js' +import { Rotary } from '../../math/index.js' import { Position2D, Orientation2D, Scale2D, Position3D, Orientation3D, Scale3D } from '../../transform/index.js' /** @@ -65,7 +66,7 @@ export class Orientation2DAnimationEffector extends AnimationEffector { static apply(world, entity, results) { const component = world.get(entity, this.componentType) - component.value = results[0] + component.copy(Rotary.fromAngle(results[0])) } static elementSize() { return 1 diff --git a/src/integrator/systems/euler.js b/src/integrator/systems/euler.js index d790fa81..d63bae7a 100644 --- a/src/integrator/systems/euler.js +++ b/src/integrator/systems/euler.js @@ -1,5 +1,5 @@ import { Query, World } from '../../ecs/index.js' -import { Quaternion, Vector2, Vector3 } from '../../math/index.js' +import { Quaternion, Rotary, Vector2, Vector3 } from '../../math/index.js' import { Acceleration2D, Acceleration3D, Rotation2D, Rotation3D, Torque2D, Torque3D, Velocity2D, Velocity3D } from '../../movable/index.js' import { Orientation2D, Orientation3D, Position2D, Position3D } from '../../transform/index.js' @@ -57,7 +57,8 @@ export function updateOrientationEuler2D(world) { const dt = 1 / 60 query.each(([orientation, rotation]) => { - orientation.value += rotation.value * dt + const angle = Rotary.fromAngle(rotation.value * dt) + orientation.multiply(angle) }) } diff --git a/src/integrator/systems/verlet.js b/src/integrator/systems/verlet.js index c02ddba4..24572f7d 100644 --- a/src/integrator/systems/verlet.js +++ b/src/integrator/systems/verlet.js @@ -1,5 +1,5 @@ import { Query, World } from '../../ecs/index.js' -import { Vector2 } from '../../math/index.js' +import { Rotary, Vector2 } from '../../math/index.js' import { Acceleration2D, Rotation2D, Torque2D, Velocity2D } from '../../movable/index.js' import { Orientation2D, Position2D } from '../../transform/index.js' @@ -33,7 +33,7 @@ export function updateOrientationVerlet2D(world) { query.each(([orientation, rotation, torque]) => { torque.value *= dt * 0.5 rotation.value += torque.value - orientation.value += rotation.value * dt + torque.value * dt + orientation.multiply(Rotary.fromAngle(rotation.value * dt + torque.value * dt)) rotation.value += torque.value * dt * 0.5 torque.value = 0 }) diff --git a/src/movable/prefabs/movable2d.js b/src/movable/prefabs/movable2d.js index 6eaa4b76..b0e9c9dc 100644 --- a/src/movable/prefabs/movable2d.js +++ b/src/movable/prefabs/movable2d.js @@ -1,4 +1,4 @@ -import { GlobalTransform2D, Orientation2D, Position2D, Scale2D } from '../../transform/index.js' +import { createTransform2D, GlobalTransform2D, Orientation2D, Position2D, Scale2D } from '../../transform/index.js' import { Velocity2D, Rotation2D, Acceleration2D, Torque2D } from '../components/index.js' /** @@ -8,7 +8,7 @@ import { Velocity2D, Rotation2D, Acceleration2D, Torque2D } from '../components/ * @returns {[Position2D, Orientation2D, Scale2D, GlobalTransform2D, Velocity2D, Rotation2D, Acceleration2D, Torque2D]} */ export function createMovable2D(x = 0, y = 0, a = 0) { - return [new Position2D(x, y), new Orientation2D(a), new Scale2D(), new GlobalTransform2D(), new Velocity2D(), new Rotation2D(), new Acceleration2D(), new Torque2D()] + return [...createTransform2D(x, y, a), new Velocity2D(), new Rotation2D(), new Acceleration2D(), new Torque2D()] } /** diff --git a/src/movable/prefabs/movable3d.js b/src/movable/prefabs/movable3d.js index f2b2669e..09a71961 100644 --- a/src/movable/prefabs/movable3d.js +++ b/src/movable/prefabs/movable3d.js @@ -1,11 +1,11 @@ -import { GlobalTransform3D, Orientation3D, Position3D, Scale3D } from '../../transform/index.js' +import { createTransform3D, GlobalTransform3D, Orientation3D, Position3D, Scale3D } from '../../transform/index.js' import { Velocity3D, Rotation3D, Acceleration3D, Torque3D } from '../components/index.js' /** * @returns {[Position3D,Orientation3D, Scale3D,GlobalTransform3D,Velocity3D,Rotation3D,Acceleration3D,Torque3D]} */ export function createMovable3D() { - return [new Position3D(), new Orientation3D(), new Scale3D(), new GlobalTransform3D(), new Velocity3D(), new Rotation3D(), new Acceleration3D(), new Torque3D()] + return [...createTransform3D(), new Velocity3D(), new Rotation3D(), new Acceleration3D(), new Torque3D()] } /** diff --git a/src/physics/systems/physics.js b/src/physics/systems/physics.js index c7dd9ff5..e6b762a3 100644 --- a/src/physics/systems/physics.js +++ b/src/physics/systems/physics.js @@ -4,6 +4,7 @@ import { CollisionManifold, Contacts } from '../../narrowphase/index.js' import { PhysicsSettings } from '../settings.js' import { Collider2D } from '../components/index.js' import { Orientation2D, Position2D, Scale2D } from '../../transform/index.js' +import { Rotary } from '../../math/index.js' /** * @param {World} world @@ -15,7 +16,7 @@ export function updateBodies(world) { Collider2D.update( shape, position, - orientation.value, + Rotary.toAngle(orientation), scale ) }) diff --git a/src/render-core/prefabs/camera2d.js b/src/render-core/prefabs/camera2d.js index d729281d..cb61a1a5 100644 --- a/src/render-core/prefabs/camera2d.js +++ b/src/render-core/prefabs/camera2d.js @@ -1,4 +1,4 @@ -import { GlobalTransform2D, Orientation2D, Position2D, Scale2D } from '../../transform/index.js' +import { createTransform2D, GlobalTransform2D, Orientation2D, Position2D, Scale2D } from '../../transform/index.js' import { Camera, RenderLists2D } from '../components/index.js' /** @@ -10,5 +10,5 @@ import { Camera, RenderLists2D } from '../components/index.js' * @returns {[Position2D,Orientation2D,Scale2D,GlobalTransform2D,Camera,RenderLists2D]} */ export function createCamera2D(x = 0, y = 0, a = 0, sx = 1, sy = 1) { - return [new Position2D(x, y), new Orientation2D(a), new Scale2D(sx, sy), new GlobalTransform2D(), new Camera(), new RenderLists2D()] + return [...createTransform2D(x, y, a, sx, sy), new Camera(), new RenderLists2D()] } \ No newline at end of file diff --git a/src/render-core/prefabs/camera3d.js b/src/render-core/prefabs/camera3d.js index 75e30eee..c847e498 100644 --- a/src/render-core/prefabs/camera3d.js +++ b/src/render-core/prefabs/camera3d.js @@ -1,5 +1,5 @@ import { Quaternion } from '../../math/index.js' -import { Orientation3D, Position3D, Scale3D, GlobalTransform3D } from '../../transform/index.js' +import { Orientation3D, Position3D, Scale3D, GlobalTransform3D, createTransform3D } from '../../transform/index.js' import { Camera, RenderLists3D } from '../components/index.js' import { } from '../plugins/index.js' @@ -16,23 +16,18 @@ import { } from '../plugins/index.js' * @returns {[Position3D,Orientation3D,Scale3D,GlobalTransform3D,Camera,RenderLists3D]} */ export function createCamera3D( - x = 0, - y = 0, + x = 0, + y = 0, z = 0, - ox = 0, - oy = 0, + ox = 0, + oy = 0, oz = 0, - sx = 1, - sy = 1, + sx = 1, + sy = 1, sz = 1 ) { - const quaternion = Quaternion.fromEuler(ox, oy, oz) - return [ - new Position3D(x, y, z), - new Orientation3D().copy(quaternion), - new Scale3D(sx, sy, sz), - new GlobalTransform3D(), + ...createTransform3D(x, y, z, ox, oy, oz, sx, sy, sz), new Camera(), new RenderLists3D() ] diff --git a/src/transform/prefabs/transform.js b/src/transform/prefabs/transform.js index 8642459a..6699e0cf 100644 --- a/src/transform/prefabs/transform.js +++ b/src/transform/prefabs/transform.js @@ -17,7 +17,7 @@ export function createTransform2D( ) { return [ new Position2D(dx, dy), - new Orientation2D(a), + new Orientation2D(Math.cos(a),Math.sin(a)), new Scale2D(sx, sy), new GlobalTransform2D() ] diff --git a/src/transform/systems/remote.js b/src/transform/systems/remote.js index ad921bec..620113a7 100644 --- a/src/transform/systems/remote.js +++ b/src/transform/systems/remote.js @@ -20,7 +20,7 @@ export function transformRemote2D(world) { position.copy(entity[0]).add(offPosition) } if (remote.copyOrientation) { - orientation.value = entity[1].value + Rotary.toAngle(offOrientation) + orientation.copy(Rotary.multiply(entity[1], offOrientation)) } if (remote.copyScale) { scale.copy(entity[2]).multiply(offScale) diff --git a/src/transform/systems/transform.js b/src/transform/systems/transform.js index 1686adbd..df042752 100644 --- a/src/transform/systems/transform.js +++ b/src/transform/systems/transform.js @@ -11,7 +11,7 @@ export function synctransform2D(world) { const query = new Query(world, [Position2D, Orientation2D, Scale2D, GlobalTransform2D]) query.each(([position, orientation, scale, transform]) => { - transform.compose(position, Rotary.fromAngle(orientation.value), scale) + transform.compose(position, orientation, scale) }) } diff --git a/src/tween/plugin.js b/src/tween/plugin.js index e9bb4680..c8cb1e3f 100644 --- a/src/tween/plugin.js +++ b/src/tween/plugin.js @@ -11,7 +11,7 @@ import { TweenRepeat, Tween } from './components/index.js' -import { Vector2, Quaternion, Vector3, Angle } from '../math/index.js' +import { Vector2, Quaternion, Vector3, Angle, Rotary } from '../math/index.js' import { generateTweenFlipSystem, generateTweenRepeatTween, generateTweenTimerSystem, generateTweenUpdateSystem } from './systems/index.js' import { Orientation2D, Orientation3D, Position2D, Position3D, Scale2D, Scale3D } from '../transform/index.js' import { typeidGeneric } from '../reflect/index.js' @@ -36,7 +36,7 @@ export class DefaultTweenPlugin extends Plugin { .registerPlugin(new TweenPlugin({ component: Orientation2D, tween: Orientation2DTween, - interpolation: Angle.lerp + interpolation: Rotary.slerp })) .registerPlugin(new TweenPlugin({ component: Orientation3D, From cfd44ffceaab7d5e171233621185bafad9ef5f0a Mon Sep 17 00:00:00 2001 From: waynemwashuma <94756970+waynemwashuma@users.noreply.github.com> Date: Thu, 18 Sep 2025 00:21:28 +0300 Subject: [PATCH 4/5] Fix `Rotary.multiply` instance method Ensure results are copied to calling rotary --- src/math/core/angles/rotary.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/math/core/angles/rotary.js b/src/math/core/angles/rotary.js index 231eb0ed..b131c086 100644 --- a/src/math/core/angles/rotary.js +++ b/src/math/core/angles/rotary.js @@ -84,7 +84,7 @@ export class Rotary { * @returns {this} */ multiply(rotary) { - Rotary.multiply(rotary, this) + Rotary.multiply(rotary, this, this) return this } From d25a413df9da64a176bc3913b5bb148a95e80e69 Mon Sep 17 00:00:00 2001 From: waynemwashuma <94756970+waynemwashuma@users.noreply.github.com> Date: Sun, 21 Sep 2025 01:17:22 +0300 Subject: [PATCH 5/5] lint files --- src/integrator/systems/euler.js | 1 + src/math/core/angles/rotary.js | 4 +++- src/render-core/prefabs/camera3d.js | 1 - src/transform/prefabs/transform.js | 2 +- src/transform/systems/transform.js | 2 +- src/tween/plugin.js | 2 +- 6 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/integrator/systems/euler.js b/src/integrator/systems/euler.js index d63bae7a..6c4117db 100644 --- a/src/integrator/systems/euler.js +++ b/src/integrator/systems/euler.js @@ -58,6 +58,7 @@ export function updateOrientationEuler2D(world) { query.each(([orientation, rotation]) => { const angle = Rotary.fromAngle(rotation.value * dt) + orientation.multiply(angle) }) } diff --git a/src/math/core/angles/rotary.js b/src/math/core/angles/rotary.js index b131c086..fe6e8a4b 100644 --- a/src/math/core/angles/rotary.js +++ b/src/math/core/angles/rotary.js @@ -317,14 +317,16 @@ export class Rotary { * @param {Rotary} a * @param {Rotary} b * @param {number} t + * @param {Rotary} out */ - static slerp(a,b,t, out = new Rotary()){ + static slerp(a, b, t, out = new Rotary()){ const x = (a.cos + b.cos) * t const y = (a.sin + b.sin) * t const length = Math.sqrt(x * x + y * y) out.cos = x / length out.sin = y / length + return out } diff --git a/src/render-core/prefabs/camera3d.js b/src/render-core/prefabs/camera3d.js index c847e498..efd61965 100644 --- a/src/render-core/prefabs/camera3d.js +++ b/src/render-core/prefabs/camera3d.js @@ -1,4 +1,3 @@ -import { Quaternion } from '../../math/index.js' import { Orientation3D, Position3D, Scale3D, GlobalTransform3D, createTransform3D } from '../../transform/index.js' import { Camera, RenderLists3D } from '../components/index.js' import { } from '../plugins/index.js' diff --git a/src/transform/prefabs/transform.js b/src/transform/prefabs/transform.js index 6699e0cf..43baa1ee 100644 --- a/src/transform/prefabs/transform.js +++ b/src/transform/prefabs/transform.js @@ -17,7 +17,7 @@ export function createTransform2D( ) { return [ new Position2D(dx, dy), - new Orientation2D(Math.cos(a),Math.sin(a)), + new Orientation2D(Math.cos(a), Math.sin(a)), new Scale2D(sx, sy), new GlobalTransform2D() ] diff --git a/src/transform/systems/transform.js b/src/transform/systems/transform.js index df042752..c0163a0b 100644 --- a/src/transform/systems/transform.js +++ b/src/transform/systems/transform.js @@ -1,6 +1,6 @@ import { Entity, has, Query, without, World } from '../../ecs/index.js' import { Children, Parent } from '../../hierarchy/index.js' -import { Affine2, Affine3, Rotary } from '../../math/index.js' +import { Affine2, Affine3 } from '../../math/index.js' import { RelationshipQuery } from '../../relationship/index.js' import { Position2D, Orientation2D, Scale2D, GlobalTransform2D, Position3D, Orientation3D, Scale3D, GlobalTransform3D } from '../components/index.js' diff --git a/src/tween/plugin.js b/src/tween/plugin.js index c8cb1e3f..3004f61b 100644 --- a/src/tween/plugin.js +++ b/src/tween/plugin.js @@ -11,7 +11,7 @@ import { TweenRepeat, Tween } from './components/index.js' -import { Vector2, Quaternion, Vector3, Angle, Rotary } from '../math/index.js' +import { Vector2, Quaternion, Vector3, Rotary } from '../math/index.js' import { generateTweenFlipSystem, generateTweenRepeatTween, generateTweenTimerSystem, generateTweenUpdateSystem } from './systems/index.js' import { Orientation2D, Orientation3D, Position2D, Position3D, Scale2D, Scale3D } from '../transform/index.js' import { typeidGeneric } from '../reflect/index.js'