Hi I'm trying to make a very simple game using javascripts canvas element. I have a rectangle thats drawn on the canvas and I would like for it to move across the canvas when user clicks a button but its not working.
here is my html:
<style>
canvas {
border: 1px solid black;
height: 300px;
width:500px;
}
</style>
</head>
<body>
<button id = "play">Click to play</button>
</body>
My javascript:
$( document ).ready(function() {
var x = document.createElement("CANVAS");
var ctx = x.getContext("2d");
ctx.fillStyle = "#FF0000";
var x1 = 10;
var y = 10;
ctx.fillRect(x1, y, 80, 10);
document.body.appendChild(x);
var Game = {stopped:true};;
Game.draw = function() {
ctx.fillRect(x1, y, 80, 10);
};
Game.update = function() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
x1 = x1+5;
};
Game.run = function() {
Game.update();
Game.draw();
};
$("#play").click(function() {
Game.stopped = false;
while (!Game.stopped){
Game.run();
}
});
});
There are multiple problems in your script.
there is no variable called, canvas it is x
Your loop is an infinite while loop, which does not give any time for the UI to update - since browser tab is a single threaded app both js execution and the repaint/refresh of the UI happens in the same thread
So
var interval;
$("#play").click(function () {
Game.stopped = false;
interval = setInterval(Game.run, 5);
});
$("#stop").click(function () {
Game.stopped = true;
clearInterval(interval);
});
Demo: Fiddle
There is another simple implement:
$(document).ready(function () {
var canvas = document.createElement("CANVAS");
var ctx = canvas.getContext("2d");
ctx.fillStyle = "#FF0000";
var x1 = 10;
var y = 10;
ctx.fillRect(x1, y, 80, 10);
document.body.appendChild(canvas);
var Game = {stopped: true};
;
Game.draw = function () {
ctx.fillRect(x1, y, 80, 10);
};
Game.update = function () {
ctx.clearRect(0, 0, canvas.width, canvas.height);
x1 = x1 + 5;
};
Game.run = function () {
Game.update();
Game.draw();
};
$("#play").click(function () {
Game.stopped = false;
// while (!Game.stopped) {
// Game.run();
// }
if(!Game.stopped){
setInterval(Game.run,1000);
}
});
});
For animation, it's better to use Window.requestAnimationFrame(), if you want to get a better performance.
Related
I have a canvas object which is rendering an image. When the user click on button the image will move to right. My problem is this movement is not smooth. The image is simply jumping to the specified position. How can I make this movement smooth? This is the codepen example Can anyone please help me?
$(window).on('load', function () {
myCanvas();
});
function myCanvas() {
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
var x = 0;
function fly() {
ctx.clearRect(0, 0, c.width, c.height);
ctx.closePath();
ctx.beginPath();
var img = new Image();
img.onload = function () {
ctx.drawImage(img, x, 0);
};
img.src = 'http://via.placeholder.com/200x200?text=first';
}
fly();
$('#movebutton').click(function () {
for (i = 0; i < 200; i++) {
x = i;
requestAnimationFrame(fly);
}
});
}
<canvas id="myCanvas" width="960" height="600"></canvas>
<button id="movebutton">Move</button>
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
First of all, why are you loading your image in your frame rendering function - if cache is disabled, it will request an image every frame!
I rewrote the script so that the animation is linear and smooth, you can edit the speed variable to adjust the movement speed.
$(window).on('load', function () {
var img = new Image();
img.onload = function () {
myCanvas(img);
};
img.src = 'http://via.placeholder.com/200x200?text=first';
});
function myCanvas(img) {
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
var x = 0;
var last_ts = -1
var speed = 0.1
function renderScene() {
ctx.clearRect(0, 0, c.width, c.height);
ctx.closePath();
ctx.beginPath();
ctx.drawImage(img, x, 0);
}
function fly(ts) {
if(last_ts > 0) {
x += speed*(ts - last_ts)
}
last_ts = ts
if(x < 200) {
renderScene()
requestAnimationFrame(fly);
}
}
renderScene()
$('#movebutton').click(function () {
x = 0;
requestAnimationFrame(fly);
});
}
My code below is for Chris Courses "Circular Motion" tutorial, but I can't figure out why my clearRect isn't working. It's got to be something I'm just not seeing, I have two other canvas animations working now, but this one wont clear the rect and it's driving me nuts....
Thanks for anyone who has the time to help!
function spirals() {
const canvas2 = document.getElementById('mycanvas');
canvas2.width = document.getElementById('mycanvas').scrollWidth;
canvas2.height = document.getElementById('mycanvas').scrollHeight;
const c2 = canvas2.getContext('2d');
const spiralColorArray = [
'#ff0000',
'#00ff00',
'#0000ff'
];
addEventListener('resize', () => {
canvas2.width = document.getElementById('mycanvas').scrollWidth;
canvas2.height = document.getElementById('mycanvas').scrollHeight;
init();
});
function SpinnerIcon(h, v, radius, color) {
this.h = h;
this.v = v;
this.color = color;
this.radius = radius;
this.update = () => {
this.h += 1;
this.draw();
};
this.draw = () => {
c2.beginPath;
c2.arc(this.h, this.v, this.radius, 0, Math.PI*2, false);
c2.fillStyle = this.color;
c2.fill();
c2.closePath();
}
}
function init() {
spinnerArray = [];
for(let i=0; i < 1; i++) {
spinnerArray.push(new SpinnerIcon(canvas2.width/2, canvas2.height/2, 5, 'red'))
}
}
let spinnerArray;
function animate() {
requestAnimationFrame(animate);
c2.clearRect(0, 0, canvas2.width, canvas2.height);
spinnerArray.forEach(parti => {
parti.update();
})
}
init();
animate();
}
spirals();
#mycanvas {
background: blue;
}
<canvas id="mycanvas" width="500" height="500">
Your line with c2.beginPath is missing () and should be c2.beginPath(); since it's a function. clearPath won't work when beginPath isn't called.
I am trying to make the images race each other and once one of the images passes the finish line display the winner.
I have some old code I used for the animation but i don't know how to implement the images with it.
<html>
<head>
<title>Canvas Race</title>
<script src="jquery-2.2.3.js"></script>
<style type="text/css">
canvas {
border: 1px solid black;
background-image: url("http://www.gamefromscratch.com/image.axd?picture=road2048v2.png");
background-size: 200px 300px;
background-position-y: -81px;
}
</style>
</head>
<body>
<canvas id="canvas" width="1100" height="150" >
<script>
var blueCar = new Image();
var redCar = new Image();
// images
function image(){
blueCar.src = "http://worldartsme.com/images/car-top-view clipart-1.jpg";
redCar.src = "http://images.clipartpanda.com/car-clipart-top-view-free-vector-red-racing-car-top-view_099252_Red_racing_car_top_view.png";
}
window.onload = function draw(){
var ctx = document.getElementById('canvas').getContext('2d');
ctx.globalCompositeOperation = 'destination-over';
window.requestAnimationFrame(draw);
window.requestAnimationFrame(animate);
// finish line
ctx.beginPath();
ctx.moveTo(1020, 150);
ctx.lineTo(1020, 0);
ctx.strokeStyle = "#FFEF0E";
ctx.stroke();
//blue car
ctx.save();
if(blueCar.complete){
ctx.drawImage(blueCar, 10, 10, 100, 60);
}
// red car
if(redCar.complete){
ctx.drawImage(redCar, 10, 80, 100, 60);
}
}
image();
</script>
</canvas>
<div id="winner"></div>
</body>
</html>
Old code:
I want to use this old code but i don't know what to remove and how to add the images that i have above for the cars. As you can see for this code i created squares instead of images.
window.requestAnimFrame = (function(callback) {
return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame ||
function(callback) {
window.setTimeout(callback, 1000 / 60);
};
})();
// drawing red square
function drawRedRect(redCar, ctx) {
ctx.beginPath();
ctx.drawImage(redCar, 5, 5);
}
// finish line
function drawFinishLine(ctx){
ctx.beginPath();
ctx.moveTo(1040, 150);
ctx.lineTo(1040, 0);
ctx.stroke();
}
// this is drawing the blue square
function drawBlueRect(blueRectangle, ctx){
ctx.beginPath();
ctx.rect(blueRectangle.x, blueRectangle.y, blueRectangle.width, blueRectangle.height);
ctx.fillStyle = 'blue';
ctx.fill();
}
// red square animation
function animate(lastTime, redCar, blueRectangle, runAnimation, canvas, ctx) {
if(runAnimation.value) {
// update
var time = (new Date()).getTime();
var timeDiff = time - lastTime;
// pixels / second
var redSpeed = Math.floor((Math.random() * 400) + 1);
var blueSpeed = Math.floor((Math.random() * 400) + 1);
var linearDistEachFrameRed = redSpeed * timeDiff / 1000;
var linearDistEachFrameBlue = blueSpeed * timeDiff / 1000;
var currentX = redRectangle.x;
var currentZ = blueRectangle.x;
if(currentX < canvas.width - redRectangle.width - redRectangle.borderWidth / 2) {
var newX = currentX + linearDistEachFrameRed;
redRectangle.x = newX;
}
if(currentZ < canvas.width - blueRectangle.width - blueRectangle.borderWidth / 2) {
var newZ = currentZ + linearDistEachFrameBlue;
blueRectangle.x = newZ;
}
console.log(redSpeed);
console.log(blueSpeed);
// clear
ctx.clearRect(0, 0, canvas.width, canvas.height);
// draw
drawFinishLine(ctx);
drawRedRect(redRectangle, ctx);
drawBlueRect(blueRectangle, ctx);
//winner(win);
// request new frame
requestAnimFrame(function() {
animate(time, redRectangle, blueRectangle, runAnimation, canvas, ctx);
});
}
}
var canvas = document.getElementById('myCanvas');
var ctx = canvas.getContext('2d');
var win = document.getElementById('Winner')
//blue square
var blueRectangle = {
x: 5, y: 30, width: 45, height: 25, borderWidth:5
};
//red square
var redRectangle = {
x: 5,
y: 90,
width: 45,
height: 25,
borderWidth: 5
};
/!*
* define the runAnimation boolean as an obect
* so that it can be modified by reference
*!/
var runAnimation = {
value: false
};
// add click listener to canvas
document.getElementById('myCanvas').addEventListener('click', function() {
// flip flag
runAnimation.value = !runAnimation.value;
if(runAnimation.value) {
var date = new Date();
var time = date.getTime();
animate(time, redRectangle, blueRectangle, runAnimation, canvas, ctx);
}
});
drawFinishLine(ctx);
drawRedRect(redRectangle, ctx);
drawBlueRect(blueRectangle, ctx);
//winner(win);
Here is some of your code refactored to race car images:
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var cw=canvas.width;
var ch=canvas.height;
// game vars
var redRectangle={x:5,y:40,width:62,height:21};
var goldRectangle={x:5,y:75,width:62,height:21};
var finishX=450;
// animation vars
var nextTime=0;
var delay=1000/60;
// image vars and call start() when all images are loaded
var red=new Image();
red.onload=start;
red.src='https://dl.dropboxusercontent.com/u/139992952/multple/car1.png';
var gold=new Image();
gold.onload=start;
gold.src='https://dl.dropboxusercontent.com/u/139992952/multple/car2.png';
var imageCount=2;
function start(){
// return if all the images aren't loaded
if(--imageCount>0){return;}
// start the animation loop
requestAnimationFrame(animate);
}
function animate(time){
// has the desired time elapsed?
if(time<nextTime){requestAnimationFrame(animate);return;}
nextTime=time+delay;
// update the car positions
redRectangle.x+=Math.random()*5;
goldRectangle.x+=Math.random()*5;
// draw the current scene
ctx.clearRect(0,0,canvas.width,canvas.height);
drawFinishLine(ctx);
drawRedRect(redRectangle, ctx);
drawgoldRect(goldRectangle, ctx);
// request another animation loop
hasRedWon=redRectangle.x+redRectangle.width>finishX;
hasGoldWon=goldRectangle.x+goldRectangle.width>finishX;
// alert if race is over
if(hasRedWon){ alert('Red wins'); return; }
if(hasGoldWon){ alert('Gold wins'); return; }
// race is still going, request another animation loop
requestAnimationFrame(animate);
}
// draw images instead of rects
function drawRedRect(redRectangle, ctx){
ctx.drawImage(red, redRectangle.x, redRectangle.y, redRectangle.width, redRectangle.height);
}
// draw images instead of rects
function drawgoldRect(goldRectangle, ctx){
ctx.drawImage(gold, goldRectangle.x, goldRectangle.y, goldRectangle.width, goldRectangle.height);
}
// draw finish line
function drawFinishLine(){
ctx.fillRect(finishX,0,5,ch);
}
body{ background-color: ivory; }
#canvas{border:1px solid red; }
<canvas id="canvas" width=500 height=300></canvas>
So I'm trying to do some simple javascript animation with an image, and this is as far as I've gotten. I can load the file, but it simply shows the 'end result' and no actual movement (unless I step through each movement with console). I'm pretty sure I need to use setTimeout somewhere in my code, but can't seem to find the right way to use it.
var canvas = document.getElementById('myCanvas');
var ctx = canvas.getContext('2d');
var img;
img = new Image();
img.src = "img/background4x3.png";
var sun;
sun = new Image();
sun.src = "img/rsz_sun_200x200.png";
var y = 250;
var func1 = function (y) {
ctx.clearRect(0, 0, 600, 500);
ctx.drawImage(img, 0, 0, 600, 500);
ctx.globalCompositeOperation = 'source-over';
setTimeout(100000);
ctx.drawImage(sun, 5, y);
};
img.onload = function() {
//x = 1;
while(y > 150) {
func1(y);
y = y - 5;
setTimeout(100000);
}
};
That's not a correct usage of setTimeout. It doesn't "sleep" for this time. The script just runs a function after some time. Please, read documentation before using.
setTimeout(myFunction, 1000); // runs myFunction after a second
In your case, there are several ways to do this properly. For example, you can use setInterval. Just something like this:
var y = 250, interval;
var func1 = function () {
if (y < 150) {
clearInterval(interval);
return;
}
ctx.clearRect(0, 0, 600, 500);
ctx.drawImage(img, 0, 0, 600, 500);
ctx.globalCompositeOperation = 'source-over';
ctx.drawImage(sun, 5, y);
y = y - 5;
};
img.onload = function() {
func1();
interval = setInterval(func1, 10000);
};
or using setTimeout in another way:
var y = 250, interval;
var func1 = function () {
ctx.clearRect(0, 0, 600, 500);
ctx.drawImage(img, 0, 0, 600, 500);
ctx.globalCompositeOperation = 'source-over';
ctx.drawImage(sun, 5, y);
y = y - 5;
if (y > 150) {
setTimeout(func1, 1000);
}
};
img.onload = function() {
func1();
};
I wanted a rectangle to move horizontally..However, the rectangle is not animating..How do I fix this?
<script type="text/javascript">
var interval = 10;
var x=0;
var y=0;
var rect = null;
var context ;
var canvas;
function Rectangle(x, y, width, height, borderWidth) {
this.x=x;
this.y=y;
this.width = width;
this.height = height;
this.borderWidth = borderWidth;
}
function DrawRects(){
myRectangle = new Rectangle (250,70,100,50, 5);
context.rect(myRectangle.x,myRectangle.y,myRectangle.width,myRectangle.height)
context.fillStyle="#8ED6FF";
context.fill();
context.lineWidth=myRectangle.borderWidth;
context.strokeStyle="black";
context.stroke();
}
function updateStageObjects() {
var amplitude = 150;
var centerX = 240;
var nextX = myRectangle.x+ 10;
myRectangle.x = nextX;
}
function clearCanvas() {
context.clearRect(0,0,canvas.width, canvas.height);
}
function DrawRect(){
alert("Test1");
setTimeout(CheckCanvas,10);
//clearCanvas();
updateStageObjects();
DrawRects();
alert("Test2");
}
function CheckCanvas(){
return !!(document.createElement('canvas').getContext);
}
function CheckSound(){
return !!(document.createElement('sound').canPlayType)
}
function CheckVideo(){
return !!(document.createElement('video').canPlayType)
}
function Checkstorage(){
return !!(window.localStorage)
}
function CheckVideo(){
return !!(document.createElement('video').canPlayType)
}
function DrawCanvas(){
if (CheckCanvas()){
canvas = document.getElementById('Canvas');
context =canvas.getContext('2d');
$('#Result').text('Canvas supported...');
$('#Result').text($('#Result').text()+'Sound supported...'+CheckSound());
$('#Result').text($('#Result').text()+'Video supported...'+CheckVideo());
$('#Result').text($('#Result').text()+'Storage supported...'+Checkstorage());
DrawRects();
setInterval(DrawRect(), 10);
}
}
</script>
Html:
<canvas id="Canvas" width="800px" height="800px" onclick="DrawCanvas()"> Nor supported</canvas>
You need to do
setInterval(DrawRect, 10);
Using DrawRect() will invoke the function once, and then try to call the result of that function, as a function (which it isn't) every 10 milliseconds.