I know you can fillRect right? And you can clearRect. But what happens if there's an animation and you have to remove an object although it would be redrawn from setInterval. How would you remove the fillRect?
Here's an example:
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var width = canvas.width;
var height = canvas.height;
var circle = function (x, y, radius, fillCircle, color) {
ctx.beginPath();
ctx.fillStyle = color;
ctx.arc(x, y, radius, 0, Math.PI * 2, false);
if (fillCircle) {
ctx.fill();
} else {
ctx.stroke();
}
};
var drawRect = function (x, y, color) {
ctx.fillStyle = color;
ctx.fillRect(x, y, 20, 20)
}
var Object = function (xPos, yPos) {
this.x = xPos;
this.y = yPos;
}
// The Ball constructor
var Ball = function () {
this.x = width / 2;
this.y = height / 2;
this.xSpeed = 0;
this.ySpeed = 0;
this.radius = 10;
};
// Update the ball's position based on its speed
Ball.prototype.move = function () {
this.x += this.xSpeed;
this.y += this.ySpeed;
if (this.x < 11) {
this.x = 11;
} else if (this.x > width - 11) {
this.x = width - 11;
} else if (this.y < 11) {
this.y = 11;
} else if (this.y > height - 11) {
this.y = height - 11;
}
};
// Draw the ball at its current position
Ball.prototype.draw = function () {
circle(this.x, this.y, 10, true, "Black");
};
Object.prototype.draw = function () {
drawRect(this.x, this.y, "Black")
}
Object.prototype.drawKey = function (color) {
drawRect(this.x, this.y, "Yellow")
}
Object.prototype.checkCollision = function (direction) {
return (ball.x-ball.radius < this.x + 20)
&& (ball.x+ball.radius > this.x)
&& (ball.y-ball.radius < this.y + 20)
&& (ball.y+ball.radius > this.y)
;
}
function draw() {
ctx.clearRect(0, 0, width, height);
ball.draw();
object1.draw("Blue");
object2.draw();
object3.draw();
object4.draw();
object5.draw();
key.drawKey();
ctx.strokeRect(0, 0, width, height);
}
function simulate() {
for (z = 0; z < 5; z++) {
var prev_ball_x = ball.x;
var prev_ball_y = ball.y;
ball.move();
// handle collision here
if (object1.checkCollision() || object2.checkCollision() || object3.checkCollision() || object4.checkCollision() || object5.checkCollision()) {
ball.setDirection('stop');
// reset ball's position so they do not overlap
ball.x = prev_ball_x;
ball.y = prev_ball_y;
}
if (key.checkCollision()) {
ball.x = prev_ball_x;
ball.y = prev_ball_y;
}
}
$("body").keyup(function (event) {
ball.setDirection('stop');
})
}
setInterval(function () {
// separate drawing and simulating phases
simulate();
draw();
}, 30);
// Set the ball's direction based on a string
Ball.prototype.setDirection = function (direction) {
if (direction === "up") {
this.xSpeed = 0;
this.ySpeed = -1;
} else if (direction === "down") {
this.xSpeed = 0;
this.ySpeed = 1;
} else if (direction === "left") {
this.xSpeed = -1;
this.ySpeed = 0;
} else if (direction === "right") {
this.xSpeed = 1;
this.ySpeed = 0;
} else if (direction === "stop") {
this.xSpeed = 0;
this.ySpeed = 0;
}
};
// Create the ball object
var ball = new Ball();
var object1 = new Object(50, 0);
var object2 = new Object(50, 20);
var object3 = new Object(50, 40);
var object4 = new Object(50, 60);
var object5 = new Object(50, 80);
var key = new Object(70, 70);
// An object to convert keycodes into action names
var keyActions = {
37: "left",
38: "up",
39: "right",
40: "down"
};
// The keydown handler that will be called for every keypress
$("body").keydown(function (event) {
var direction = keyActions[event.keyCode];
ball.setDirection(direction);
});
<script src="https://code.jquery.com/jquery-2.1.0.js"></script>
<canvas id="canvas" width="800" height="200"></canvas>
You move around a ball with your arrow keys. When I collide with the yellow block, I want it to disappear. Using clearRect would not work simply because it would be redrawn in the setInterval. How would I make it disappear?
Generally when you have several items in a game you place them into a sort of objects array, then when you draw you loop through and call .draw() on each item. Doing it this way allows you to remove items you do not want (such as key), and as such it will no longer be drawn. In your case one thing we could do (assuming there is only a single key) is give your ball a hasKey property. And on collision set it from false to true. Then inside draw, if you wish to also remove the collisions you would do !ball.hasKey && key.checkCollision() inside your collision conditional for the key:
if(!ball.hasKey) key.drawKey();
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var width = canvas.width;
var height = canvas.height;
var circle = function (x, y, radius, fillCircle, color) {
ctx.beginPath();
ctx.fillStyle = color;
ctx.arc(x, y, radius, 0, Math.PI * 2, false);
if (fillCircle) {
ctx.fill();
} else {
ctx.stroke();
}
};
var drawRect = function (x, y, color) {
ctx.fillStyle = color;
ctx.fillRect(x, y, 20, 20)
}
var Object = function (xPos, yPos) {
this.x = xPos;
this.y = yPos;
}
// The Ball constructor
var Ball = function () {
this.x = width / 2;
this.y = height / 2;
this.xSpeed = 0;
this.ySpeed = 0;
this.radius = 10;
this.hasKey = false;
};
// Update the ball's position based on its speed
Ball.prototype.move = function () {
this.x += this.xSpeed;
this.y += this.ySpeed;
if (this.x < 11) {
this.x = 11;
} else if (this.x > width - 11) {
this.x = width - 11;
} else if (this.y < 11) {
this.y = 11;
} else if (this.y > height - 11) {
this.y = height - 11;
}
};
// Draw the ball at its current position
Ball.prototype.draw = function () {
circle(this.x, this.y, 10, true, "Black");
};
Object.prototype.draw = function () {
drawRect(this.x, this.y, "Black")
}
Object.prototype.drawKey = function (color) {
drawRect(this.x, this.y, "Yellow")
}
Object.prototype.checkCollision = function (direction) {
return (ball.x-ball.radius < this.x + 20)
&& (ball.x+ball.radius > this.x)
&& (ball.y-ball.radius < this.y + 20)
&& (ball.y+ball.radius > this.y)
;
}
function draw() {
ctx.clearRect(0, 0, width, height);
ball.draw();
object1.draw("Blue");
object2.draw();
object3.draw();
object4.draw();
object5.draw();
if(!ball.hasKey) key.drawKey();
ctx.strokeRect(0, 0, width, height);
}
function simulate() {
for (z = 0; z < 5; z++) {
var prev_ball_x = ball.x;
var prev_ball_y = ball.y;
ball.move();
// handle collision here
if (object1.checkCollision() || object2.checkCollision() || object3.checkCollision() || object4.checkCollision() || object5.checkCollision()) {
ball.setDirection('stop');
// reset ball's position so they do not overlap
ball.x = prev_ball_x;
ball.y = prev_ball_y;
}
if (!ball.hasKey && key.checkCollision()) {
ball.x = prev_ball_x;
ball.y = prev_ball_y;
ball.hasKey = true;
}
}
$("body").keyup(function (event) {
ball.setDirection('stop');
})
}
setInterval(function () {
// separate drawing and simulating phases
simulate();
draw();
}, 30);
// Set the ball's direction based on a string
Ball.prototype.setDirection = function (direction) {
if (direction === "up") {
this.xSpeed = 0;
this.ySpeed = -1;
} else if (direction === "down") {
this.xSpeed = 0;
this.ySpeed = 1;
} else if (direction === "left") {
this.xSpeed = -1;
this.ySpeed = 0;
} else if (direction === "right") {
this.xSpeed = 1;
this.ySpeed = 0;
} else if (direction === "stop") {
this.xSpeed = 0;
this.ySpeed = 0;
}
};
// Create the ball object
var ball = new Ball();
var object1 = new Object(50, 0);
var object2 = new Object(50, 20);
var object3 = new Object(50, 40);
var object4 = new Object(50, 60);
var object5 = new Object(50, 80);
var key = new Object(70, 70);
// An object to convert keycodes into action names
var keyActions = {
37: "left",
38: "up",
39: "right",
40: "down"
};
// The keydown handler that will be called for every keypress
$("body").keydown(function (event) {
var direction = keyActions[event.keyCode];
ball.setDirection(direction);
});
<script src="https://code.jquery.com/jquery-2.1.0.js"></script>
<canvas id="canvas" width="800" height="200"></canvas>
Related
Can you help with the code?
I'm creating a parkour game and everything went well but I got stuck on it:
as the cube will stand on the floor.
Here is my js code:
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
//Налаштування
var width = canvas.width;
var height = canvas.height;
var gameOver = function () {
clearInterval(intervalId);
ctx.font = "60px Caurier";
ctx.textAlign = "cener";
ctx.textBaseline = "middle";
ctxfillText("GAME OVER", width / 2, height / 2);
};
var cicle = function (x, y, radius, fillCircle) {
ctx.beginPath();
ctx.arc(x, y, radius, 0, Math.PI * 2, false);
if (fillCircle) {
ctx.fill();
} else {
ctx.stroke();
}
};
//Людина
//намалювати
function Draw() {
this.x = 10;
this.y = 10;
}
Draw.prototype.draw = function () {
ctx.beginPath();
ctx.moveTo(this.x, this.y);
ctx.lineTo(this.x + 50, this.y);
ctx.lineTo(this.x + 50, this.y + 50);
ctx.lineTo(this.x, this.y + 50);
ctx.lineTo(this.x, this.y);
ctx.fill();
}
Draw.prototype.move = function () {
if (this.x < 0) {
this.x = 0;
} else if (this.x > 1250) {
this.x = 1250;
}
if (this.y < 0) {
this.y = 0;
} else if (this.y > 450) {
this.y = 450;
}
while (this.y < 450) {
this.y++;
}
}
Draw.prototype.setDirection = function (direction) {
if (direction === "left") {
this.x = this.x - 10;
} else if (direction === "right") {
this.x = this.x + 10;
} else if (direction === "up") {
this.y = this.y - 150;
}
}
var person = new Draw;
var keyActions = {
37: "left",
38: "up",
39: "right"
};
$("body").keydown(function (event) {
var direction = keyActions[event.keyCode];
person.setDirection(direction);
});
setInterval(function () {
ctx.clearRect(0, 0, 1300, 500);
person.draw();
person.move();
//карта
var floor = ctx.strokeStyle = "LimeGreen"; ctx.lineWidth = 4; ctx.strokeRect(0, 312, 1300, 362);
}, 30);
I tried a lot but it didn't work out.
For example, I tried this:
first the code checks whether the cube and the floor are in the same coordinates, if so it reflects, if not, then no.I want the cube to be able to walk on the floor which is painted green, and not pass through it.
I am using the JavaScript canvas to make a pong-style game. I am attempting to use the values of the pong board's x and y grid values to create a prototype function for the ball to cause it to bounce off of the pong board whenever it touches. I have tried this a few different ways and I can't seem to get the ball to bounce off the pong board. I did not think that this aspect of the game's functionality would be the difficult part. I will provide snippets of the code below that I think are the problem:
var Pongboard = function() {
this.x = 15;
this.y = 15;
}
Ball.prototype.draw = function() {
makeBall(this.x, this.y, 5);
}
var pongboardValues = Object.values(Pongboard);
var pongX = pongboardValues[0];
var pongY = pongboardValues[1];
Ball.prototype.checkPongCollision = function() {
if (this.x < pongX && this.y < pongY) {
this.xSpeed = -this.xSpeed;
this.ySpeed = -this.ySpeed;
};
}
Any suggestions on how to get this working? Any hints would be greatly appreciated. If it helps, I will provide the full code below.
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var width = canvas.width;
var height = canvas.height;
//Create ball function
function makeBall (x, y, radius) {
ctx.beginPath();
ctx.arc(x, y, radius, 0, Math.PI*2, false);
ctx.fill();
}
//Create pong board function
function makePong (x, y) {
ctx.fillRect(x, y, 10, 60);
}
//Ball construcor function
var Ball = function() {
this.x = width;
this.y = height/2;
this.xSpeed = 6;
this.ySpeed = Math.random()*8 - 2;
}
//Pong board constructor function
var Pongboard = function() {
this.x = 15;
this.y = 15;
}
//These are the values for the Pongboard object's location
var pongboardValues = Object.values(Pongboard);
var pongX = pongboardValues[0];
var pongY = pongboardValues[1];
Ball.prototype.draw = function() {
makeBall(this.x, this.y, 5);
}
Ball.prototype.move = function() {
this.x += this.xSpeed;
this.y += this.ySpeed;
if (this.x < 0 || this.x > width) {
this.xSpeed = -this.xSpeed;
};
if (this.y < 0 || this.y > height) {
this.ySpeed = -this.ySpeed;
};
}
Ball.prototype.checkPongCollision = function() {
if (this.x < pongX && this.y < pongY) {
this.xSpeed = -this.xSpeed;
this.ySpeed = -this.ySpeed;
};
}
Pongboard.prototype.draw = function() {
makePong(this.x, this.y);
}
var keyNames = {
38: "up",
40: "down"
};
Pongboard.prototype.moveUpAndDown = function(direction) {
if (direction==="up") {
this.y = this.y += -1*10;
};
if (direction==="down") {
this.y = this.y += 10;
};
};
var ball = new Ball();
var pong = new Pongboard();
$("#start-button").click(function() {
setInterval(function() {
ctx.clearRect(0, 0, width, height);
pong.draw();
ball.draw();
ball.move();
ctx.strokeRect(0, 0, width, height);
}, 30);
})
$("body").keydown(function(event) {
var direction = keyNames[event.keyCode];
pong.moveUpAndDown(direction);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="start-button">Start</button><br>
<canvas width=300 height=200 id="canvas"></canvas>
Here I've got things working the way I think you want it.
You could extend this to make the ball bounce randomly on the Y axis too,..
I've commented out code that really wasn't doing anything too..
Also worth noting, you wasn't even calling checkPongCollision, so I've placed that in the timer.
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var width = canvas.width;
var height = canvas.height;
//Create ball function
function makeBall (x, y, radius) {
ctx.beginPath();
ctx.arc(x, y, radius, 0, Math.PI*2, false);
ctx.fill();
}
//Create pong board function
function makePong (x, y) {
ctx.fillRect(x, y, 10, 60);
}
//Ball construcor function
var Ball = function() {
this.x = width;
this.y = height/2;
this.xSpeed = 6;
this.ySpeed = Math.random()*8 - 2;
}
//Pong board constructor function
var Pongboard = function() {
this.x = 15;
this.y = 15;
}
//These are the values for the Pongboard object's location
//not needed..
//var pongboardValues = Object.values(Pongboard);
//var pongX = pongboardValues[0];
//var pongY = pongboardValues[1];
Ball.prototype.draw = function() {
makeBall(this.x, this.y, 5);
}
Ball.prototype.move = function() {
this.x += this.xSpeed;
this.y += this.ySpeed;
if (this.x < 0 || this.x > width) {
this.xSpeed = -this.xSpeed;
};
if (this.y < 0 || this.y > height) {
this.ySpeed = -this.ySpeed;
};
}
Ball.prototype.checkPongCollision = function() {
//if (this.x < pong.x && this.y < pong.y) {
if (
this.x >= pong.x && this.x < pong.x + 10 &&
this.y >= pong.y && this.y < pong.y + 60)
{
this.xSpeed = -this.xSpeed;
//this.ySpeed = -this.ySpeed;
};
}
Pongboard.prototype.draw = function() {
makePong(this.x, this.y);
}
var keyNames = {
38: "up",
40: "down"
};
Pongboard.prototype.moveUpAndDown = function(direction) {
if (direction==="up") {
this.y = this.y += -1*10;
};
if (direction==="down") {
this.y = this.y += 10;
};
};
var ball = new Ball();
var pong = new Pongboard();
$("#start-button").click(function() {
this.style.display = "none";
setInterval(function() {
ctx.clearRect(0, 0, width, height);
pong.draw();
ball.draw();
ball.move();
ctx.strokeRect(0, 0, width, height);
ball.checkPongCollision();
}, 30);
})
$("body").keydown(function(event) {
var direction = keyNames[event.keyCode];
pong.moveUpAndDown(direction);
});
body {
padding: 0;
margin: 0;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button style="float:left" id="start-button">Start</button>
<canvas width=300 height=180 id="canvas"></canvas>
I made this basic game where I drew a map and a player, the player can move anywhere but how can I make so that it wont move when its on the tile[1] in the map?
also when I try to check if the player.x is greater than 50 it could go left it works but than if I click 2 keys at once it goes through
const context = document.querySelector("canvas").getContext("2d");
var rgb = 'rgb(' + Math.random()*256 + ',' + Math.random()*256 + ',' + Math.random()*256 + ','+Math.random() + ')';
document.onload = Loop();
var width = 1500;
var height = 800;
function Loop(){
var width = 1500;
var height = 800;
context.canvas.height = height;
context.canvas.width = width;
this.interval = setInterval(Update, 1000/100);
}
const Player = function(x, y, w, h, color) {
this.x = x; this.y = y; this.w = w; this.h = h;
this.speedY = 0; this.speedX = 0;
this.Draw = function(){
context.fillStyle = this.color;
context.fillRect(this.x, this.y, this.w, this.h);
};
this.Move = function(){
this.x += this.speedX;
this.y += this.speedY;
};
};<code>
var player = new Player(100,100,50, 50, rgb);
var Key = {};
function Update(){
context.clearRect(0, 0, width, height);
Map();
player.Draw();
player.Move();
onkeydown = onkeyup = function(e){
player.speedX = 0;
player.speedY = 0;
e = e || event;
Key[e.keyCode] = e.type == 'keydown';
if(Key[37] || Key[65]) {player.speedX -= 2}
if(Key[38] || Key[87]) {player.speedY -= 2}
if(Key[39] || Key[68]) {player.speedX += 2}
if(Key[40] || Key[83]) {player.speedY += 2}
if(Key[32]) {player.color = 'rgb(' + Math.random()*256 + ',' + Math.random()*256 + ',' + Math.random()*256 + ','+Math.random()*1 + ')';}
};
}
var map = [
1, 1, 1, 1, 1,
1, 0, 0, 0, 1,
1, 0, 0, 0, 1,
1, 0, 0, 0, 1,
1, 1, 1, 1, 1
];
var row = 5;
var column = 5;
function Map(){
for(let y = -1; y < column; y++){
for(let x = -1; x < row; x++){
switch(map[((y*row) + x)]) {
case 0: context.fillStyle = player.color;
break;
case 1: context.fillStyle = "#ffffff";
break;
default: context.fillStyle = "#000000";
}
context.fillRect(x*50, y*50, 50, 50);
}
}
}
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<style>
body {
background-color: black;
}
canvas {
display: block;
margin: auto;
border: solid 1px white;
border-radius: 10px;
}
script {
display: none;
}
</style>
</head>
<body>
<canvas id="canvas"></canvas>
<script type="application/javascript">
void function() {
"use strict";
// Classes
function Camera(x,y) {
this.x = x || 0.0;
this.y = y || 0.0;
}
Camera.prototype = {
set: function(x,y) {
this.x = x || 0.0;
this.y = y || 0.0;
},
pan: function(x,y) {
this.x += x || 0.0;
this.y += y || 0.0;
}
};
var nextID = 0;
function Tile(colour) {
this.id = nextID++;
this.colour = colour || "black";
}
function Map(width,height) {
this.width = width || 1;
this.height = height || 1;
this.map = [];
this.map.length = this.height;
for (var y = 0; y < this.height; ++y) {
this.map[y] = [];
this.map[y].length = width;
for (var x = 0; x < this.width; ++x) {
this.map[y][x] = Math.random() < 0.2 ?
this.TILE_WALL:
this.TILE_GRASS;
}
this.map[y][0] = this.TILE_WALL;
this.map[y][this.width - 1] = this.TILE_WALL;
}
for (var x = 0; x < this.width; ++x) {
this.map[0][x] = this.TILE_WALL;
this.map[this.height - 1][x] = this.TILE_WALL;
}
}
Map.prototype = {
TILE_WIDTH: 32.0,
TILE_HEIGHT: 32.0,
INV_TILE_WIDTH: 0.0,
INV_TILE_HEIGHT: 0.0,
TILE_AIR: new Tile("#00000000"),
TILE_GRASS: new Tile("#00AA00FF"),
TILE_WALL: new Tile("#555555FF"),
set: function(x,y,tile) {
this.map[y][x] = tile;
},
scaleX: function(x) {
return (x * this.INV_TILE_WIDTH) | 0;
},
scaleY: function(y) {
return (y * this.INV_TILE_HEIGHT) | 0;
},
isColliding: function(x,y) {
return x > -1 && x < this.width
&& y > -1 && y < this.height
&& this.map[y][x].id > 1;
},
render: function(ctx,camera) {
for (var y = 0; y < this.height; ++y) {
for (var x = 0; x < this.width; ++x) {
var tile = this.map[y][x];
var _x = x * this.TILE_WIDTH - camera.x;
var _y = y * this.TILE_HEIGHT - camera.y;
ctx.fillStyle = tile.colour;
ctx.fillRect(_x,_y,this.TILE_WIDTH - 1,this.TILE_HEIGHT - 1);
}
}
}
};
Map.prototype.INV_TILE_WIDTH = 1.0 / Map.prototype.TILE_WIDTH;
Map.prototype.INV_TILE_HEIGHT = 1.0 / Map.prototype.TILE_HEIGHT;
function Player(x,y) {
this.x = x || 0.0;
this.y = y || 0.0;
this.dx = 0.0;
this.dy = 0.0;
this.isUp = false;
this.isDown = false;
this.isLeft = false;
this.isRight = false;
}
Player.prototype = {
WIDTH: 20.0,
HEIGHT: 20.0,
ACCELERATION: 1.0,
DEACCELERATION: 0.5,
MAX_SPEED: 3.0,
tick: function(map) {
// Movement
if (this.isUp) {
this.dy -= this.ACCELERATION;
if (this.dy < -this.MAX_SPEED) {
this.dy = -this.MAX_SPEED;
}
} else if (this.dy < 0.0) {
this.dy += this.DEACCELERATION;
if (this.dy > 0.0) {
this.dy = 0.0;
}
}
if (this.isDown) {
this.dy += this.ACCELERATION;
if (this.dy > this.MAX_SPEED) {
this.dy = this.MAX_SPEED;
}
} else if (this.dy > 0.0) {
this.dy -= this.DEACCELERATION;
if (this.dy < 0.0) {
this.dy = 0.0;
}
}
if (this.isLeft) {
this.dx -= this.ACCELERATION;
if (this.dx < -this.MAX_SPEED) {
this.dx = -this.MAX_SPEED;
}
} else if (this.dx < 0.0) {
this.dx += this.DEACCELERATION;
if (this.dx > 0.0) {
this.dx = 0.0;
}
}
if (this.isRight) {
this.dx += this.ACCELERATION;
if (this.dx > this.MAX_SPEED) {
this.dx = this.MAX_SPEED;
}
} else if (this.dx > 0.0) {
this.dx -= this.DEACCELERATION;
if (this.dx < 0.0) {
this.dx = 0.0;
}
}
// Collision
if (this.dx !== 0.0) {
var minY = map.scaleY(this.y);
var maxY = map.scaleY(this.y + this.HEIGHT);
var minX = 0;
var maxX = 0;
if (this.dx < 0.0) {
minX = map.scaleX(this.x + this.dx);
maxX = map.scaleX(this.x);
} else {
minX = map.scaleX(this.x + this.WIDTH);
maxX = map.scaleX(this.x + this.WIDTH + this.dx);
}
loop:
for (var y = minY; y <= maxY; ++y) {
for (var x = minX; x <= maxX; ++x) {
if (map.isColliding(x,y)) {
this.x = this.dx < 0.0 ?
(x + 1) * map.TILE_WIDTH:
x * map.TILE_WIDTH - this.WIDTH - 1;
this.dx = 0.0;
break loop;
}
}
}
}
if (this.dy !== 0.0) {
var minX = map.scaleX(this.x);
var maxX = map.scaleX(this.x + this.WIDTH);
var minY = 0;
var maxY = 0;
if (this.dy < 0.0) {
minY = map.scaleY(this.y + this.dy);
maxY = map.scaleY(this.y);
} else {
minY = map.scaleY(this.y + this.HEIGHT);
maxY = map.scaleY(this.y + this.HEIGHT + this.dy);
}
loop:
for (var y = minY; y <= maxY; ++y) {
for (var x = minX; x <= maxX; ++x) {
if (map.isColliding(x,y)) {
this.y = this.dy < 0.0 ?
(y + 1) * map.TILE_HEIGHT:
y * map.TILE_HEIGHT - this.HEIGHT - 1;
this.dy = 0.0;
break loop;
}
}
}
}
this.x += this.dx;
this.y += this.dy;
},
render: function(ctx,camera) {
camera.set(this.x,this.y);
ctx.lineWidth = 1;
ctx.strokeStyle = "black";
ctx.fillStyle = "darkred";
ctx.beginPath();
ctx.rect(this.x - camera.x,this.y - camera.y,this.WIDTH,this.HEIGHT);
ctx.fill();
ctx.stroke();
}
};
// Variables
var canvasWidth = 180;
var canvasHeight = 160;
var canvas = null;
var ctx = null;
var camera = null;
var map = null;
var player = null;
// Functions
function onKeyDown(e) {
switch(e.key.toUpperCase()) {
case "W": player.isUp = true; break;
case "S": player.isDown = true; break;
case "A": player.isLeft = true; break;
case "D": player.isRight = true; break;
}
}
function onKeyUp(e) {
switch(e.key.toUpperCase()) {
case "W": player.isUp = false; break;
case "S": player.isDown = false; break;
case "A": player.isLeft = false; break;
case "D": player.isRight = false; break;
}
}
function loop() {
// Tick
player.tick(map);
// Render
ctx.fillStyle = "gray";
ctx.fillRect(-canvasWidth >> 1,-canvasHeight >> 1,canvasWidth,canvasHeight);
map.render(ctx,camera);
player.render(ctx,camera);
//
requestAnimationFrame(loop);
}
// Entry point (first to execute)
onload = function() {
canvas = document.getElementById("canvas");
canvas.width = canvasWidth;
canvas.height = canvasHeight;
ctx = canvas.getContext("2d");
ctx.translate(canvasWidth >> 1,canvasHeight >> 1);
camera = new Camera(0.0,0.0);
map = new Map(10,10);
player = new Player(40.0,40.0);
map.set(1,1,map.TILE_GRASS);
addEventListener("keydown",onKeyDown);
addEventListener("keyup",onKeyUp);
loop();
}
}();
</script>
</body>
</html>
Firstly, looking at your code, there are some things that are missing which is required to implement basic collision detection and those are:
The player's current direction that he/she is moving in. This is important because it allows the function determining the collision detection to distinguish which side it is checking for the collision (Up, down, left, or right) since a player can only collide with one side at a time.
The tile's position and size. This is also very important because like the first point, there is only one side of the tile that the player can collide with and knowing the size and position can determine if it is a collision or not based on the players size and position.
Also, since you mentioned it is a basic game, the implementation below is a basic collision detection. If you were to make a more complex and bigger game, you should try looking into quad trees for more efficient collision detection:
https://gamedevelopment.tutsplus.com/tutorials/quick-tip-use-quadtrees-to-detect-likely-collisions-in-2d-space--gamedev-374
Now this is the function for detecting collision, for the sake of readability and shortness, p will represent the player object and t would represent the tile object. This function returns whether or not the player is colliding with a tile based on their direction of movement.
function isColliding(p, t){
if (p.direction == 'up') {
return p.y +(p.height/2)-p.speedY< t.y + t.height && p.y > t.y
&& p.x + p.width > t.x && p.x < t.x + t.width;
}
if (p.direction == 'down') {
return p.y + (p.height/2)+p.speedY > t.y && p.y < t.y
&& p.x + p.width > t.x && p.x < t.x + t.width;
}
if (p.direction == 'right') {
return p.x + p.width+p.speedX > t.x && p.x < t.x
&& p.y +(p.height/2)> t.y && p.y + p.height < t.y +t.height+ (p.height / 2);
}
if (p.direction == 'left') {
return p.x -p.speedX< t.x + t.width && p.x > t.x
&& p.y +(p.height/2)> t.y && p.y + p.height < t.y +t.height+ (p.height / 2);
}
return false;
}
You would probably want to put this in the player move function to constantly detect for tiles as it is moving. To do that, you'd want to modify your keydown detection so that with each different keydown, it would update the player's direction, here's a simple example:
document.onkeydown = function(event){
if (event.keyCode == 87)
player.up = true;
else if (event.keyCode == 65)
player.left = true;
else if (event.keyCode == 83)
player.down = true;
else if (event.keyCode == 68)
player.right = true;
}
and another simple example for every time the player moves (user presses a keydown):
const Player= function(/*Param stuff*/){
/*Property stuff*/
//tileArray is the array (or object, your choice) of all the current tiles in the map
this.move=function(tileArray){
//Go through all tiles to see if player is colliding with any of them
for(var t in tileArray){
if(this.up){
if(isColliding(this, tileArray[t]){
//functionality for when player collides
}else{
//functionality for when player doesn't collide
}
}
//check if player is going down, left, etc
}
}
}
These are just examples of how to implement the detection. You should use it as a reference to implement it relatively to how your code function because I didn't write it based on what you posted.
PS.
Make sure to also convert the directions to false after the user stops pressing the key.
This question already has an answer here:
Comparing x/y of two positions on a canvas
(1 answer)
how to make a canvas element follow another canvas element smoothly at the same speed [duplicate]
Closed 6 years ago.
I'm wondering today how to make a canvas element follow another canvas element smoothly. For example, I'm trying to make a game where a canvas element continually follows the player (which can be moved using W, A, S, & D) smoothly. I had an idea to use the Pythagorean theorem to check for the closest & fastest way to move from Point A (the canvas element) to Point B (the player). However, I have no physical way to do this. Does anyone have any ideas or answers of how I could make a canvas element constantly follow a player as smoothly as possible so it reaches the player the fastest?
Here I have an example of a very bad way of following:
<!DOCTYPE html>
<html>
<head>
<title>Target Following Test</title>
</head>
<body>
<script src="https://code.jquery.com/jquery-2.1.0.js"></script>
<center>
<canvas id="canvas" width="800" height="500"></canvas>
</center>
<script>
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var width = canvas.width;
var height = canvas.height;
var circle = function(x, y, radius, fillCircle, color) {
ctx.beginPath();
ctx.fillStyle = color;
ctx.arc(x, y, radius, 0, Math.PI * 2, false);
if (fillCircle) {
ctx.fill();
} else {
ctx.stroke();
}
};
var drawRect = function(x, y, color) {
ctx.fillStyle = color;
ctx.fillRect(x, y, 20, 20)
}
//Moving Obstacle
var Obstacle = function(x, y) {
this.x = x;
this.y = y;
this.vSpeed = 0;
this.hSpeed = 0;
}
Obstacle.prototype.drawOb = function(color) {
drawRect(this.x, this.y, "Red")
}
Obstacle.prototype.follow = function() {
this.y += this.vSpeed
this.x += this.hSpeed
if (this.x < ball.x - 9) {
this.hSpeed = 1;
}
if (this.x > ball.x - 10) {
this.hSpeed = -1;
}
if (this.y > ball.y - 10) {
this.vSpeed = -1;
}
if (this.y < ball.y - 9) {
this.vSpeed = 1;
}
}
Obstacle.prototype.checkCollision = function(direction) {
return (ball.x - ball.radius < this.x + 20) &&
(ball.x + ball.radius > this.x) &&
(ball.y - ball.radius < this.y + 20) &&
(ball.y + ball.radius > this.y);
}
// The Ball constructor
var Ball = function() {
this.x = 20
this.y = 20
this.xSpeed = 0;
this.ySpeed = 0;
this.radius = 10;
};
// Draw the ball at its current position
Ball.prototype.draw = function() {
circle(this.x, this.y, 10, true, "Black");
};
Ball.prototype.reposition = function(reX, reY) {
this.x = reX;
this.y = reY;
}
// Update the ball's position based on its speed
Ball.prototype.move = function() {
this.x += this.xSpeed;
this.y += this.ySpeed;
if (this.x < 11) {
this.x = 11;
} else if (this.x > width - 11) {
this.x = width - 11;
} else if (this.y < 11) {
this.y = 11;
} else if (this.y > height - 11) {
this.y = height - 11;
}
};
// Set the ball's direction based on a string
Ball.prototype.setDirection = function(direction) {
if (direction === "up") {
this.xSpeed = 0;
this.ySpeed = -2;
} else if (direction === "down") {
this.xSpeed = 0;
this.ySpeed = 2;
} else if (direction === "left") {
this.xSpeed = -2;
this.ySpeed = 0;
} else if (direction === "right") {
this.xSpeed = 2;
this.ySpeed = 0;
} else if (direction === "stop") {
this.xSpeed = 0;
this.ySpeed = 0;
}
};
function simulate() {
var prev_ball_x = ball.x;
var prev_ball_y = ball.y;
var prev_fol_x = follower.x;
var prev_fol_y = follower.y;
ball.move();
follower.follow()
if (follower.checkCollision()) {
ball.setDirection('stop');
follower.vSpeed = 0;
follower.hSpeed = 0;
follower.x = prev_fol_x;
follower.y = prev_fol_y;
ball.x = prev_ball_x;
ball.y = prev_ball_y;
}
}
function draw() {
ctx.clearRect(0, 0, width, height);
ball.draw();
follower.drawOb();
ctx.strokeRect(0, 0, width, height);
}
// An object to convert keycodes into action names
var keyActions = {
37: "left",
38: "up",
39: "right",
40: "down"
};
// The keydown handler that will be called for every keypress
$("body").keydown(function(event) {
var direction = keyActions[event.keyCode];
ball.setDirection(direction);
});
$("body").keyup(function(event) {
ball.setDirection('stop');
})
setInterval(function() {
// separate drawing and simulating phases
simulate();
draw();
}, 10);
// Create all the Objects!
var ball = new Ball();
var follower = new Obstacle(400, 100);
</script>
</body>
</html>
Note: i haven't really inspected your code...
But hopefully I understand your question correctly. And if I do, the solution could be pretty simple.
The most simple and fast way is to move the canvas element in a straight line to the player, without the help of mr Pythagoras. For that you need to know the player's position (x, y), which you do.
I took an easing function from an AS3 question, but it's the same for JS: AS 3 simple ease
On every update, ease the follower to the position of the player:
follower.x += (player.x - follower.x) / delay;
follower.y += (player.y - follower.y) / delay;
Example: Fiddle
It isn't a drop-in fix for your script, but hopefully it's helpful
I've been trying to make a game but there are obstacles. I have a (ball) player and a square (obstacle) and I can't figure out how to make a collision detection thing to work. Here's my code so far:
<!DOCTYPE html>
<html>
<head>
<title>Ball Race</title>
</head>
<body>
<script src="https://code.jquery.com/jquery-2.1.0.js"></script>
<canvas id="canvas" width="800" height="200"></canvas>
<script>
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var width = canvas.width;
var height = canvas.height;
var circle = function (x, y, radius, fillCircle) {
ctx.beginPath();
ctx.arc(x, y, radius, 0, Math.PI * 2, false);
if (fillCircle) {
ctx.fill();
} else {
ctx.stroke();
}
};
var drawRect = function (x, y) {
ctx.fillRect(x, y, 20, 20)
}
var Object = function () {
this.x = width / 4;
this.y = height / 4;
}
// The Ball constructor
var Ball = function () {
this.x = width / 2;
this.y = height / 2;
this.xSpeed = 5;
this.ySpeed = 0;
};
// Update the ball's position based on its speed
Ball.prototype.move = function () {
this.x += this.xSpeed;
this.y += this.ySpeed;
if (this.x < 11) {
this.x = 11;
} else if (this.x > width - 11) {
this.x = width - 11;
} else if (this.y < 11) {
this.y = 11;
} else if (this.y > height - 11) {
this.y = height - 11;
}
};
// Draw the ball at its current position
Ball.prototype.draw = function () {
circle(this.x, this.y, 10, true);
};
Object.prototype.draw = function () {
drawRect(this.x, this.y)
}
//collision types
Object.prototype.checkCollision = function () {
var col1 = this.x == ball.x && this.y == ball.y;
var col2 = this.x + 1 == ball.x && this.y == ball.y;
var col3 = this.x + 2 == ball.x && this.y == ball.y;
var col4 = this.x + 3 == ball.x && this.y == ball.y;
if (col1 || col2 || col3 || col4) {
alert("COLLISION!");
}
}
// Set the ball's direction based on a string
Ball.prototype.setDirection = function (direction) {
if (direction === "up") {
this.xSpeed = 0;
this.ySpeed = -5;
} else if (direction === "down") {
this.xSpeed = 0;
this.ySpeed = 5;
} else if (direction === "left") {
this.xSpeed = -5;
this.ySpeed = 0;
} else if (direction === "right") {
this.xSpeed = 5;
this.ySpeed = 0;
} else if (direction === "stop") {
this.xSpeed = 0;
this.ySpeed = 0;
}
};
// Create the ball object
var ball = new Ball();
var object = new Object();
// An object to convert keycodes into action names
var keyActions = {
32: "stop",
37: "left",
38: "up",
39: "right",
40: "down"
};
// The keydown handler that will be called for every keypress
$("body").keydown(function (event) {
var direction = keyActions[event.keyCode];
ball.setDirection(direction);
});
// The animation function, called every 30 ms
setInterval(function () {
ctx.clearRect(0, 0, width, height);
ball.draw();
ball.move();
object.draw();
ctx.strokeRect(0, 0, width, height);
}, 30);
setInterval(function () {
object.checkCollision();
}, 1)
</script>
</body>
</html>
How would you code this? Please give an example similar to mine.
It seems like most of the functionality is there you're just missing the correct logic in the checkCollision. I would change it to something like:
Object.prototype.checkCollision = function() {
var colx = (ball.x-ball.radius<this.x&&ball.x+ball.radius>this.x)||(ball.x-ball.radius<this.x+20&&ball.x+ball.radius>this.x+20);
var coly = (ball.y-ball.radius<this.y&&ball.y+ball.radius>this.y)||(ball.y-ball.radius<this.y+20&&ball.y+ball.radius>this.y+20);
if(colx&&coly){
console.log('collision');
}
}
colx checks the x collision, to see if the ball is in between the objects position. coly does the same thing but for the y variable. If both are true then there is a collision.
I added radius variable to Ball
var Ball = function() {
this.x = width / 2;
this.y = height / 2;
this.xSpeed = 5;
this.ySpeed = 0;
this.radius = 10;
};
Here is a fiddle