@needle-tools/engine
Version:
Needle Engine is a web-based runtime for 3D apps. It runs on your machine for development with great integrations into editors like Unity or Blender - and can be deployed onto any device! It is flexible, extensible and networking and XR are built-in.
83 lines • 3.82 kB
JavaScript
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
import { Object3D, Quaternion, Vector3 } from "three";
import { Mathf } from "../engine/engine_math.js";
import { Axes } from "../engine/engine_physics.types.js";
import { serializable } from "../engine/engine_serialization_decorator.js";
import { getWorldPosition, getWorldQuaternion } from "../engine/engine_three_utils.js";
import { Behaviour } from "./Component.js";
/**
* SmoothFollow makes the {@link Object3D} (`GameObject`) smoothly follow another target {@link Object3D}.
* It can follow the target's position, rotation, or both.
* @category Interactivity
* @group Components
*/
export class SmoothFollow extends Behaviour {
/**
* The target to follow. If null, the GameObject will not move.
*/
target = null;
/**
* The factor to smoothly follow the target's position.
* The value is clamped between 0 and 1. If 0, the GameObject will not follow the target's position.
*/
followFactor = .1;
/**
* The factor to smoothly follow the target's rotation.
* The value is clamped between 0 and 1. If 0, the GameObject will not follow the target's rotation.
*/
rotateFactor = .1;
positionAxes = Axes.All;
flipForward = false;
static _invertForward = new Quaternion().setFromAxisAngle(new Vector3(0, 1, 0), Math.PI);
_firstUpdate = true;
/**
* Update the position and rotation of the GameObject to follow the target.
*/
onBeforeRender() {
this.updateNow(false);
}
updateNow(hard) {
if (!this.target || this.target === this.gameObject)
return;
if (this.followFactor > 0) {
const wp = getWorldPosition(this.target);
const fpos = this._firstUpdate || hard ? 1 : Mathf.clamp01(this.context.time.deltaTime * this.followFactor);
const currentPosition = this.worldPosition;
if (this.positionAxes & Axes.X)
currentPosition.x = Mathf.lerp(currentPosition.x, wp.x, fpos);
if (this.positionAxes & Axes.Y)
currentPosition.y = Mathf.lerp(currentPosition.y, wp.y, fpos);
if (this.positionAxes & Axes.Z)
currentPosition.z = Mathf.lerp(currentPosition.z, wp.z, fpos);
// TODO lerp distance from target as well
this.worldPosition = currentPosition;
}
if (this.rotateFactor > 0) {
const wr = getWorldQuaternion(this.target);
if (this.flipForward) {
wr.premultiply(SmoothFollow._invertForward);
}
const frot = this._firstUpdate || hard ? 1 : Mathf.clamp01(this.context.time.deltaTime * this.rotateFactor);
this.worldQuaternion = this.worldQuaternion.slerp(wr, frot);
}
this._firstUpdate = false;
}
}
__decorate([
serializable(Object3D)
], SmoothFollow.prototype, "target", void 0);
__decorate([
serializable()
], SmoothFollow.prototype, "followFactor", void 0);
__decorate([
serializable()
], SmoothFollow.prototype, "rotateFactor", void 0);
__decorate([
serializable()
], SmoothFollow.prototype, "positionAxes", void 0);
//# sourceMappingURL=SmoothFollow.js.map