I'm creating a basic game that draws squares at random positions on a canvas, but sometimes the shape gets cut off because it's outside of the canvas' boundaries. Can any one explain how I could go about getting the square to be drawn on the other side of the canvas (similar to how it's done in asteroids)? The searches I've come up with haven't been helpful. Any help is appreciated.
OK I think I've solved this one. Basically this code only draws the square whilst it is inside the canvas, if it leaves the canvas it checks which boundaries it is leaving and updates the position. The looped variable is needed because otherwise the square will be always leaving the canvas.
var canvas = document.getElementById('bg');
var ctx = canvas.getContext('2d');
var squares = [];
squares[squares.length] = new Square(200, 200, 20, 'red', 0.785398164);
function Square(x, y, size, colour, angle)
{
this.x = x;
this.y = y;
this.size = size;
this.colour = colour;
this.speed = 5;
this.angle = angle;
this.looped = false;
}
Square.prototype.update = function()
{
this.x += (Math.cos(this.angle) * this.speed);
this.y += (Math.sin(this.angle) * this.speed);
if (this.x < canvas.width && this.x + this.size > 0 &&
this.y < canvas.height && this.y + this.size > 0)
{
this.draw();
this.looped = false;
}
else
{
if (this.x > canvas.width && !this.looped)
{
this.x = -this.size;
}
if (this.x + this.size < 0 && !this.looped)
{
this.x = this.size + canvas.width;
}
if (this.y > canvas.height && !this.looped)
{
this.y = -this.size;
}
if (this.y + this.size < 0 && !this.looped)
{
this.y = this.size + canvas.height;
}
this.looped = true;
}
}
Square.prototype.draw = function()
{
ctx.fillStyle = this.colour;
ctx.fillRect(this.x, this.y, this.size, this.size);
}
function gameLoop()
{
ctx.clearRect(0, 0, canvas.width, canvas.height);
for (var i = 0; i < squares.length; i++)
{
squares[i].update();
}
requestAnimationFrame(gameLoop);
}
gameLoop();
(function()
{
// http://paulirish.com/2011/requestanimationframe-for-smart-animating/
var lastTime = 0;
var vendors = ['ms', 'moz', 'webkit', 'o'];
for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x)
{
window.requestAnimationFrame = window[vendors[x]+'RequestAnimationFrame'];
window.cancelAnimationFrame = window[vendors[x]+'CancelAnimationFrame'] || window[vendors[x]+'CancelRequestAnimationFrame'];
}
if (!window.requestAnimationFrame) window.requestAnimationFrame = function(callback, element)
{
var currTime = new Date().getTime();
var timeToCall = Math.max(0, 16 - (currTime - lastTime));
var id = window.setTimeout(function()
{
callback(currTime + timeToCall);
}, timeToCall);
lastTime = currTime + timeToCall;
return id;
};
if (!window.cancelAnimationFrame) window.cancelAnimationFrame = function(id)
{
clearTimeout(id);
};
}());
I'd do a JSFiddle but requestAnimationFrame doesn't play nice with it.
Related
I'm trying to create an idle animation where the red rectangle moves back and forth slightly in a loop. For some reason once it reaches the specified threshhold instead of proceeding to move in the opposite direction, it just stops.
What did I do wrong?
<canvas id="myCanvas" width="1500" height="500" style="border:1px solid #c3c3c3;">
Your browser does not support the canvas element.
</canvas>
<script>
var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
// Spaceship structure
var shipWidth = 250;
var shipHeight = 100;
// Canvas parameters
var cWidth = canvas.width;
var cHeight = canvas.height;
// Positioning variables
var centerWidthPosition = (cWidth / 2) - (shipWidth / 2);
var centerHeightPosition = (cHeight / 2) - (shipHeight / 2);
var requestAnimationFrame = window.requestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.msRequestAnimationFrame;
function drawShip(){
ctx.clearRect(0, 0, cWidth, cHeight);
ctx.fillStyle = "#FF0000";
ctx.fillRect(centerWidthPosition,centerHeightPosition,shipWidth,shipHeight);
centerWidthPosition--;
if (centerWidthPosition < 400){
++centerWidthPosition;
}
requestAnimationFrame(drawShip);
}
drawShip();
</script>
#TheAmberlamps explained why it's doing that. Here I offer you a solution to achieve what I believe you are trying to do.
Use a velocity variable that changes magnitude. X position always increases by velocity value. Velocity changes directions at screen edges.
// use a velocity variable
var xspeed = 1;
// always increase by velocity
centerWidthPosition += xspeed;
// screen edges are 0 and 400 in this example
if (centerWidthPosition > 400 || centerWidthPosition < 0){
xspeed *= -1; // change velocity direction
}
I added another condition in your if that causes the object to bounce back and forth. Remove the selection after || if you don't want it doing that.
Your function is caught in a loop; once centerWidthPosition reaches 399 your conditional makes it increment back up to 400, and then it decrements back to 399.
here is another one as a brain teaser - how would go by making this animation bounce in the loop - basically turn text into particles and then reverse back to text and reverse back to particles and back to text and so on and on and on infinitely:
var random = Math.random;
window.onresize = function () {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
};
window.onresize();
var ctx = canvas.getContext('2d');
ctx.font = 'bold 50px "somefont"';
ctx.textBaseline = 'center';
ctx.fillStyle = 'rgba(255,255,255,1)';
var _particles = [];
var particlesLength = 0;
var currentText = "SOMETEXT";
var createParticle = function createParticle(x, y) {_particles.push(new Particle(x, y));};
var checkAlpha = function checkAlpha(pixels, i) {return pixels[i * 4 + 3] > 0;};
var createParticles = function createParticles() {
var textSize = ctx.measureText(currentText);
ctx.fillText(currentText,Math.round((canvas.width / 2) - (textSize.width / 2)),Math.round(canvas.height / 2));
var imageData = ctx.getImageData(1, 1, canvas.width, canvas.height);
var pixels = imageData.data;
var dataLength = imageData.width * imageData.height;
for (var i = 0; i < dataLength; i++) {
var currentRow = Math.floor(i / imageData.width);
var currentColumn = i - Math.floor(i / imageData.height);
if (currentRow % 2 || currentColumn % 2) continue;
if (checkAlpha(pixels, i)) {
var cy = ~~(i / imageData.width);
var cx = ~~(i - (cy * imageData.width));
createParticle(cx, cy);
}}
particlesLength = _particles.length;
};
var Point = function Point(x, y) {
this.set(x, y);
};
Point.prototype = {
set: function (x, y) {
x = x || 0;
y = y || x || 0;
this._sX = x;
this._sY = y;
this.reset();
},
add: function (point) {
this.x += point.x;
this.y += point.y;
},
multiply: function (point) {
this.x *= point.x;
this.y *= point.y;
},
reset: function () {
this.x = this._sX;
this.y = this._sY;
return this;
},
};
var FRICT = new Point(0.98);//set to 0 if no flying needed
var Particle = function Particle(x, y) {
this.startPos = new Point(x, y);
this.v = new Point();
this.a = new Point();
this.reset();
};
Particle.prototype = {
reset: function () {
this.x = this.startPos.x;
this.y = this.startPos.y;
this.life = Math.round(random() * 300);
this.isActive = true;
this.v.reset();
this.a.reset();
},
tick: function () {
if (!this.isActive) return;
this.physics();
this.checkLife();
this.draw();
return this.isActive;
},
checkLife: function () {
this.life -= 1;
this.isActive = !(this.life < 1);
},
draw: function () {
ctx.fillRect(this.x, this.y, 1, 1);
},
physics: function () {
if (performance.now()<nextTime) return;
this.a.x = (random() - 0.5) * 0.8;
this.a.y = (random() - 0.5) * 0.8;
this.v.add(this.a);
this.v.multiply(FRICT);
this.x += this.v.x;
this.y += this.v.y;
this.x = Math.round(this.x * 10) / 10;
this.y = Math.round(this.y * 10) / 10;
}
};
var nextTime = performance.now()+3000;
createParticles();
function clearCanvas() {
ctx.fillStyle = 'rgba(0,0,0,1)';
ctx.fillRect(0, 0, canvas.width, canvas.height);
}
(function clearLoop() {
clearCanvas();
requestAnimationFrame(clearLoop);
})();
(function animLoop(time) {
ctx.fillStyle = 'rgba(255,255,255,1)';
var isAlive = true;
for (var i = 0; i < particlesLength; i++) {
if (_particles[i].tick()) isAlive = true;
}
requestAnimationFrame(animLoop);
})();
function resetParticles() {
for (var i = 0; i < particlesLength; i++) {
_particles[i].reset();
}}
I created a game using Javascript. It is a game where a circle which can be controlled by the mouse, has to navigate through moving obstacles similar to a maze. When the circle hits an obstacle, the game should stop.
When i tried the same game but with one obstacle, it worked. But after adding more lines of code to create more obstacles, the circle and the obstacle doesn't appear in the output. Also, the crashWith function isn't being called when the circle hits the obstacle.
Here is the code:
<!DOCTYPE html>
<html>
<style>
canvas {
border:1px solid #000000;
background-image: url("https://data.whicdn.com/images/223851992/large.jpg");
}
</style>
<body onload="begin()">
<script>
var gamePiece;
var gameObstacle = [];
function begin(){
gameArea.start();
gamePiece = new piece(10, "white", 20, 135);
}
var gameArea = {
canvas : document.createElement("canvas"),
start : function(){
this.canvas.width = 480;
this.canvas.height = 270;
this.canvas.style.cursor= 'none';
this.context = this.canvas.getContext("2d");
document.body.insertBefore( this.canvas, document.body.childNodes[0]);
this.frameNo = 0;
this.interval = setInterval(updateGame , 10); //for each frame
window.addEventListener('mousemove', function(n){
gameArea.x = n.pageX;
gameArea.y = n.pageY;
});
},
clear : function(){
this.context.clearRect(0,0, this.canvas.width, this.canvas.height);
},
stop : function(){
clearInterval(this.interval);
}
}
function eachInterval(e){
if((gameArea.frameNo / e) % 1 == 0)
return true;
else
return false;
}
//for circle
function piece (radius, color, x, y){
this.radius = radius;
this.speedx = 0;
this.speedy =0;
this.x = x;
this.y = y;
this.update = function(){
pieceContext = gameArea.context;
pieceContext.beginPath();
pieceContext.arc( this.x, this.y, this.radius, 0, 2 * Math.PI);
pieceContext.fillStyle = color;
pieceContext.fill();
}
this.newPlace = function(){
this.x += this.speedx;
this.y += this.speedy;
}
}
//for obstacle
function obstacle (width, height, color, x, y){
this.width = width;
this.height = height;
this.speedx = 0;
this.speedy =0;
this.x = x;
this.y = y;
this.update = function(){
obstacleContext = gameArea.context;
obstacleContext.fillStyle = color;
obstacleContext.fillRect(this.x, this.y, this.width, this.height);
}
this.newPlace = function(){
this.x += this.speedx;
this.y += this.speedy;
}
//check crash
this.crashWith = function(gamePiece){
var collide = true;
var otherleft = this.x;
var otherright = this.x + (this.width);
var othertop = this.y;
var otherbottom = this.y + (this.height);
var circleBottom = gamePiece.y + (gamePiece.radius);
var circleTop = gamePiece.y;
var circleLeft = gamePiece.x;
var circleRight = gamePiece.x + (gamePiece.radius);
if ((circleBottom < othertop) || (circleTop > otherbottom) || (circleRight < otherleft) || (circleLeft > otherright)) {
collide = false;
}
return collide;
}
}
function updateGame(){
var x,y;
for(i=0 ; i<gameObstacle.length ; i++){
if (gameObstacle[i].crashWith(gamePiece)){
gameArea.stop();
return;
}
}
gameArea.clear();
gameArea.frameNo +=1 ;
if(gameArea.frameNo == 1 || eachInterval(150)){
x = gameArea.canvas.width;
y = gameArea.canvas.height - 200;
gameObstacle.push(new obstacle(10, 200, "grey", x, y));
}
for(i=0 ; i<gameObstacle.length ; i++){
gameObstacle[i].x -= 1;
gameObstacle[i].update();
}
gameObstacle.x -= 1;
//giving co ordinates of cursor to game piece
gamePiece.x = gameArea.x;
gamePiece.y = gameArea.y;
gamePiece.update();
gamePiece.newPlace();
}
</script>
</body>
</html>
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.
I am trying to modified this effect to work within my canvas. However, I can't seem to get the mouse position to work properly. The hover area isn't contained to my canvas.
Here's a CSSdeck of how i tried to implement it: http://cssdeck.com/labs/ukktjtis
Effect:
function hoverText(){
window.requestAnimFrame = (function(){
return window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame ||
function( callback ){
window.setTimeout(callback, 1000 / 60);
};
})();
var canvas = document.getElementById("canvas"),
ctx = canvas.getContext("2d"),
keyword = "MacroPlay Games",
imageData,
density = 3,
mouse = {},
hovered = false,
colors = ["0,120,232", "8,200,255", "30,140,255"],
minDist = 20,
bounceFactor = 0.7;
var W = window.innerWidth, H = window.innerHeight;
canvas.width = W;
canvas.height = H;
document.addEventListener("mousemove", function(e) {
mouse.x = e.pageX-50;
mouse.y = e.pageY+200;
}, false);
// Particle Object
var Particle = function() {
this.w = Math.random() * 10.5;
this.h = Math.random() * 10.5;
this.x = -W;
this.y = -H;
this.free = false;
this.vy = -5 + parseInt(Math.random() * 10) / 2;
this.vx = -4 + parseInt(Math.random() * 8);
// Color
this.a = Math.random();
this.color = colors[parseInt(Math.random()*colors.length)];
this.setPosition = function(x, y) {
this.x = x;
this.y = y;
};
this.draw = function() {
ctx.fillStyle = "rgba("+this.color+","+this.a+")";
ctx.fillRect(this.x, this.y, this.w, this.h);
}
};
var particles = [];
// Draw the text
function drawText() {
ctx.clearRect(0, 0, W, H);
ctx.fillStyle = "#000000";
ctx.font = "100px 'Arial', sans-serif";
ctx.textAlign = "center";
ctx.fillText(keyword, W/2, H/2);
}
// Clear the canvas
function clear() {
ctx.clearRect(0, 0, W, H);
}
// Get pixel positions
function positionParticles() {
// Get the data
imageData = ctx.getImageData(0, 0, W, W);
data = imageData.data;
// Iterate each row and column
for (var i = 0; i < imageData.height; i += density) {
for (var j = 0; j < imageData.width; j += density) {
// Get the color of the pixel
var color = data[((j * ( imageData.width * 4)) + (i * 4)) - 1];
// If the color is black, draw pixels
if (color == 255) {
particles.push(new Particle());
particles[particles.length - 1].setPosition(i, j);
}
}
}
}
drawText();
positionParticles();
// Update
function update() {
clear();
for(i = 0; i < particles.length; i++) {
var p = particles[i];
if(mouse.x > p.x && mouse.x < p.x + p.w && mouse.y > p.y && mouse.y < p.y + p.h)
hovered = true;
if(hovered == true) {
var dist = Math.sqrt((p.x - mouse.x)*(p.x - mouse.x) + (p.y - mouse.y)*(p.y - mouse.y));
if(dist <= minDist)
p.free = true;
if(p.free == true) {
p.y += p.vy;
p.vy += 0.15;
p.x += p.vx;
// Collision Detection
if(p.y + p.h > H) {
p.y = H - p.h;
p.vy *= -bounceFactor;
// Friction applied when on the floor
if(p.vx > 0)
p.vx -= 0.1;
else
p.vx += 0.1;
}
if(p.x + p.w > W) {
p.x = W - p.w;
p.vx *= -bounceFactor;
}
if(p.x < 0) {
p.x = 0;
p.vx *= -0.5;
}
}
}
ctx.globalCompositeOperation = "lighter";
p.draw();
}
}
(function animloop(){
requestAnimFrame(animloop);
update();
})();
}
It's highly advised you use jquery (or some js lib) to avoid cross-browser issues like getting the mouse position.
You can easily get the mouse position in any browser using jquery like this:
// get the position of the canvas relative to the web page
var canvasOffset=$("#canvas").offset();
var offsetX=canvasOffset.left;
var offsetY=canvasOffset.top;
// then in the mouse handler, get the exact mouse position like this:
function handleMouseDown(e){
mouseX=parseInt(e.clientX-offsetX);
mouseY=parseInt(e.clientY-offsetY);
// Put your mousedown stuff here
}
// tell the browser to send mousedown events to the handleMouseDown function
$("#canvas").mousedown(function(e){handleMouseDown(e);});
I personally prefer a library like hammer.js. I've use it for all my projects - check it out, it's pretty good.