UNPKG

@rpgjs/physic

Version:

A deterministic 2D top-down physics library for RPG, sandbox and MMO games

152 lines (151 loc) 4.74 kB
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