HTML5 Canvas - Enemy Shooting - javascript

I'm making a game in HTML5 Canvas. Right now I'm trying to make it so the enemy (a ground to air gun) can shoot in the direction of the player (a plane).
My game uses 2 arrays to make a map according to the values in it. Because the game won't know how many enemies to put on the screen until it goes through the map, I have it create a new enemy with a random id, and have it add it to an object that keeps track of the enemies every time it comes across an enemy value in the map.
The problem comes when the enemies shoot at the plane, they all shoot at the same angle, and not at the angle necessary for that particular situation.
Here's the question: How can I get each enemy to shoot at the player at the correct angle?
I realize that this question/explanation may be a little confusing to understand, but please give it a shot. It would be good to start looking at lines 222-257 (The updateEntity function). (Please be aware that this is a separate code example from my real game code, it's not the best.)
Code on google drive: https://drive.google.com/open?id=0By026U5OT4C7OUZSNG5GM19kV1U
JS Fiddle: https://jsfiddle.net/k2xwypkp/
Whole code:
<center><canvas id = "gameCanvas" width = "500" height = "500" style = "border:1px solid navy;"></canvas></center>
var canvas, ctx;
var clip = {};
var arsenal = {};
var enemyClip = {};
var keyDown = {};
var enemy = {};
window.onload = function() {
canvas = document.getElementById("gameCanvas");
ctx = canvas.getContext("2d");
for (var i = 0; i < 3; i++) {
createEnemy(Math.random(), i * 100 + 140);
}
setInterval(function() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
update();
}, 1000 / 30);
}
var player = {
x: 240,
y: 240,
w: 20,
h: 20,
color: "navy",
alive: true,
canShoot: true,
canNuke: true,
facingRight: true,
draw: function() {
ctx.fillStyle = this.color;
ctx.fillRect(this.x, this.y, this.w, this.h);
},
shoot: function() {
if (player.canShoot) {
player.canShoot = false;
if (player.facingRight) {
createPlayerBullet(Math.random(), player.x + player.w, player.y + player.h / 2, true);
} else {
createPlayerBullet(Math.random(), player.x, player.y + player.h / 2, false);
}
setTimeout(function() {
player.canShoot = true;
}, 750);
}
},
nuke: function() {
if (player.canNuke) {
player.canNuke = false;
createNuke(Math.random(), player.x + player.w / 2, player.y + player.h);
setTimeout(function() {
player.canNuke = true;
}, 2000);
}
}
}
//var enemy = {
// x:240,
// y:480,
// w:20,
// h:20,
// color:"maroon",
// alive:true,
// canShoot:true,
//
// draw:function(){
// ctx.fillStyle = this.color;
// ctx.fillRect(this.x, this.y, this.w, this.h);
// },
//
// shoot:function(){
// if(enemy.canShoot){
// enemy.canShoot = false;
//
// if(player.x >= enemy.x && player.y <= enemy.y){// Top Right: TF, Bottom Right: TT, Bottom Left: FT, Top Left: FF
// createEnemyBullet(Math.random(), enemy.x + enemy.w/2, enemy.y, player.x, player.y, true, false); // True equals ___ is greater than
// }else if(player.x >= enemy.x && player.y >= enemy.y){
// createEnemyBullet(Math.random(), enemy.x + enemy.w/2, enemy.y, player.x, player.y, true, true);
// }else if(player.x <= enemy.x && player.y >= enemy.y){
// createEnemyBullet(Math.random(), enemy.x + enemy.w/2, enemy.y, player.x, player.y, false, true);
// }else if(player.x <= enemy.x && player.y <= enemy.y){
// createEnemyBullet(Math.random(), enemy.x + enemy.w/2, enemy.y, player.x, player.y, false, false);
// }
//
// setTimeout(function(){
// enemy.canShoot = true;
// }, 750);
// }
// }
//}
var createEnemy = function(ID, X) {
var e = {
x: X,
y: 480,
w: 20,
h: 20,
color: "maroon",
alive: true,
canShoot: true,
id: ID,
draw: function() {
ctx.fillStyle = this.color;
ctx.fillRect(this.x, this.y, this.w, this.h);
},
shoot: function() {
if (this.canShoot) {
this.canShoot = false;
if (player.x >= this.x && player.y <= this.y) { // Top Right: TF, Bottom Right: TT, Bottom Left: FT, Top Left: FF
createEnemyBullet(Math.random(), this.x + this.w / 2, this.y, player.x, player.y, true, false); // True means greater than
} else if (player.x >= this.x && player.y >= this.y) {
createEnemyBullet(Math.random(), this.x + this.w / 2, this.y, player.x, player.y, true, true);
} else if (player.x <= this.x && player.y >= this.y) {
createEnemyBullet(Math.random(), this.x + this.w / 2, this.y, player.x, player.y, false, true);
} else if (player.x <= this.x && player.y <= this.y) {
createEnemyBullet(Math.random(), this.x + this.w / 2, this.y, player.x, player.y, false, false);
}
setTimeout(function() {
enemy.canShoot = true;
}, 750);
}
}
};
enemy[e.id] = e;
}
var createPlayerBullet = function(ID, X, Y, dir) {
var playerBullet = {
x: X,
y: Y,
w: 5,
h: 5,
color: "navy",
id: ID,
facingRight: dir,
draw: function() {
ctx.fillStyle = this.color;
ctx.fillRect(this.x, this.y, this.w, this.h);
}
}
clip[playerBullet.id] = playerBullet;
}
var createEnemyBullet = function(ID, X, Y, playerx, playery, dirx, diry) {
var enemyBullet = {
x: X,
y: Y,
w: 5,
h: 5,
color: "maroon",
id: ID,
dirX: dirx,
dirY: diry,
playerX: playerx,
playerY: playery,
draw: function() {
ctx.fillStyle = this.color;
ctx.fillRect(this.x, this.y, this.w, this.h);
}
}
enemyClip[enemyBullet.id] = enemyBullet;
}
var createNuke = function(ID, X, Y) {
var nuke = {
x: X,
y: Y,
w: 5,
h: 5,
color: "green",
id: ID,
draw: function() {
ctx.fillStyle = this.color;
ctx.fillRect(this.x, this.y, this.w, this.h);
}
}
arsenal[nuke.id] = nuke;
}
var updateEntity = function() {
for (var playerBullet in clip) {
clip[playerBullet].draw();
if (clip[playerBullet].facingRight) {
clip[playerBullet].x += 8;
} else {
clip[playerBullet].x -= 8;
}
if (clip[playerBullet].x <= 0) {
delete clip[playerBullet];
} else if (clip[playerBullet].x >= canvas.width) {
delete clip[playerBullet];
}
}
for (var nuke in arsenal) {
arsenal[nuke].draw();
arsenal[nuke].y += 3;
if (arsenal[nuke].y >= canvas.height) {
delete arsenal[nuke];
}
}
for (var enemyBullet in enemyClip) {
for (var e in enemy) {
var dx = enemy[e].x - enemyClip[enemyBullet].playerX;
var dy = enemy[e].y - enemyClip[enemyBullet].playerY;
var angle = Math.atan2(dy, dx);
}
enemyClip[enemyBullet].draw();
if (enemyClip[enemyBullet].dirX && !enemyClip[enemyBullet].dirY) {
enemyClip[enemyBullet].x -= 10 * Math.cos(angle);
enemyClip[enemyBullet].y -= 10 * Math.sin(angle);
} else if (enemyClip[enemyBullet].dirX && enemyClip[enemyBullet].dirY) {
enemyClip[enemyBullet].x -= 10 * Math.cos(angle);
enemyClip[enemyBullet].y -= 10 * Math.sin(angle);
} else if (!enemyClip[enemyBullet].dirX && enemyClip[enemyBullet].dirY) {
enemyClip[enemyBullet].x -= 10 * Math.cos(angle);
enemyClip[enemyBullet].y -= 10 * Math.sin(angle);
} else if (!enemyClip[enemyBullet].dirX && !enemyClip[enemyBullet].dirY) {
enemyClip[enemyBullet].x -= 10 * Math.cos(angle);
enemyClip[enemyBullet].y -= 10 * Math.sin(angle);
}
if (enemyClip[enemyBullet].x <= 0) {
delete enemyClip[enemyBullet];
} else if (enemyClip[enemyBullet].x >= canvas.width) {
delete enemyClip[enemyBullet];
} else if (enemyClip[enemyBullet].y <= 0) {
delete enemyClip[enemyBullet];
} else if (enemyClip[enemyBullet].y >= canvas.height) {
delete enemyClip[enemyBullet];
} else if (enemyClip[enemyBullet].x >= player.x && enemyClip[enemyBullet].x <= player.x + player.w && enemyClip[enemyBullet].y >= player.y && enemyClip[enemyBullet].y <= player.y + player.h) {
delete enemyClip[enemyBullet];
}
}
}
var update = function() {
updateEntity();
if (player.alive) {
player.draw();
}
//if(enemy.alive){
// enemy.draw();
// enemy.shoot();
//}
for (var e in enemy) {
ctx.fillStyle = enemy[e].color;
ctx.fillRect(enemy[e].x, enemy[e].y, enemy[e].w, enemy[e].h);
if (enemy[e].canShoot) {
enemy[e].canShoot = false;
if (player.x >= enemy[e].x && player.y <= enemy[e].y) { // Top Right: TF, Bottom Right: TT, Bottom Left: FT, Top Left: FF
createEnemyBullet(Math.random(), enemy[e].x + enemy[e].w / 2, enemy[e].y, player.x, player.y, true, false); // True equals ___ is greater than
} else if (player.x >= enemy[e].x && player.y >= enemy[e].y) {
createEnemyBullet(Math.random(), enemy[e].x + enemy[e].w / 2, enemy[e].y, player.x, player.y, true, true);
} else if (player.x <= enemy[e].x && player.y >= enemy[e].y) {
createEnemyBullet(Math.random(), enemy[e].x + enemy[e].w / 2, enemy[e].y, player.x, player.y, false, true);
} else if (player.x <= enemy[e].x && player.y <= enemy[e].y) {
createEnemyBullet(Math.random(), enemy[e].x + enemy[e].w / 2, enemy[e].y, player.x, player.y, false, false);
}
setTimeout(function() {
for (var e in enemy) {
enemy[e].canShoot = true;
}
}, 750);
}
}
if (37 in keyDown) {
player.facingRight = false;
player.x -= 5;
}
if (38 in keyDown) {
player.y -= 5;
}
if (39 in keyDown) {
player.facingRight = true;
player.x += 5;
}
if (40 in keyDown) {
player.y += 5;
}
if (32 in keyDown) {
player.shoot();
}
if (90 in keyDown) {
player.nuke();
}
}
addEventListener("keydown", function(e) {
keyDown[e.keyCode] = true;
});
addEventListener("keyup", function(e) {
delete keyDown[e.keyCode];
});
I appreciate your time spent trying (and hopefully) helping me. Thanks.

This code in updateEntity
for (var enemyBullet in enemyClip) {
for (var e in enemy) {
var dx = enemy[e].x - enemyClip[enemyBullet].playerX;
var dy = enemy[e].y - enemyClip[enemyBullet].playerY;
var angle = Math.atan2(dy, dx);
}
Should be written without the for loop. You should just refer to the enemy that shot the bullet.
for (var enemyBullet in enemyClip) {
var bullet = enemyClip[enemyBullet];
var dx = bullet.enemyX - bullet.playerX;
var dy = bullet.enemyY - bullet.playerY;
var angle = Math.atan2(dy, dx);
However, instead of storing all this information when a bullet is shot, you should just calculate the angle of the bullet when it is shot (it is not necessary for the bullet to know the player position and the 'dir' value seems unnecessary)
if (enemy[e].canShoot) {
enemy[e].canShoot = false;
var angle = Math.atan2( enemy[e].y-player.y, enemy[e].x-player.x);
...
createEnemyBullet(Math.random(), angle, enemy[e].x + enemy[e].w/2, enemy[e].y);
Your updateEntity code then just becomes:
for (var enemyBullet in enemyClip) {
var angle = enemyClip[enemyBullet].angle;
Before you go further I would suggest that you look at your code and review how you can simplify it there is a lot that could be removed. You create enemy bullets in 2 places and each place has 4 calls to createEnemyBullet also consider how enemy bullets and player bullets are the same. Also Math.random() is not a good way to generate a unique id. Just use an incrementing number each time (although there is no real reason for the id in this code)

Related

Add a animated sprite to phaser objects

I have the following code in phaser, and I want to use a sprite animation instead of a static image, how can I pull that off? Using group to create new bullets.
I am creating a new object and with that creating new bullets to get fired by the player. And I want the bullet to rotate with an animated spritshit. How can I do that?
this.bullets = this.physics.add.group({
classType: Bullet,
maxSize: 10,
runChildUpdate: true,
});
The class i am using to create new bullets
var Bullet = new Phaser.Class({
Extends: Phaser.GameObjects.Image,
initialize:
function Bullet (scene)
{
Phaser.GameObjects.Sprite.call(this, scene, 0, 0, "bullet");
this.speed = Phaser.Math.GetSpeed(250, 1);
},
fire: function (x, y, direcao)
{
this.direcao = direcao;
if(direcao == 1){
//Cima
// console.log("Tiro Acima");
this.setPosition(x, y - 10);
this.setActive(true);
this.setVisible(true);
}else if(direcao == 2){
// Baixo
// console.log("Tiro Abaixo");
this.setPosition(x, y + 10);
this.setActive(true);
this.setVisible(true);
}else if(direcao == 3){
//Direita
//console.log("Tiro a direita");
this.setPosition(x + 10, y);
this.setActive(true);
this.setVisible(true);
}else if(direcao == 4){
//Esquerda
//console.log("Tiro a esquerda");
this.setPosition(x - 10, y );
this.setActive(true);
this.setVisible(true);
} else {
//Debug
console.log("Não disparou");
}
},
update: function (time, delta)
{
if(this.direcao == 1){
//Cima
// console.log("Tiro Acima");
this.y -= this.speed * delta;
}else if(this.direcao == 2){
//Baixo
// console.log("Tiro Abaixo");
this.y += this.speed * delta;
}else if(this.direcao == 3){
//Direita
// console.log("Tiro a direita");
this.x += this.speed * delta;
}else if(this.direcao == 4){
//Esquerda
// console.log("Tiro a esquerda");
this.x -= this.speed * delta;
}else{
//Debug
// console.log("Não disparou");
}
if (this.y < 0)
{
this.setActive(false);
this.setVisible(false);
}
if (this.y > 480)
{
this.setActive(false);
this.setVisible(false);
}
if (this.x < 0)
{
this.setActive(false);
this.setVisible(false);
}
if (this.x > 960)
{
this.setActive(false);
this.setVisible(false);
}
}
});
First you could extend from Phaser.GameObjects.Sprite rather than from Phaser.GameObjects.Image, then create an animation, with this.anims.create (link to documentation), and start the animation in the fire method , with the method play and stop the animation, when the bullet leaves the display (or so), in the update method.
Here a small working Demo (with pulsating bullet):
document.body.style = 'margin:0;';
var Bullet = new Phaser.Class({
Extends: Phaser.GameObjects.Sprite,
initialize: function Bullet (scene, x, y) {
Phaser.GameObjects.Sprite.call(this, scene, x, y, 'dynamicFrames');
},
fire: function (x, y) {
this.x = x;
this.y = y;
this.play('pulse');
this.setActive(true);
this.setVisible(true);
},
update: function (time, delta) {
let speed = .15;
this.x += speed * delta;
if (this.x > config.width) {
this.setActive(false);
this.setVisible(false);
this.stop();
}
}
});
class Example extends Phaser.Scene
{
constructor () {
super();
}
preload () {
/** CREATE SPRITE FRAME FOR ONLY DEMO --- START */
const canvasFrame = this.textures
.createCanvas('dynamicFrames', 32, 16);
let ctx = canvasFrame.context;
ctx.fillStyle = '#ffff00';
ctx.beginPath();
ctx.arc(8, 8, 8, 0, Math.PI * 2, false);
ctx.closePath();
ctx.fill();
ctx.beginPath();
ctx.arc(16 + 8, 8, 6, 0, Math.PI * 2, false);
ctx.closePath();
ctx.fill();
canvasFrame.add(1, 0, 0, 0, 16, 16);
canvasFrame.add(2, 0, 16, 0, 16, 16);
canvasFrame.refresh();
/** CREATE SPRITE FRAME FOR ONLY DEMO --- END*/
this.anims.create({
key: 'pulse',
frames: this.anims.generateFrameNumbers('dynamicFrames', { start: 1, end: 2 }),
frameRate: 8,
repeat: -1
});
}
create(){
this.add.circle(60, 100, 20, 0xffffff);
this.add.rectangle(55, 100, 45, 10, 0xffffff)
.setOrigin(0, .5);
let bullets = this.physics.add.group({
classType: Bullet,
maxSize: 10,
runChildUpdate: true,
});
this.time.addEvent({
delay: 1000,
startAt: 0,
loop: true,
callback: _ => {
bullets
.get(100, 100)
.fire(110, 100);
}
});
}
}
var config = {
type: Phaser.AUTO,
width: 536,
height: 183,
physics: { default: 'arcade' },
scene: [ Example ],
banner: false
};
new Phaser.Game(config);
<script src="https://cdn.jsdelivr.net/npm/phaser#3.55.2/dist/phaser.js"></script>
For future references, here is the solution using #winner solution.
var Bullet = new Phaser.Class({
Extends: Phaser.GameObjects.Sprite,
initialize:
function Bullet (scene)
{
Phaser.GameObjects.Sprite.call(this, scene, 0, 0, "bullet");
this.speed = Phaser.Math.GetSpeed(250, 1);
},
fire: function (x, y, direcao)
{
//Animação Bala
this.anims.create({
key: 'bulletAnimation',
frames: this.anims.generateFrameNumbers('bullet', {frames: [0, 1, 3, 4, 6, 7, 9, 10]}),
frameRate: 10,
repeat: -1,
});
this.anims.play('bulletAnimation', true);
this.direcao = direcao;
if(direcao == 1){
//Cima
// console.log("Tiro Acima");
this.setPosition(x, y - 10);
this.setActive(true);
this.setVisible(true);
}else if(direcao == 2){
//Baixo
// console.log("Tiro Abaixo");
this.setPosition(x, y + 10);
this.setActive(true);
this.setVisible(true);
}else if(direcao == 3){
//Direita
// console.log("Tiro a direita");
this.setPosition(x + 10, y);
this.setActive(true);
this.setVisible(true);
}else if(direcao == 4){
//Esquerda
// console.log("Tiro a esquerda");
this.setPosition(x - 10, y );
this.setActive(true);
this.setVisible(true);
}else{
//Debug
console.log("Não disparou");
}
},
update: function (time, delta)
{
if(this.direcao == 1){
//Cima
// console.log("Tiro Acima");
this.y -= this.speed * delta;
}else if(this.direcao == 2){
//Baixo
// console.log("Tiro Abaixo");
this.y += this.speed * delta;
}else if(this.direcao == 3){
//Direita
// console.log("Tiro a direita");
this.x += this.speed * delta;
}else if(this.direcao == 4){
//Esquerda
// console.log("Tiro a esquerda");
this.x -= this.speed * delta;
}else{
//Debug
// console.log("Não disparou");
}
if (this.y < 0)
{
this.setActive(false);
this.setVisible(false);
}
if (this.y > 480)
{
this.setActive(false);
this.setVisible(false);
}
if (this.x < 0)
{
this.setActive(false);
this.setVisible(false);
}
if (this.x > 960)
{
this.setActive(false);
this.setVisible(false);
}
}
});

Javascript Enemy angle/direction

I made a little game where there are 3 objects
Player: Can move using WASD
Bullet: Moved by an event listener of click
Enemy: Follows the player like a zombie.
How do I make it so the angle of the zombie is the direction he is moving, Rather than always facing the player object?
Fiddle
tick: function() {
enemy.angle = Math.atan2(player.y - enemy.y, player.x - enemy.x);// * (180 / Math.PI);
},
above is the code I use to make the enemy face the player
I understand what you're trying to ask, but really, right now the zombie is always going directly to player, so it would actually be weird if it looked some other way. What you need to do is to actually make zombie slowly turn and walk on it's own, rather than just reducing euclidean distance between it and the player.
First stem, one that I'll do for you is calculating the rotation. Instead of just getting to the correct angle instantly, we have to slowly turn every tick:
tick: function() {
// 1 degree per tick
const rotationSpeed = (1/180)*Math.PI;
// the angle we want - facing the player
const desiredAngle = Math.atan2(player.y - enemy.y, player.x - enemy.x)
// transition angle will be explained below
enemy.angle = transitionAngle(enemy.angle, desiredAngle,rotationSpeed );
},
This is not as easy as it sounds, because you need to calculate whether it's faster to turn left or right to face the player again. Fortunately this is easy to google once you know what you need. I based my function on this answer:
function transitionAngle(fromAngle, toAngle, speed) {
// normalize the angles to 0-360 range
const rad360 = 2*Math.PI;
fromAngle = fromAngle % rad360;
toAngle = toAngle % rad360;
if (fromAngle < toAngle) {
if (Math.abs(fromAngle - toAngle) < Math.PI)
fromAngle += speed;
else fromAngle -= speed;
}
else {
if (Math.abs(fromAngle - toAngle) < Math.PI)
fromAngle -= speed;
else fromAngle += speed;
}
return fromAngle;
}
With that, the zombie slows slowly, and it already looks a little better.
var canvas = document.getElementById('canvas');
var context = canvas.getContext('2d');
var bounds = canvas.getBoundingClientRect();
var mouseX = 0.0;
var mouseY = 0.0;
var pressingDown = false;
var pressingUp = false;
var pressingLeft = false;
var pressingRight = false;
var player = {
x: 210,
y: 250,
radius: 17.5,
angle: 0.0,
tick: function() {
this.angle = Math.atan2(mouseY - this.y, mouseX - this.x);
},
draw: function() {
context.fillStyle = "darkred";
context.strokeStyle = "black";
context.translate(this.x, this.y);
context.rotate(this.angle);
context.beginPath();
context.moveTo(this.radius, 0.0);
context.lineTo(-0.5 * this.radius, 0.5 * this.radius);
context.lineTo(-0.5 * this.radius, -0.5 * this.radius);
context.lineTo(this.radius, 0.0);
context.fill();
context.stroke();
context.rotate(-this.angle);
context.translate(-this.x, -this.y);
},
updatePlayerPosition: function() {
if (pressingRight)
player.x += 1;
if (pressingLeft)
player.x -= 1;
if (pressingDown)
player.y += 1;
if (pressingUp)
player.y -= 1;
}
}
var bullet = {
x: player.x,
y: player.y,
dx: 0.0,
dy: 0.0,
radius: 5.0,
tick: function() {
this.x += this.dx;
this.y += this.dy;
if (this.x + this.radius < 0.0 || this.x - this.radius > canvas.width || this.y + this.radius < 0.0 || this.y - this.radius > canvas.height) {
this.dx = 0.0;
this.dy = 0.0;
}
},
render: function() {
context.fillStyle = "darkcyan";
context.strokeStyle = "white";
context.beginPath();
context.arc(this.x, this.y, this.radius, 0.0, 2.0 * Math.PI, false);
context.fill();
context.stroke();
}
};
var enemy = {
x: 200,
y: 300,
radius: 17.5,
angle: 0.0,
tick: function() {
// 1 degree per tick
const rotationSpeed = (1/180)*Math.PI;
const desiredAngle = Math.atan2(player.y - enemy.y, player.x - enemy.x)
enemy.angle = transitionAngle(enemy.angle, desiredAngle,rotationSpeed );
},
draw: function() {
context.fillStyle = "Green";
context.strokeStyle = "darkgreen";
context.translate(this.x, this.y);
context.rotate(this.angle);
context.beginPath();
context.moveTo(this.radius, 0.0);
context.lineTo(-0.5 * this.radius, 0.5 * this.radius);
context.lineTo(-0.5 * this.radius, -0.5 * this.radius);
context.lineTo(this.radius, 0.0);
context.fill();
context.stroke();
context.rotate(-this.angle);
context.translate(-this.x, -this.y);
},
drawEnemy: function(something){
var diffX = player.x - something.x;
var diffY = player.y - something.y
if (diffX > 0)
something.x += .3
else
something.x -= .3;
if (diffY > 0)
something.y += .3
else
something.y -= .3;
}
}
function Refresh() {
context.clearRect(0, 0, canvas.width, canvas.height);
bullet.render();
bullet.tick();
player.draw();
player.tick();
player.updatePlayerPosition();
enemy.draw();
enemy.tick();
enemy.drawEnemy(enemy);
}
setInterval(Refresh, 0)
window.onmousemove = function(e) {
mouseX = e.clientX - bounds.left;
mouseY = e.clientY - bounds.top;
}
document.onkeydown = function(event) {
if (event.keyCode === 83) //s
pressingDown = true;
else if (event.keyCode === 87) //w
pressingUp = true;
else if (event.keyCode === 65) //a
pressingLeft = true;
else if (event.keyCode === 68) //d
pressingRight = true;
}
document.onkeyup = function(event) {
if (event.keyCode === 83) //s
pressingDown = false;
else if (event.keyCode === 87) //w
pressingUp = false;
else if (event.keyCode === 65) //a
pressingLeft = false;
else if (event.keyCode === 68) //d
pressingRight = false;
}
window.onmousedown = function(e) {
// The mouse pos - the player pos gives a vector
// that points from the player toward the mouse
var x = mouseX - player.x;
var y = mouseY - player.y;
// Using pythagoras' theorm to find the distance (the length of the vector)
var l = Math.sqrt(x * x + y * y);
// Dividing by the distance gives a normalized vector whose length is 1
x = x / l;
y = y / l;
// Reset bullet position
bullet.x = player.x;
bullet.y = player.y;
// Get the bullet to travel towards the mouse pos with a new speed of 10.0 (you can change this)
bullet.dx = x * 10.0;
bullet.dy = y * 10.0;
}
function transitionAngle(fromAngle, toAngle, speed) {
// normalize the angles to 0-360 range
const rad360 = 2*Math.PI;
fromAngle = fromAngle % rad360;
toAngle = toAngle % rad360;
if (fromAngle < toAngle) {
if (Math.abs(fromAngle - toAngle) < Math.PI)
fromAngle += speed;
else fromAngle -= speed;
}
else {
if (Math.abs(fromAngle - toAngle) < Math.PI)
fromAngle -= speed;
else fromAngle += speed;
}
return fromAngle;
}
<canvas id="canvas" style="border:2px solid darkred" width="700" height="500"></canvas>
The second part of the job - and I'm leaving that to you - is to make zombie actually walk in the direction it's facing. To do that, assign it a walking speed and then use sin and cos of the zombie's angle multiplied with the speed to get X and Y offsets. Again, google is your friend, just type "move by speed and angle javascript".

Canvas Rectangle & Ball Collision Not working

I'm making a html5 canvas game and I have a problem with the collision.
The problem is when the ball collides with any platform, the ball gravity should be -1 and go up as the same velocity as the platforms but it only works with the last platform and the left one. How can I fix it? Thanks!
HTML:
<html>
<head>
<title>Falldown</title>
</head>
<body>
<canvas id="canvas" width = "380" height= "640"></canvas>
<script src="beta.js"></script>
</body>
</html>
JS Code:
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var isMenu = true;
var isPlaying = false;
var testing = true;
var pressingLeft = false;
var pressingRight = false;
var Platforms = [];
var difficulty = 1;
var gravity = 1;
var Player = {
color: "red",
radius: 7.5,
stepY: 1.5,
x: 175,
y: 75
};
function RectCircleColliding(circle, rect) {
var distX = Math.abs(circle.x - rect.x - rect.width / 2);
var distY = Math.abs(circle.y - rect.y - 20 / 2);
if (distX > (rect.width / 2 + circle.radius)) return false;
if (distY > (20 / 2 + circle.radius)) return false;
if (distX <= (rect.width / 2)) return true;
if (distY <= (20 / 2)) return true;
var dx = distX - rect.width / 2;
var dy = distY - 20 / 2;
return (dx * dx + dy * dy <= (circle.radius * circle.radius));
}
function drawBackground() {
ctx.fillStyle = "black";
ctx.fillRect(0, 0, canvas.width, canvas.height);
if (isMenu && !isPlaying) {
createText("60px monospace", "white", "FallDown", 45, 130);
createText("34px Arial", "white", "PLAY", 130, 260);
createText("34px Arial", "white", "LEADERBOARD", 50, 340);
createText("34px Arial", "white", "SETTINGS", 90, 420);
} else {
if (testing) {
Platforms = [];
for (var i = 0; i < 13; i++) {
Platforms.push({
"x": 10,
"y": 160 + (i * 70),
"width": (Math.random() * canvas.width) - 60
});
}
testing = false;
}
for (var i in Platforms) {
ctx.fillStyle = "#00ffff";
ctx.fillRect(10, Platforms[i].y, Platforms[i].width, 20);
var totalTest = Platforms[i].width + 60;
ctx.fillRect(totalTest + 30, Platforms[i].y, canvas.width - totalTest, 20);
Platforms[i].y -= 1;
if (RectCircleColliding(Player, Platforms[i])) {
gravity = -1;
} else {
gravity = 1;
}
}
detectBorderCollision();
detectPlayerCollision();
drawPlayer();
drawBorder();
if (Platforms.length === 7) Platforms = [];
}
}
function detectBorderCollision() {
if (Player.x > 370 - Player.radius) {
Player.x = 370 - Player.radius;
} else if (Player.x < 3.8 + Player.radius * 2) {
Player.x = 3.8 + Player.radius * 2
}
}
function detectPlayerCollision() {
}
function drawPlayer() {
ctx.beginPath();
ctx.fillStyle = Player.color;
ctx.arc(Player.x, Player.y, Player.radius, 0, 2 * Math.PI);
ctx.fill();
ctx.closePath();
Player.y += gravity;
if (pressingRight) {
Player.x += 2;
} else if (pressingLeft) {
Player.x -= 2;
}
/*
ctx.fillStyle = "#00ffff";
ctx.fillRect(10, 160, 300, 20);
*/
}
function drawBorder() {
ctx.beginPath();
ctx.strokeStyle = "#00ffff";
ctx.lineWidth = 10;
ctx.moveTo(5, 0);
ctx.lineTo(5, 640);
ctx.moveTo(375, 0);
ctx.lineTo(375, 640);
ctx.stroke();
ctx.closePath();
}
function createText(font, color, value, posX, posY) {
ctx.font = font;
ctx.fillStyle = color;
ctx.fillText(value, posX, posY)
}
function isInside(realX, realY, x1, x2, y1, y2) {
return (realX > x1 && realX < x2) && (realY > y1 && realY < y2)
}
function drawGame() {
drawBackground();
}
function startDrawing() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
drawGame();
requestAnimationFrame(startDrawing);
}
function Init() {
requestAnimationFrame(startDrawing);
canvas.addEventListener("click", function(evt) {
var rect = canvas.getBoundingClientRect();
var mouseX = evt.clientX - rect.left;
var mouseY = evt.clientY - rect.top;
if (isMenu && !isPlaying) {
if (isInside(mouseX, mouseY, 115, 230, 220, 270)) {
isPlaying = true;
isMenu = false;
} else if (isInside(mouseX, mouseY, 35, 320, 300, 345)) {
console.log("Leaderboard");
} else if (isInside(mouseX, mouseY, 75, 270, 380, 430)) {
console.log("Settings");
}
}
});
window.addEventListener("keydown", function(evt) {
if (!isMenu && isPlaying) {
if (evt.keyCode === 39) { // right
pressingRight = true;
} else if (evt.keyCode === 37) { // left
pressingLeft = true;
}
}
});
window.addEventListener("keyup", function(evt) {
if (!isMenu && isPlaying) {
if (evt.keyCode === 39) { // right
pressingRight = false;
} else if (evt.keyCode === 37) { // left
pressingLeft = false;
}
}
});
}
Init();
There are so many magic numbers in your code that debugging it is difficult and tedious. Replace all the number literals with identifiers which describe what the values represent.
The following amendment to part of the drawBackground function causes all the collisions with left hand platforms to work, but not perfectly.
var hasCollided;
for (var i in Platforms) {
ctx.fillStyle = "#00ffff";
ctx.fillRect(10, Platforms[i].y, Platforms[i].width, 20);
var totalTest = Platforms[i].width + 60;
ctx.fillRect(totalTest + 30, Platforms[i].y, canvas.width - totalTest, 20);
Platforms[i].y -= 1;
if (!hasCollided) {
if (RectCircleColliding(Player, Platforms[i])) {
gravity = -1;
hasCollided = true;
} else {
gravity = 1;
}
}
}

Duplicate randomly multiple objects inside a javascript for loop

I found this platform game on the Internet and I modified it a bit:
<canvas id="canvas" widht=1000 height=400></canvas>
<script>
(function () {
var requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame;
window.requestAnimationFrame = requestAnimationFrame;
})();
var canvas = document.getElementById("canvas"),
ctx = canvas.getContext("2d"),
width = 1000,
height = 400,
player = {
x: width / 2,
y: height - 15,
width: 5,
height: 5,
speed: 3,
velX: 0,
velY: 0,
jumping: false,
grounded: false
},
keys = [],
friction = 0.8,
gravity = 0.3;
var boxes = [];
// dimensions
a = Math.floor((Math.random() * 20) + 1);
for (i = 0; i < a; i++) {
random1 = Math.floor((Math.random() * 1000) + 1);
random2 = Math.floor((Math.random() * 400) + 1);
random3 = Math.floor((Math.random() * 200) + 1);
random4 = Math.floor((Math.random() * 200) + 1);
boxes.push({
x: random1,
y: random2,
width: random3,
height: random4
}
boxes.push({
x: 0,
y: 0,
width: 10,
height: height
});
boxes.push({
x: 0,
y: height - 2,
width: width,
height: 50
});
boxes.push({
x: width - 10,
y: 0,
width: 50,
height: height
});
canvas.width = width;
canvas.height = height;
function update() {
// check keys
if (keys[38] || keys[32]) {
// up arrow or space
if (!player.jumping && player.grounded) {
player.jumping = true;
player.grounded = false;
player.velY = -player.speed * 2;
}
}
if (keys[39]) {
// right arrow
if (player.velX < player.speed) {
player.velX++;
}
}
if (keys[37]) {
// left arrow
if (player.velX > -player.speed) {
player.velX--;
}
}
player.velX *= friction;
player.velY += gravity;
ctx.clearRect(0, 0, width, height);
ctx.fillStyle = "black";
ctx.beginPath();
player.grounded = false;
for (var i = 0; i < boxes.length; i++) {
ctx.rect(boxes[i].x, boxes[i].y, boxes[i].width, boxes[i].height);
var dir = colCheck(player, boxes[i]);
if (dir === "l" || dir === "r") {
player.velX = 0;
player.jumping = false;
} else if (dir === "b") {
player.grounded = true;
player.jumping = false;
} else if (dir === "t") {
player.velY *= -1;
}
}
if(player.grounded){
player.velY = 0;
}
player.x += player.velX;
player.y += player.velY;
ctx.fill();
ctx.fillStyle = "red";
ctx.fillRect(player.x, player.y, player.width, player.height);
requestAnimationFrame(update);
}
function colCheck(shapeA, shapeB) {
// get the vectors to check against
var vX = (shapeA.x + (shapeA.width / 2)) - (shapeB.x + (shapeB.width / 2)),
vY = (shapeA.y + (shapeA.height / 2)) - (shapeB.y + (shapeB.height / 2)),
// add the half widths and half heights of the objects
hWidths = (shapeA.width / 2) + (shapeB.width / 2),
hHeights = (shapeA.height / 2) + (shapeB.height / 2),
colDir = null;
// if the x and y vector are less than the half width or half height, they we must be inside the object, causing a collision
if (Math.abs(vX) < hWidths && Math.abs(vY) < hHeights) {
// figures out on which side we are colliding (top, bottom, left, or right)
var oX = hWidths - Math.abs(vX),
oY = hHeights - Math.abs(vY);
if (oX >= oY) {
if (vY > 0) {
colDir = "t";
shapeA.y += oY;
} else {
colDir = "b";
shapeA.y -= oY;
}
} else {
if (vX > 0) {
colDir = "l";
shapeA.x += oX;
} else {
colDir = "r";
shapeA.x -= oX;
}
}
}
return colDir;
}
document.body.addEventListener("keydown", function (e) {
keys[e.keyCode] = true;
});
document.body.addEventListener("keyup", function (e) {
keys[e.keyCode] = false;
});
window.addEventListener("load", function () {
update();
});
</script>
The problem is in the for loop when I want to create multiple boxes with random width, height, position but that didn't work. How could I do that?
In you code there are two syntax error. first one is you didn't close for loop and second one is inside for loop first push operation was not close properly.
i have update code.
(function () {
var requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame;
window.requestAnimationFrame = requestAnimationFrame;
})();
var canvas = document.getElementById("canvas"),
ctx = canvas.getContext("2d"),
width = 1000,
height = 400,
player = {
x: width / 2,
y: height - 15,
width: 5,
height: 5,
speed: 3,
velX: 0,
velY: 0,
jumping: false,
grounded: false
},
keys = [],
friction = 0.8,
gravity = 0.3;
var boxes = [];
// dimensions
a = Math.floor((Math.random() * 20) + 1);
for (i = 0; i < a; i++) {
random1 = Math.floor((Math.random() * 1000) + 1);
random2 = Math.floor((Math.random() * 400) + 1);
random3 = Math.floor((Math.random() * 200) + 1);
random4 = Math.floor((Math.random() * 200) + 1);
boxes.push({
x: random1,
y: random2,
width: random3,
height: random4
});
boxes.push({
x: 0,
y: 0,
width: 10,
height: height
});
boxes.push({
x: 0,
y: height - 2,
width: width,
height: 50
});
boxes.push({
x: width - 10,
y: 0,
width: 50,
height: height
});
canvas.width = width;
canvas.height = height;
}
function update() {
// check keys
if (keys[38] || keys[32]) {
// up arrow or space
if (!player.jumping && player.grounded) {
player.jumping = true;
player.grounded = false;
player.velY = -player.speed * 2;
}
}
if (keys[39]) {
// right arrow
if (player.velX < player.speed) {
player.velX++;
}
}
if (keys[37]) {
// left arrow
if (player.velX > -player.speed) {
player.velX--;
}
}
player.velX *= friction;
player.velY += gravity;
ctx.clearRect(0, 0, width, height);
ctx.fillStyle = "black";
ctx.beginPath();
player.grounded = false;
for (var i = 0; i < boxes.length; i++) {
ctx.rect(boxes[i].x, boxes[i].y, boxes[i].width, boxes[i].height);
var dir = colCheck(player, boxes[i]);
if (dir === "l" || dir === "r") {
player.velX = 0;
player.jumping = false;
} else if (dir === "b") {
player.grounded = true;
player.jumping = false;
} else if (dir === "t") {
player.velY *= -1;
}
}
if(player.grounded){
player.velY = 0;
}
player.x += player.velX;
player.y += player.velY;
ctx.fill();
ctx.fillStyle = "red";
ctx.fillRect(player.x, player.y, player.width, player.height);
requestAnimationFrame(update);
}
function colCheck(shapeA, shapeB) {
// get the vectors to check against
var vX = (shapeA.x + (shapeA.width / 2)) - (shapeB.x + (shapeB.width / 2)),
vY = (shapeA.y + (shapeA.height / 2)) - (shapeB.y + (shapeB.height / 2)),
// add the half widths and half heights of the objects
hWidths = (shapeA.width / 2) + (shapeB.width / 2),
hHeights = (shapeA.height / 2) + (shapeB.height / 2),
colDir = null;
// if the x and y vector are less than the half width or half height, they we must be inside the object, causing a collision
if (Math.abs(vX) < hWidths && Math.abs(vY) < hHeights) {
// figures out on which side we are colliding (top, bottom, left, or right)
var oX = hWidths - Math.abs(vX),
oY = hHeights - Math.abs(vY);
if (oX >= oY) {
if (vY > 0) {
colDir = "t";
shapeA.y += oY;
} else {
colDir = "b";
shapeA.y -= oY;
}
} else {
if (vX > 0) {
colDir = "l";
shapeA.x += oX;
} else {
colDir = "r";
shapeA.x -= oX;
}
}
}
return colDir;
}
document.body.addEventListener("keydown", function (e) {
keys[e.keyCode] = true;
});
document.body.addEventListener("keyup", function (e) {
keys[e.keyCode] = false;
});
window.addEventListener("load", function () {
update();
});
<canvas id="canvas" widht=1000 height=400></canvas>

How can I make half the player come out on the other side?

Here's my code:
var canvas = document.getElementById("canvas")
var ctx = canvas.getContext("2d")
var w = canvas.width
var h = canvas.height
var player = {
x: w / 2,
y: h / 2,
r: 10,
vx: 0,
vy: 0,
speed: 5,
}
var keys = []
window.onkeydown = function(event) {keys[event.keyCode] = true}
window.onkeyup = function(event) {keys[event.keyCode] = false}
setInterval(update, 1000 / 60)
function update() {
if (keys[38] && player.vy > -player.speed) {
player.vy--
}
if (keys[40] && player.vy < player.speed) {
player.vy++
}
if (keys[37] && player.vx > -player.speed) {
player.vx--
}
if (keys[39] && player.vx < player.speed) {
player.vx++
}
player.vx *= 0.9
player.vy *= 0.9
player.x += player.vx
player.y += player.vy
ctx.clearRect(0,0,w,h)
ctx.beginPath()
ctx.arc(player.x, player.y, player.r, 0, Math.PI * 2, false)
ctx.fillStyle = "red"
ctx.fill()
}
http://jsfiddle.net/wfNse/
So, my question is, how can I make the player come out on the other side when you go out side of the bounds? Now this is pretty easily done, so there's one more thing, when half the player is out of the bounds, I want it to be seen half on both sides, like this:
You can do this :
// coordinates replaced in the board
player.x = (player.x+w)%w;
player.y = (player.y+h)%h;
// player position drawing
ctx.clearRect(0,0,w,h)
ctx.beginPath()
for (var i=-1; i<=1; i++) {
for (var j=-1; j<=1; j++) {
var x = player.x+i*w, y = player.y+j*h;
if (x+player.r<0 || x-player.r>w || y+player.r<0 || y-player.r>h) continue;
ctx.arc(x, y, player.r, 0, Math.PI * 2, false)
}
}
Demonstration

Categories

Resources