@rpgjs/physic
Version:
A deterministic 2D top-down physics library for RPG, sandbox and MMO games
152 lines (151 loc) • 4.74 kB
JavaScript
import { Vector2 } from "./index2.js";
var ProjectileType = /* @__PURE__ */ ((ProjectileType2) => {
ProjectileType2["Straight"] = "straight";
ProjectileType2["Arc"] = "arc";
ProjectileType2["Bounce"] = "bounce";
return ProjectileType2;
})(ProjectileType || {});
class ProjectileMovement {
constructor(type, options) {
this.type = type;
this.elapsed = 0;
this.distanceTraveled = 0;
this.startPosition = null;
this.bounceCount = 0;
this.stage = 0;
this.finished = false;
this.currentHeight = 0;
this.verticalVelocity = 0;
const defaults = {
speed: options.speed,
direction: options.direction,
initialHeight: 0,
maxHeight: 2,
gravity: 30,
maxBounces: 0,
bounciness: 0.6,
drag: 0
};
this.options = { ...defaults, ...options };
const magnitude = Math.hypot(this.options.direction.x, this.options.direction.y);
this.direction = magnitude > 0 ? { x: this.options.direction.x / magnitude, y: this.options.direction.y / magnitude } : { x: 1, y: 0 };
this.currentHeight = this.options.initialHeight ?? 0;
if (this.type === "arc" || this.type === "bounce") {
const gravity = this.options.gravity ?? 30;
const maxHeight = this.options.maxHeight ?? 2;
this.verticalVelocity = Math.sqrt(Math.max(0, 2 * gravity * maxHeight));
}
}
update(body, dt) {
if (this.finished || dt <= 0) {
body.setVelocity({ x: 0, y: 0 });
return;
}
if (this.startPosition === null) {
this.startPosition = new Vector2(body.position.x, body.position.y);
}
this.elapsed += dt;
if (this.options.lifetime !== void 0 && this.elapsed >= this.options.lifetime) {
this.finish(body);
return;
}
switch (this.stage) {
case 0:
this.updateFlying(body, dt);
break;
case 1:
this.updateRolling(body, dt);
break;
case 2:
this.finish(body);
return;
}
if (this.startPosition) {
this.distanceTraveled = new Vector2(body.position.x, body.position.y).distanceTo(this.startPosition);
if (this.options.maxRange !== void 0 && this.distanceTraveled >= this.options.maxRange) {
this.finish(body);
}
}
}
isFinished() {
return this.finished;
}
getHeight() {
return this.currentHeight;
}
getProgress() {
if (this.options.maxRange) {
return Math.min(1, this.distanceTraveled / this.options.maxRange);
}
if (this.options.lifetime) {
return Math.min(1, this.elapsed / this.options.lifetime);
}
return 0;
}
updateFlying(body, dt) {
let vx = this.direction.x * this.options.speed;
let vy = this.direction.y * this.options.speed;
const drag = Math.max(0, Math.min(1, this.options.drag ?? 0));
if (drag > 0) {
const dragFactor = Math.pow(1 - drag, dt);
vx *= dragFactor;
vy *= dragFactor;
}
if (this.type === "arc" || this.type === "bounce") {
const gravity = this.options.gravity ?? 30;
this.verticalVelocity -= gravity * dt;
this.currentHeight += this.verticalVelocity * dt;
if (this.options.onHeightUpdate) {
this.options.onHeightUpdate(this.currentHeight, body);
} else {
const dispatcher = globalThis;
if (typeof dispatcher.dispatchEvent === "function" && typeof CustomEvent !== "undefined") {
const event = new CustomEvent("projectile:height", {
detail: {
id: body.id,
height: this.currentHeight
}
});
dispatcher.dispatchEvent(event);
}
}
if (this.currentHeight <= 0) {
this.currentHeight = 0;
if (this.type === "bounce") {
if (this.bounceCount < (this.options.maxBounces ?? 0)) {
const bounceEnergy = this.options.bounciness ?? 0.6;
this.verticalVelocity = Math.abs(this.verticalVelocity) * bounceEnergy;
vx *= bounceEnergy;
vy *= bounceEnergy;
this.bounceCount += 1;
} else {
this.stage = 1;
}
} else {
this.finish(body);
return;
}
}
}
body.setVelocity({ x: vx, y: vy });
}
updateRolling(body, dt) {
const friction = 0.85;
const vx = body.velocity.x * Math.pow(friction, dt * 60);
const vy = body.velocity.y * Math.pow(friction, dt * 60);
body.setVelocity({ x: vx, y: vy });
if (Math.abs(vx) < 0.1 && Math.abs(vy) < 0.1) {
this.finish(body);
}
}
finish(body) {
this.finished = true;
this.stage = 2;
body.setVelocity({ x: 0, y: 0 });
}
}
export {
ProjectileMovement,
ProjectileType
};
//# sourceMappingURL=index40.js.map