UNPKG

@woosh/meep-engine

Version:

Pure JavaScript game engine. Fully featured and production ready.

205 lines (147 loc) 4.71 kB
import { assert } from "../../../../core/assert.js"; import Quaternion from "../../../../core/geom/Quaternion.js"; import Vector3 from "../../../../core/geom/Vector3.js"; import { lerp } from "../../../../core/math/lerp.js"; import { Transform } from "../../../ecs/transform/Transform.js"; import { BehaviorStatus } from "../BehaviorStatus.js"; import { EntityBehavior } from "./EntityBehavior.js"; export class OrbitingBehavior extends EntityBehavior { /** * Radians per second. * Can be negative for counter-clockwise rotation. * @type {number} */ rate = Math.PI; /** * * @type {number} */ radius = 1; /** * Initial offset in radians * @type {number} */ phase = 0; /** * * @type {number} */ angle = 0; /** * Offset from the origin * @type {Vector3} */ offset = new Vector3(); /** * * @type {number} */ parent = -1; /** * * @type {number} */ easing = 1; orientation = new Quaternion(); /** * * @type {Vector3} */ center = new Vector3(); /** * * @type {Quaternion} */ lookRotation = new Quaternion(); /** * * @param {Vector3} [center] * @param {number} [radius] * @param {number} [rate] * @returns {OrbitingBehavior} */ static from({ center = Vector3.zero, radius = 1, rate = 1 }) { assert.defined(center, 'center') assert.isNumber(radius, 'radius') assert.isNumber(rate, 'rate') const r = new OrbitingBehavior(); r.offset.copy(center); r.radius = radius; r.rate = rate; return r; } initialize(context) { super.initialize(context); const easing = this.easing; this.easing = 1; this.tick(0); this.easing = easing; } tick(timeDelta) { const angleDelta = timeDelta * this.rate; this.angle += angleDelta; const entity = this.context.entity; const ecd = this.context.ecd; /** * * @type {Transform} */ const transform = ecd.getComponent(entity, Transform); if (transform === undefined) { return BehaviorStatus.Failed; } const a = this.angle + this.phase; const cos = Math.cos(a); const sin = Math.sin(a); let center_x = this.offset.x; let center_y = this.offset.y; let center_z = this.offset.z; const r = this.radius; let x = r * cos; let y = 0; let z = r * sin; const q = this.orientation; //transform point into quaternion const qx = q.x, qy = q.y, qz = q.z, qw = q.w; // calculate quat * vector var ix = qw * x + qy * z; var iy = qz * x - qx * z; var iz = qw * z - qy * x; var iw = -qx * x - qz * z; // calculate result * inverse quat x = ix * qw + iw * -qx + iy * -qz - iz * -qy; y = iy * qw + iw * -qy + iz * -qx - ix * -qz; z = iz * qw + iw * -qz + ix * -qy - iy * -qx; if (this.parent !== -1 && ecd.entityExists(this.parent)) { const parentTransform = ecd.getComponent(this.parent, Transform); center_x += parentTransform.position.x; center_y += parentTransform.position.y; center_z += parentTransform.position.z; const parentScape = parentTransform.scale; x *= parentScape.x; y *= parentScape.y; z *= parentScape.z; } center_x = lerp(this.center.x, center_x, this.easing); center_y = lerp(this.center.y, center_y, this.easing); center_z = lerp(this.center.z, center_z, this.easing); this.center.set(center_x, center_y, center_z); const _x = center_x + x; const _y = center_y + y; const _z = center_z + z; const p = transform.position; const old_x = p.x; const old_y = p.y; const old_z = p.z; if (old_x !== _x || old_y !== _y || old_z !== _z) { transform.rotation._lookRotation(_x - old_x, _y - old_y, _z - old_z, 0, 1, 0); transform.rotation.multiplyQuaternions(transform.rotation, this.lookRotation); } p.set(_x, _y, _z); return BehaviorStatus.Running; } }