123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176 |
- export class Ship {
- constructor(canvas, x, y, color = "crimson") {
- this.canvas = canvas;
- this.position = { x: x, y: y };
- this.color = color;
- this.velocity = { x: 0.1, y: -0.1 };
- this.acceleration = { x: 0, y: 0 };
- this.target = { x: canvas.width / 2, y: canvas.height / 2 };
- this.futurePoint = { x: x, y: y };
- this.angle = 0;
- this.debug = false;
- this.wrapDelay = 0;
- this.width = 10;
- this.height = 15;
- }
- update(delta) {
- this.velocity.x += this.acceleration.x;
- this.position.x += this.velocity.x;
- this.velocity.y += this.acceleration.y;
- this.position.y += this.velocity.y;
- this.velocity.x = Math.sign(this.velocity.x) * Math.min(5, Math.abs(this.velocity.x));
- this.velocity.y = Math.sign(this.velocity.y) * Math.min(5, Math.abs(this.velocity.y));
- this.acceleration = this.computeAcceleration();
- let wrappedPosition = this.screenWrap(this.position);
- if (wrappedPosition.x != this.position.x || wrappedPosition.y != this.position.y) {
- this.wrapDelay = 30;
- }
- this.position = wrappedPosition;
- }
- screenWrap(position) {
- let wrappedPosition = { x: position.x, y: position.y };
- if (position.x < 0 - 10) {
- wrappedPosition.x = this.canvas.width + 10;
- }
- if (position.x > this.canvas.width + 10) {
- wrappedPosition.x = 0 - 10;
- }
- if (position.y < 0 - 10) {
- wrappedPosition.y = this.canvas.height + 10;
- }
- if (position.y > this.canvas.height + 10) {
- wrappedPosition.y = 0 - 10;
- }
- return wrappedPosition;
- }
- computeAcceleration() {
- // let angle = Math.atan2(this.target.y - this.position.y, this.target.x - this.position.x);
- // let distanceToTarget = Math.hypot(this.target.y - this.position.y, this.target.x - this.position.x);
- // if (this.position.x != this.target.x) {
- // acceleration.x = 0.1 * Math.cos(angle);
- // }
- // if (this.position.y != this.target.y) {
- // acceleration.y = 0.1 * Math.sin(angle);
- // }
- if (this.wrapDelay > 0) {
- this.wrapDelay--;
- return this.acceleration;
- }
- let acceleration = { x: 0, y: 0 };
- // //predictive slowing
- this.futurePoint = {
- x: this.position.x,
- y: this.position.y
- };
- let futureVelocity = { x: this.velocity.x, y: this.velocity.y };
- let isCloseEnough = false;
- for (let i = 0; i < 10; i++) {
- this.futurePoint.x += futureVelocity.x;
- this.futurePoint.y += futureVelocity.y;
- if (this.closeEnough(this.target.x, this.futurePoint.x, this.canvas.width / 8) &&
- this.closeEnough(this.target.y, this.futurePoint.y, this.canvas.height / 8)) {
- isCloseEnough = true;
- break;
- }
- }
- this.angle = Math.atan2(this.target.y - this.position.y, this.target.x - this.position.x);
- let distanceToTarget = Math.hypot(this.target.y - this.position.y, this.target.x - this.position.x);
- if (!isCloseEnough) {
- acceleration.x = 0.1 * Math.cos(this.angle);
- acceleration.y = 0.1 * Math.sin(this.angle);
- }
- return acceleration;
- }
- closeEnough(n1, n2, amount = 0.1) {
- return Math.abs(n1 - n2) <= amount;
- }
- draw(context) {
- context.save();
- context.translate(this.position.x, this.position.y);
- context.rotate(this.angle - (Math.PI / 2));
- context.fillStyle = this.color;
- context.beginPath();
- this.shipShape(context);
- context.fill();
- if (this.acceleration.x != 0 || this.acceleration.y != 0) {
- context.fillStyle = "cyan";
- context.beginPath();
- this.shipThrustShape(context);
- context.fill();
- }
- context.restore();
- if (this.debug) {
- context.strokeStyle = "yellow";
- context.beginPath();
- context.moveTo(this.position.x, this.position.y);
- context.lineTo(this.target.x, this.target.y);
- context.stroke();
- context.strokeStyle = "red";
- context.beginPath();
- context.moveTo(this.position.x, this.position.y);
- context.lineTo(this.canvas.width, this.position.y);
- context.stroke();
- context.strokeStyle = "red";
- context.beginPath();
- context.moveTo(this.position.x, this.position.y);
- context.lineTo(0, this.position.y);
- context.stroke();
- context.strokeStyle = "cyan";
- context.beginPath();
- context.moveTo(this.position.x, this.position.y);
- context.lineTo(this.position.x, this.canvas.height);
- context.stroke();
- context.strokeStyle = "cyan";
- context.beginPath();
- context.moveTo(this.position.x, this.position.y);
- context.lineTo(this.position.x, 0);
- context.stroke();
- context.fillStyle = "yellow";
- context.beginPath();
- context.moveTo(this.position.x, this.position.y);
- context.arc(this.futurePoint.x, this.futurePoint.y, 2, 0, 2 * Math.PI);
- context.fill();
- }
- }
- shipShape(context) {
- context.moveTo(this.width / 2, -this.height / 2);
- context.lineTo(0, this.height / 2);
- context.lineTo(-this.width / 2, -this.height / 2);
- context.lineTo(this.width / 2, -this.height / 2);
- }
- shipThrustShape(context) {
- context.moveTo(-this.width / 4, -this.height / 2);
- context.lineTo(this.width / 4, -this.height / 2);
- context.lineTo(0, -1.2 * this.height);
- context.lineTo(-this.width / 4, -this.height / 2);
- }
- setTarget(x, y) {
- this.target.x = x;
- this.target.y = y;
- }
- }
|