Making an object move on canvas in JavaScript - javascript

I am trying to make a simple game in JavaScript in which you move an object (circle/ball) around on canvas using arrow keys. I have spent a lot of time researching and coding, but without luck so far, so I hope you guys can help me. For now, I am simply trying to move the object/ball around using arrow keys [up, down, left, right]. Anybody able to figure out, why this doesn't work? Thank you very much in advance.
var canvas = document.getElementById("mycanvas");
var ctx = canvas.getContext("2d");
canvas.width = canvas.height = 500;
//the circle
function circle() {
ctx.beginPath();
ctx.arc(50, 50, 25, 0, Math.PI * 2, true);
ctx.fillStyle = "blue";
ctx.fill();
}
circle();
//move function for going left
window.addEventListener("keydown", function(event) {
if (event.keyCode == 37) {
circle.x = 1;
}
})

You could accomplish such movement in the following way ...
var canvas = document.getElementById("mycanvas");
var ctx = canvas.getContext("2d");
var x = 50,
y = 50,
radius = 15,
speed = 3;
function circle() {
ctx.beginPath();
ctx.arc(x, y, radius, 0, Math.PI * 2, true);
ctx.fillStyle = "#07C";
ctx.fill();
}
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
circle();
requestAnimationFrame(draw);
}
draw();
window.addEventListener("keydown", function(e) {
switch (e.key) {
case 'ArrowUp':
if (y > radius) y -= speed;
break;
case 'ArrowDown':
if (y < canvas.height - radius) y += speed;
break;
case 'ArrowLeft':
if (x > radius) x -= speed;
break;
case 'ArrowRight':
if (x < canvas.width - radius) x += speed;
break;
}
});
canvas {
border: 1px solid black;
}
<canvas id="mycanvas" width="200" height="200"></canvas>
apology for not giving any explanation

Related

How do I increase the speed of my ball movement, but keep the smooth animation

Right now, my ball moves very slowly, at 1px on w, a, s, or d click. I don't really want to do a setInterval function. I'm not sure what to do to make my ball move faster, but still at 1px for a second. Alternatively, maybe someone could show me how to make smooth ball movement but still at higher speeds, like 10px? Thanks a ton!
var canvas = document.getElementById("canvas")
var ctx = canvas.getContext('2d')
canvas.width = window.screen.width
canvas.height = window.screen.height
var x = canvas.width / 2;
var y = canvas.height / 2;
r = 50;
var dx = 1;
var dy = -1;
ctx.beginPath();
ctx.arc(x, y, r, 0, 2 * Math.PI);
ctx.stroke();
window.onkeypress = function(e) {
console.log(e.keyCode)
if (e.keyCode == 119) {
function drawCircle() {
ctx.beginPath();
ctx.arc(x, y, r, 0, 2 * Math.PI);
ctx.stroke();
}
ctx.clearRect(0, 0, canvas.width, canvas.height)
window.requestAnimationFrame(drawCircle)
y += dy
} else if (e.keyCode == 97) {
function drawCircle() {
ctx.beginPath();
ctx.arc(x, y, r, 0, 2 * Math.PI);
ctx.stroke();
}
ctx.clearRect(0, 0, canvas.width, canvas.height)
window.requestAnimationFrame(drawCircle)
x -= dx
} else if (e.keyCode == 115) {
function drawCircle() {
ctx.beginPath();
ctx.arc(x, y, r, 0, 2 * Math.PI);
ctx.stroke();
}
ctx.clearRect(0, 0, canvas.width, canvas.height)
window.requestAnimationFrame(drawCircle)
y -= dy
} else if (e.keyCode == 100) {
function drawCircle() {
ctx.beginPath();
ctx.arc(x, y, r, 0, 2 * Math.PI);
ctx.stroke();
}
ctx.clearRect(0, 0, canvas.width, canvas.height)
window.requestAnimationFrame(drawCircle)
x += dx
}
}
window.onload = function() {
}
You need to separate the key event listening from the animation loop. Here's a small OOP based code snippet, which stores the direction of the ball into a lookup table type object. When a key is pressed down, a direction is stored (as -1/1), when a key is released, the direction is marked as 0. The animation loop runs independently from the key events, and moves the ball based on the stored directions and speed property.
// Mathematical constants
const dCorr = 1 / Math.sqrt(2),
PI2 = Math.PI * 2;
class Game {
constructor(cnvId, stKeys) {
// Steering keys
this.keys = stKeys;
const negKeys = Object.keys(stKeys);
this.lKey = negKeys[0];
this.uKey = negKeys[1];
this.rKey = negKeys[2];
this.dKey = negKeys[3];
// Ball parameters
this.x = 100;
this.y = 100;
this.r = 50;
this.speed = 6;
// The game area
this.cnv = document.querySelector(cnvId);
this.ctx = this.cnv.getContext('2d');
// this binding for contextless method calls
this.keyDown = this.keyDown.bind(this);
this.keyUp = this.keyUp.bind(this);
this.animate = this.animate.bind(this);
}
init() {
const cnv = this.cnv;
// Add events
document.addEventListener('keydown', this.keyDown);
document.addEventListener('keyup', this.keyUp);
// Set game area
cnv.width = window.innerWidth - 20;
cnv.height = window.innerHeight - 20;
// Start the animation
this.animate();
return this;
}
keyDown(e) {
const key = e.code;
if (!(this.keys.hasOwnProperty(key))) {return;} // Quit, not a steering key
this.keys[key] = (key === this.lKey || key === this.uKey) ? -1 : 1;
}
keyUp(e) {
const key = e.code;
if (!(this.keys.hasOwnProperty(key))) {return;} // Quit, not a steering key
this.keys[key] = 0;
}
animate() {
window.requestAnimationFrame(this.animate);
// Calculate coordinates delta
let dX = (this.keys[this.lKey] + this.keys[this.rKey]) * this.speed,
dY = (this.keys[this.dKey] + this.keys[this.uKey]) * this.speed;
// Diagonal speed correction
if (dX && dY) {
dX *= dCorr;
dY *= dCorr;
}
// Calculate the coordinates
this.x += dX;
this.y += dY;
// Move the ball
this.ctx.clearRect(0, 0, this.cnv.width, this.cnv.height);
this.moveBall(this.x, this.y);
}
moveBall(x, y) {
this.ctx.beginPath();
this.ctx.arc(x, y, this.r, 0, PI2);
this.ctx.stroke();
}
}
const game = new Game(
'#cnv', // Unique selector for the canvas
{KeyA: 0, KeyW: 0, KeyD: 0, KeyS: 0} // Steering keys, left/up/right/down
).init();
<canvas id="cnv" width="300" height="300"></canvas>
This code doesn't contain border collision detection, but it's easy to add, see an example at jsFiddle. Notice also, that KeyboardEvent.keyCode is deprecated, KeyboardEvent.code is used instead. OOP is not necessary, but it helps to reuse the code, and you can add as many canvases as you need to the same page and move the ball with different keys. The class also works as it is on any page when ever the page has a canvas with an unique property, which can be used as a CSS selector (class, id, data-* attribute etc.).
You code is a complete re-write so I will give you an example using ES6 classes. Classes are great for this type of thing. In the snippet below I have one for the circle and one for the controller. You can create many instances of circle and controllers with just by using classes.
You can also use an animation function to draw/animate all of you objects on screen.
var canvas = document.getElementById("canvas")
var ctx = canvas.getContext('2d')
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
//classes allow you to easily build the same object over and over
class Circle {
constructor(x, y, r) {
this.x = x;
this.y = y;
this.r = r;
this.color = "lightgrey"; //if you wanted to add a fillStyle
this.dx = 0;
this.dy = 0;
}
//draws the object
draw() {
ctx.beginPath();
ctx.arc(this.x, this.y, this.r, 0, 2 * Math.PI);
ctx.stroke();
ctx.closePath();
}
//updates anything related to the object
update() {
//increasingly adds 0.5 to the dy or dx
if (controller1.up) {this.dy -= 0.5};
if (controller1.right) {this.dx += 0.5};
if (controller1.down) {this.dy += 0.5};
if (controller1.left) {this.dx -= 0.5};
//if dy or dx is being added to so will the x and y. If not then they are 0.
this.x += this.dx;
this.y += this.dy;
//Multiplying by a number less then 1 will prevent the object from gaining infinite speed and also cause the object to stop. Can be changed to anything below 1. This will also change how rigidly the circle comes to a stop. it can slide or absuplty stop.
this.dx *= 0.9;
this.dy *= 0.9;
//calling the draw() in here so I don't have to call it in the animate loop. Either way works.
this.draw();
}
}
class Controller {
constructor() {
this.up = false;
this.right = false;
this.down = false;
this.left = false;
let keyEvent = (e) => {
//if the condition is true it will set up/down/left/right to the true or false. e.type will either be 'keyup' or 'keydown'.
if (e.code == "KeyW") {this.up = e.type == 'keydown'};
if (e.code == "KeyD") {this.right = e.type == 'keydown'};
if (e.code == "KeyS") {this.down = e.type == 'keydown'};
if (e.code == "KeyA") {this.left = e.type == 'keydown'};
}
addEventListener('keydown', keyEvent);
addEventListener('keyup', keyEvent);
}
}
//Create instances of you classes
let circle1 = new Circle(canvas.width/2, canvas.height/2, 50, 0, Math.PI*2);
//can add more circles if you want
//let circle2 = new Circle(100, 100, 20, 0, Math.Pi*2);
let controller1 = new Controller();
function animate() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
circle1.update();
//can add circle2.draw() if you want the other circle to be staionary.
//circle2.draw();
requestAnimationFrame(animate)
}
animate();
body {
overflow:hidden;
}
<canvas id="canvas"></canvas>

How can I make a ball jump wherever it is?

I'm trying to make a ball jump even in midair, but my code always just teleports to the same spot and then jumps, can anydody tell me how to fix this problem of mine? It needs to be able to jump wherever it is at that exact moment, and i've already tried something with set interval.
I'm trying to make a ball jump even in midair, but my code always just teleports to the same spot and then jumps, can anydody tell me how to fix this problem of mine? It needs to be able to jump wherever it is at that exact moment, and i've already tried something with set interval.
I'm trying to make a ball jump even in midair, but my code always just teleports to the same spot and then jumps, can anydody tell me how to fix this problem of mine? It needs to be able to jump wherever it is at that exact moment, and i've already tried something with set interval.
var canvas, ctx, container;
canvas = document.createElement('canvas');
ctx = canvas.getContext("2d");
var ball;
var touchGround = false;
var pull= 0.43;
var vy;
var gravity = pull;
var i = Math.floor(Math.random()*11)
color = ["red", "blue","green","yellow","purple","white","pink","silver","teal","turqu oise","magenta","cyan"];
console.log(color[i])
function ballMovement() {
vy += gravity;
ball.y += vy;
if (ball.y + ball.radius > canvas.height) {
ball.y = canvas.height - ball.radius;
vy = 0;
var img = document.getElementById('gameOver');
ctx.drawImage(gameOver, canvas.width/2-436, 100)
ball.radius = 0;
}
}
function init() {
setupCanvas();
var img = document.getElementById('gameOver');
img.style.visibility = 'hidden';
//how high the ball goes
vy = -19;
var y1 = 450
ball = {
x: canvas.width/2,
//where the ball starts moving upwards
y: 480, //here1
radius: 20,
status: 0,
color: color[i]};
}
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.beginPath();
ctx.arc(ball.x, ball.y, ball.radius, 0, Math.PI * 2, false);
ctx.fillStyle = ball.color;
ctx.fill();
ctx.closePath()
//draw a moving ball
ballMovement();
}
setInterval(draw, 1000 / 35);
function setupCanvas() {
container = document.createElement('div');
container.className = "container";
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
document.body.appendChild(container);
container.appendChild(canvas);
ctx.strokeStyle = "#ffffff";
ctx.lineWidth = 2;
}
window.onclick = function(jump){
pull + 0.1;
touchGround = false;
init()
draw()
ballMovement()
setupCanvas()
vy+((canvas.height-canvas.height)-ball.y);
}
//GOAL
//Ball jumps at somewhere in screen, let it jump wherever it is.
If I got you correctly you want your ball to go higher and higher. But problem is that you got fixed position where it's starts so where's what you need to change:
var canvas, ctx, container;
canvas = document.createElement('canvas');
canvas.width = 800;
canvas.height = 800;
ctx = canvas.getContext("2d");
var ball = {
y: 480
};
var touchGround = false;
var pull= 0.43;
var vy;
var gravity = pull;
//Creating a variable to know whether our game is running
var gameRunning = 0;
var i = Math.floor(Math.random()*11);
//Adding variable for interval so we can start it with init function
var timer;
color = ["red", "blue","green","yellow","purple","pink","silver","teal","turquoise","magenta","cyan", "black"];
function ballMovement() {
vy += gravity;
ball.y += vy;
if (ball.y + ball.radius > canvas.height) {
ball.y = canvas.height - ball.radius;
vy = 0;
var img = document.getElementById('gameOver');
ctx.drawImage(gameOver, canvas.width/2-436, 100)
ball.radius = 0;
//Stoping the draw function
clearInterval(timer);
//Saying the game isn't running
gameRunning = 0;
}
}
function init() {
//Check if canvas already created
if(!document.querySelector('.container')){
setupCanvas()
}
vy = -19;
var y1 = 450
ball = {
x: canvas.width/2,
y: ball.y,
radius: 20,
status: 0,
color: color[i]
};
//Clearing previous interval if it were any and creating a new one
clearInterval(timer);
timer = setInterval(draw, 1000 / 60);
//Saying the game is running
gameRunning = 1;
}
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.beginPath();
ctx.arc(ball.x, ball.y, ball.radius, 0, Math.PI * 2, false);
ctx.fillStyle = ball.color;
ctx.fill();
ctx.closePath()
ballMovement();
}
function setupCanvas() {
container = document.createElement('div');
container.className = "container";
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
document.body.appendChild(container);
container.appendChild(canvas);
ctx.strokeStyle = "#ffffff";
ctx.lineWidth = 2;
}
window.onclick = function(){
pull + 0.1;
touchGround = false;
//Check if the game is running or not
//If it's not running - call init
if(!gameRunning){
init();
}
else{
//If game is already running - change speed
vy = -19;
}
//I've also removed some function that were starting with init itself
vy+((canvas.height-canvas.height)-ball.y);
}

Cannot clear HTML canvas after translating, leaving object moving and leaving trail

How do I clear the HTML canvas, Object is leaving a trail in the second canvas where it is grey?
var Xposition = 50;
var Yposition = 50;
var dx = 0.4;
var dy = 5;
var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
ctx.fillStyle = "#D3D3D3";
//Draw Square
function draw() {
ctx.fillStyle = "#D3D3D3";
ctx.fillRect(0, 0, 300, 300);
ctx.save();
ctx.translate(-0.2, 0);
ctx.fillStyle = "red";
ctx.fillRect(Xposition, Yposition, 20, 20);
ctx.fillStyle = "green";
ctx.fillRect(100, 0, 2, 50);
ctx.fillStyle = "green";
ctx.fillRect(200, 30, 2, 100);
Xposition += dx;
}
setInterval(draw, 10);
//Move Square
document.addEventListener('keydown', function(event) {
Xposition += 1;
if (event.keyCode == 40 && Yposition < canvas.height - 20) {
Yposition += 10;
}
//top
else if (event.keyCode == 38 && Yposition > 0) {
Yposition -= 10;
}
});
<div id="centre">
<canvas id="myCanvas" height="200px" width="300px"></canvas>
</div>
var clearAdj = 0;
//Draw Square
function draw() {
clearAdj += 0.2;
ctx.fillStyle = "#000";
ctx.fillRect(0, 0, 300 + clearAdj, 300);
ctx.save();
ctx.translate(-0.2, 0);
Here's a quick solution that just adds an adjustment value as you translate the canvas
The canvas is not clearing completely because the entire 300x300 entity of moving over to the left. Your call to clear a 300x300 space starts at the origin of THAT CANVAS and will translate along with it.
A more elegant fix would be to make object for each of your green bar things and just subtract the x value from them, effectively moving them to the left. This would be more efficient as you could just delete the object as they leave. Your approach requires a large canvas

es6 class object is undefined

Hi I'm making a basic pong game and when I pass the player object into drawPlate it looks like it prints the information but then throws an Uncaught TypeError exception.
It seems to print the information fine in my draw() method.
Here is my code:
"use strict";
var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
var x = canvas.width / 2;
var y = canvas.height - 20;
var offX = 5;
var offY = -5;
var radius = 8;
/**
* This is the constructor of a player object, parameters are the coordinates of x and y
*/
class Player {
constructor(x, y) {
this.x = x;
this.y = y;
this.moveRight = false;
this.moveLeft = false;
}
}
/**
* Here we add an event listener to see when the user presses a keyd, and make the plate move.
*/
document.addEventListener("keydown", handleKeyDown, false);
document.addEventListener("keyup", handleKeyUp, false);
function handleKeyDown(event) {
switch (event.key) {
case "ArrowRight":
player1.moveRight = true;
break;
case "ArrowLeft":
player1.moveLeft = true;
break;
default:
return;
}
}
function handleKeyUp(event) {
switch (event.key) {
case "ArrowRight":
player1.moveRight = false;
break;
case "ArrowLeft":
player1.moveLeft = false;
break;
default:
return;
}
}
function drawPlate(player1, player2) {
console.log(player1.x);
ctx.beginPath();
if (player1.moveRight == true) {
player1.x += 7;
} else if (player1.moveLeft == true) {
player1.x -= 7;
}
ctx.rect(player1.x, player1.y, canvas.width / 7, 8);
ctx.fillStyle = "blue";
ctx.fill();
ctx.closePath();
ctx.beginPath();
ctx.rect(player2.x, player2.y, canvas.width / 7, 8);
ctx.fillStyle = "green";
ctx.fill();
ctx.closePath();
}
function drawBall() {
ctx.beginPath();
ctx.arc(x, y, radius, 0, 2 * Math.PI);
ctx.fillStyle = "red";
ctx.fill();
ctx.closePath();
}
function draw(player1, player2) {
ctx.clearRect(0, 0, canvas.width, canvas.height);
drawBall();
drawPlate(player1, player2);
if (x + radius > canvas.width || x - radius < 0) {
offX = -offX;
}
if (y - radius < 0) {
offY = -offY;
} else if (y + radius > canvas.height) {
alert("GAME OVER");
location.reload();
}
x += offX;
y += offY;
requestAnimationFrame(draw);
}
var player1 = new Player(canvas.width / 2 - 20, 0);
var player2 = new Player(canvas.width / 2 - 2, canvas.height - 8);
//console.log(player2.x);
draw(player1, player2);
The problem is that you're first calling draw by passing in player1 and player2, but then calling it again with requestAnimationFrame(draw) which will not pass those variables along (instead requestAnimationFrame calls the draw method with a timestamp).
In this case, since you're using global variables anyway, I would just remove the person1 and person2 parameters from the draw function, and treat the player1/player2 variables as global.
So all you'd have to do is change the draw function to this:
function draw() {
// Rest of the code
}
And call it later without passing anything in:
var player1 = new Player(canvas.width / 2 - 20, 0);
var player2 = new Player(canvas.width / 2 - 2, canvas.height - 8);
draw();

Stuck with canvas/JS animation

I'm working on a game to play in canvas, and was wanting to add some ambiance to a background layer using javascript. To start, here is the code...
var canvas = document.getElementById('myCanvas');
var ctx = canvas.getContext("2d");
var x = canvas.width/2;
var y = canvas.height-150;
var dx = Math.random() * (-5 * 5) + 15;
var dy = -15;
function drawDot() {
ctx.beginPath();
ctx.arc(x, y, 10, 0, Math.PI*2);
ctx.fillStyle = "black";
ctx.fill();
ctx.closePath();
};
function move() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
drawDot();
x += dx;
y += dy;
};
setInterval(move, 50);
If you run that, you can see that what I have is a black ball that moves up and off the page inside a random conal space. What I need help with is figuring out the best way to:
A. Populate it with more balls (maybe like 2-3) that are on their own random trajectory, and
B. Make it so those 2-3 balls are constantly animating inside the random cone area off the page from the same starting area (kind of like a constant spurting fountain effect).
A problem I can already see is that by using the console log, the 1 working ball I have now just keeps going off into infinity outside the canvas, so when I try to add a new one it won't run the function. I'm very new to javascript and especially canvas so apologies if this is obvious!
Thank you for any help with this!
There is a good tutorial by Seb Lee-Delisle on this exact problem here:
https://vimeo.com/36278748
Basically you have to encapsulate each Dot so it knows about its own position and acceleration.
EDIT 1
Here is an example using you own code:
document.body.innerHTML = '<canvas height="600" width="600" id="myCanvas"></canvas>';
clearInterval(interval);
var canvas = document.getElementById('myCanvas');
var ctx = canvas.getContext('2d');
var dotArray = [];
function Dot() {
var dot = {
y : canvas.height / 2,
x : canvas.width / 2,
speedX : Math.random() * ( - 5 * 5) + 15,
speedY : Math.random() * ( - 5 * 5) + 15,
age : 0,
draw : function () {
this.x += this.speedX;
this.y += this.speedY;
ctx.beginPath();
ctx.arc(this.x, this.y, 10, 0, Math.PI * 2);
ctx.fillStyle = 'black';
ctx.fill();
ctx.closePath();
}
};
return dot;
}
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
for (var i = 0; i < dotArray.length; i++) {
dotArray[i].draw();
dotArray[i].age++;
if (dotArray[i].age > 20) {
dotArray.splice(i, 1);
}
}
dotArray.push(new Dot());
}
draw();
var interval = setInterval(draw, 1000 / 60);

Categories