I'm making an asteroid shooter system, that can shoot projectiles where the player is facing, however, when you shoot (press space), the projectile does not move.
I've tried to add cosine and sine to the X and Y, but that obviously doesn't work. I tried adding print statements to see where it went wrong and it looks like the X and Y is just not incrementing at all. How can I make it so that it increments properly and exactly how I want it to?
circle.x += Math.cos(circle.direction) * circle.speed;
circle.y += Math.sin(circle.direction) * circle.speed;
Full code:
const canvas = document.createElement("canvas");
const ctx = canvas.getContext("2d");
document.body.appendChild(canvas);
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
var projectileArray = []
var keydown = false
const gamePlaying = true
const kbd = {
ArrowLeft: false,
ArrowUp: false,
ArrowRight: false,
ArrowDown: false,
};
const noHoldDown = {
Space: false,
}
const ship = {
angle: 0,
color: "white",
x: canvas.width / 2,
y: canvas.height / 2,
width: 10,
height: 12,
drag: 0.9,
accSpeed: 0.025,
rotSpeed: 0.007,
rotv: 0,
ax: 0,
ay: 0,
vx: 0,
vy: 0,
rotateLeft() {
this.rotv -= this.rotSpeed;
},
rotateRight() {
this.rotv += this.rotSpeed;
},
accelerate() {
this.ax += this.accSpeed;
this.ay += this.accSpeed;
},
decelerate() {
this.ax -= this.accSpeed;
this.ay -= this.accSpeed;
},
shoot() {
projectileArray.push([this.x, this.y, this.angle])
},
move() {
this.angle += this.rotv;
this.rotv *= this.drag;
this.vx += this.ax;
this.vy += this.ay;
this.ax *= this.drag;
this.ay *= this.drag;
this.vx *= this.drag;
this.vy *= this.drag;
this.x += Math.cos(this.angle) * this.vx;
this.y += Math.sin(this.angle) * this.vy;
},
draw(ctx) {
ctx.save();
ctx.lineWidth = 3;
ctx.translate(this.x, this.y);
ctx.rotate(this.angle);
ctx.beginPath();
ctx.moveTo(this.height, 0);
ctx.lineTo(-this.height, this.width);
ctx.lineTo(-this.height, -this.width);
ctx.closePath();
ctx.strokeStyle = this.color;
ctx.stroke();
ctx.restore();
}
};
document.addEventListener("keydown", event => {
if (event.code in kbd) {
event.preventDefault();
kbd[event.code] = true;
}
});
document.addEventListener("keydown", event => {
if (event.code in noHoldDown) {
if (!keydown) {
keydown = true;
ship.shoot();
}
}
});
document.addEventListener('keyup', event => {
if (event.code in noHoldDown) {
keydown = false;
}
});
document.addEventListener("keyup", event => {
if (event.code in kbd) {
event.preventDefault();
kbd[event.code] = false;
}
});
(function update() {
ctx.fillStyle = "black";
ctx.fillRect(0, 0, canvas.width, canvas.height);
const shipActions = {
ArrowLeft: "rotateLeft",
ArrowUp: "accelerate",
ArrowDown: "decelerate",
ArrowRight: "rotateRight",
};
for (const key in shipActions) {
if (kbd[key]) {
ship[shipActions[key]]();
}
}
ship.move();
ship.draw(ctx);
for (var i = 0; i < projectileArray.length; i++) {
function MovableCircle() {
this.x = projectileArray[i][0];
this.y = projectileArray[i][1];
this.speed = 1;
this.direction = projectileArray[i][1];
this.draw = () => {
ctx.arc(this.x, this.y, 3.75, 0, 2 * Math.PI);
ctx.fillStyle = 'white';
ctx.fill();
}
}
var circle = new MovableCircle();
ctx.beginPath();
circle.x += Math.cos(circle.direction) * circle.speed;
circle.y += Math.sin(circle.direction) * circle.speed;
circle.draw();
console.log(circle.x, circle.y)
}
requestAnimationFrame(update);
})();
I put so many quarters into Asteroids, I had contribute here! The problem stems from the persistence of projectiles: Rebuilding them at each turn of the
updateloop forgets any state change made in the prior iteration.Projectiles should be first-class objects, held onto by either the game or the ship. Below, are two changes to the OP's otherwise fine script:
Functionally, the only thing I added was a duration, since I think I recall in the original that projectiles which don't hit anything eventually pop out of existence.
The
shootmethod changes toSide note: I think, in the original game, projectiles' speed was fixed to be greater than the top speed of the ship, but I don't remember clearly. In the above, I set projectile speed to
+1more than the ship's current speed. This is more physically correct (at sub-relativistic speeds :-)), but probably not accurate to the original.And the
drawmethod cleans up significantly, since we moved the state-forgetting projectile code into its own classSide note: Javascript classes, starting around ES5/ES6 provide a big improvement in syntax. It's worth getting familiar with this.
Demo