@woosh/meep-engine
Version:
Pure JavaScript game engine. Fully featured and production ready.
205 lines (147 loc) • 4.71 kB
JavaScript
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;
}
}