How to make Blinking text canvas animation - javascript

i am new in canvas scripting. i am try to build some condition in canvas, which the condition will showing text after the condition fulfilled. Here the conditions that i made.
if( fictionMeter > 26 && fictionMeter < 37 ) {
ctx.fillStyle = "#e86f14";
ctx.font = "25px Bangers";
ctx.fillText(
"Alert Condition 1",
mx + 55,
my - 25
);
ctx.font = "14px Bangers";
ctx.fillText(
"add some extra condition",
mx - 55,
my - 8
);
}
if( fictionMeter > 37 ) {
ctx.fillStyle = "#d5292b";
ctx.font = "25px Bangers";
ctx.fillText(
"DANGER CONDITION ONE",
mx + 45,
my - 25
);
ctx.font = "14px Bangers";
ctx.fillText(
"DANGER extra condition one",
mx - 10,
my - 8
);
}
ctx.restore();
}
My question is how to add blinking text animation on it?,which the text animation will appear for a second and than hide until the other condition fulfilled.

The easier way to keep track of objects with their own animation properties is to create objects representing them. This way you can drive an object using current time and independently.
For example (see comments):
var ctx = c.getContext("2d"), bg = 0, db = 0.01;
// BlinkText objects which will hold appearance and timings
function BlinkText(txt, x, y, interval) {
this.text = txt;
this.x = x;
this.y = y;
this.interval = interval;
this.font = "bold 20px sans-serif";
this.color = "#f00";
this.active = false;
this.time = 0;
this.toggle = true;
}
// If several instances is to be defined, use prototypal approach
BlinkText.prototype = {
start: function(time) {
this.time = time; // store start time to calc. delta
this.active = true; // enable drawing in render()
this.toggle = true; // reset toggle flag so first check is "on"
},
stop: function() {
this.active = false; // disable drawing in render()
},
render: function(ctx) { // render if active
if (this.active) {
if (this.toggle) { // are we on nor off?
ctx.font = this.font;
ctx.fillStyle = this.color;
ctx.fillText(this.text, this.x, this.y); // render text if on
}
// calc time interval and toggle every other time
var time = performance.now();
if (time - this.time >= this.interval) { // passed interval?
this.time = time; // update start time
this.toggle = !this.toggle; // toggle state
}
}
}
};
// create a couple of instances
var txt1 = new BlinkText("Hello there..", 50, 50, 500);
var txt2 = new BlinkText("This is blinking too", 100, 90, 900);
var txt3 = new BlinkText("All independant, but controlable...", 10, 120, 300);
txt2.color = "#00f"; // set some custom properties
txt3.font = "16px sans-serif";
txt3.color = "#090";
(function loop() {
// draw other stuff
ctx.fillStyle = "hsl(0,0%, " + (bg * 40) + "%)";
ctx.fillRect(0, 0, c.width, c.height);
txt1.render(ctx); // call render() regardless of state
txt2.render(ctx);
txt3.render(ctx);
bg += db;
if (bg <0 || bg > 1) db = -db;
requestAnimationFrame(loop)
})();
bstart.onclick = function() {
txt1.start(performance.now()); // init start with current time
txt2.start(performance.now());
txt3.start(performance.now());
};
bstop.onclick = function() {
txt1.stop();
txt2.stop();
txt3.stop();
};
<canvas id=c></canvas><br>
<button id=bstart>Start</button> <button id=bstop>Stop</button>

Related

CSS causes the canvas games buttons and on screen clicks to break. How do I fix it?

Why centering and even adding a header tag is causing the code's buttons to go off of the input area? I want to add some designs to the background but have no idea why the buttons are off of the input area. It is for a canvas game called bug smasher that needs mouse input.
Javascript:
// Create the canvas
var canvas = document.createElement("canvas");
var ctx = canvas.getContext('2d');
var timer = 0;
var caught = false;
var fps = 10;
document.body.appendChild(canvas);
canvas.width = 800;
canvas.height = 544;
// Background image
var bgReady = false;
var bgImage = new Image();
bgImage.onload = function () {
bgReady = true;
};
bgImage.src = "images/background.png";
// bug image
var bugReady = false;
var bugImage = new Image();
bugImage.onload = function () {
bugReady = true;
};
bugImage.src = "images/bug.png";
var bug = {};
var bugCaught = 0;
// When bug is caught, reset
var reset = function () {
bug.x = 40 + (Math.random() * (canvas.width - 70));
do {
bug.y = 40 + (Math.random() * (canvas.height - 70));
}
while (bug.y < 100)
};
//mousedown event
window.addEventListener("mousedown", onMouseDown, false);
function onMouseDown(e) {
if (e.button != 0) return;
mouseXinCanvas = e.clientX;
mouseYinCanvas = e.clientY;
if (bugBody(bug, mouseXinCanvas, mouseYinCanvas)) {
caught = true;
clearInterval(timer);
timer = setInterval(reset, 20000 / fps);
reset();
}
if (ResetScore(mouseXinCanvas, mouseYinCanvas)) {
location.reload();
}
if (ResetSpeed(mouseXinCanvas, mouseYinCanvas)) {
clearInterval(timer);
timer = setInterval(reset, 20000 / fps);
reset();
render();
}
};
//bug's body define
function bugBody(bug, x, y) {
if (x <= (bug.x + 80)
&& bug.x <= (x + 80)
&& y <= (bug.y + 80)
&& bug.y <= (y + 80)
) {
fps = fps + 5;
bugCaught++;
return true;
}
return false;
};
//Reset Score box
function ResetScore(x, y) {
if (x > (305)
&& x < (545)
&& y > (15)
&& y < (85)
) {
return true;
}
return false;
};
//Reset speed box
function ResetSpeed(x, y) {
if (x > (605)
&& x < (845)
&& y > (15)
&& y < (85)
) {
fps = 10;
return true;
}
return false;
};
// Draw everything
var render = function () {
//===========================================================
// add the following line to clear the display.
ctx.clearRect(0,0,ctx.canvas.width,ctx.canvas.height);
if (bgReady) {
ctx.drawImage(bgImage, 0, 100);
}
if (bugReady) {
ctx.drawImage(bugImage, bug.x, bug.y);
}
if (caught == true) {
if (bgReady) {
ctx.drawImage(bgImage, 0, 100);
}
caught = false;
}
// Score, Title
ctx.fillStyle = "rgb(65, 226, 24)";
ctx.font = "34px Helvetica";
ctx.textAlign = "left";
ctx.textBaseline = "top";
ctx.fillText("Bug Smasher", 5, 40);
ctx.font = "20px Helvetica";
ctx.fillText("Score: " + bugCaught, 10, 10);
// Reset Score, Speed button
ctx.fillStyle = "rgb(30, 168, 99)";
ctx.fillRect(250, 10, 250, 80);
ctx.fillRect(520, 10, 250, 80);
ctx.fillStyle = "rgb(30, 168, 99)";
ctx.fillRect(255, 15, 240, 70);
ctx.fillRect(525, 15, 240, 70);
ctx.fillStyle = "rgb(255, 255, 255)";
ctx.font = "34px Arial";
ctx.fillText("Reset Score", 275, 30);
ctx.fillText("Reset Speed", 545, 30);
};
// The main game loop
var main = function () {
render();
// Request to do this again ASAP
requestAnimationFrame(main);
};
// Cross-browser support for requestAnimationFrame
var w = window;
requestAnimationFrame = w.requestAnimationFrame || w.webkitRequestAnimationFrame || w.msRequestAnimationFrame || w.mozRequestAnimationFrame;
// Let's play this game!
//var then = Date.now();
reset();
main();
HTML:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content = "width=device-width, initial-scale = 1.0">
<link rel="stylesheet" href="Assignment5.css">
<title>Assignment 5</title>
</head>
<body>
<main>
<script src="Assignment5.js"></script>
</main>
</body>
</html>
When you add other elements to your code your <canvas> element will shift accordingly. What you are not accounting for in your mouse function is the canvas position in relation to the window.
I'm sure you've noticed that when you add elements the canvas moves down but the collision for the button and the bug do not move in relation to the canvas. So in your mouse function you need to subtract the canvas x and y position
window.addEventListener("mousedown", onMouseDown, false);
function onMouseDown(e) {
let canvasBounds = canvas.getBoundingClientRect(); //add this
if (e.button != 0) return;
mouseXinCanvas = e.clientX - canvasBounds.x; //can also be canvasBounds.left
mouseYinCanvas = e.clientY - canvasBounds.y; //can also be canvasBoudns.top
if (bugBody(bug, mouseXinCanvas, mouseYinCanvas)) {...

Creating a clicking counter on canvas

I created a little game with JavaScript while i am learning it.
I would like to get a count clicker in it. So you can see how many times you have clicked on the canvas before you die. (so it resets right after the 'game over'.
Here is the JS code i have at the moment:
window.addEventListener("load", function () {
//constants
var GAME_WIDTH = 640;
var GAME_HEIGHT = 360;
//keep the game going
var gameLive = true;
//current level
var level = 1;
//enemies
var enemies = [{
x: 100, //x coordinate
y: 100, //y coordinate
speedY: 2, //speed in Y
w: 40, //width
h: 40 //heght
},
{
x: 200,
y: 0,
speedY: 2,
w: 40,
h: 40
},
{
x: 330,
y: 100,
speedY: 3,
w: 40,
h: 40
},
{
x: 450,
y: 100,
speedY: -3,
w: 40,
h: 40
}
];
//the player object
var player = {
x: 10,
y: 160,
speedX: 2.5,
isMoving: false, //keep track whether the player is moving or not
w: 40,
h: 40
};
//the goal object
var goal = {
x: 580,
y: 160,
w: 50,
h: 36
}
// var zonder waarde
var img = {};
var movePlayer = function () {
player.isMoving = true;
}
var stopPlayer = function () {
player.isMoving = false;
}
//grab the canvas and context
var canvas = document.getElementById("mycanvas");
var ctx = canvas.getContext("2d");
//event listeners to move player
canvas.addEventListener('mousedown', movePlayer);
canvas.addEventListener('mouseup', stopPlayer);
canvas.addEventListener('touchstart', movePlayer);
canvas.addEventListener('touchend', stopPlayer);
var load = function () {
img.player = new Image();
img.player.src = 'images/ping.png';
img.background = new Image();
img.background.src = 'images/sea.png';
img.enemy = new Image();
img.enemy.src = 'images/enemy.png';
img.goal = new Image();
img.goal.src = 'images/fish.png';
};
//update the logic
var update = function () {
//check if you've won the game
if (checkCollision(player, goal)) {
// leven +1
level++;
// level in console
console.log(level);
// get player back in position
player.x = 10;
player.y = 160;
//increase the speed of the enemies by 1
//increase the speed of the enemies by 1
enemies.forEach(function (enemies) {
if (enemies.speedY > 0) {
enemies.speedY++;
} else {
enemies.speedY--;
}
});
}
//update player
if (player.isMoving) {
player.x = player.x + player.speedX;
}
enemies.forEach(function (element, index) {
//check for collision with player
if (checkCollision(player, element)) {
//stop the game
gameLive = false;
alert('Game Over!');
//reload page
window.location = "";
};
//move enemy
element.y += element.speedY;
//check borders
if (element.y <= 10) {
element.y = 10;
//element.speedY = element.speedY * -1;
element.speedY *= -1;
} else if (element.y >= GAME_HEIGHT - 50) {
element.y = GAME_HEIGHT - 50;
element.speedY *= -1;
}
});
};
//show the game on the screen
var draw = function () {
//clear the canvas
ctx.clearRect(0, 0, GAME_WIDTH, GAME_HEIGHT);
//draw background
ctx.drawImage(img.background, 0, 0);
//draw player
ctx.drawImage(img.player, player.x, player.y);
//draw enemies
enemies.forEach(function (element, index) {
ctx.drawImage(img.enemy, element.x, element.y);
});
//draw goal
ctx.drawImage(img.goal, goal.x, goal.y);
//for seeing the level in canvas
//color points
ctx.fillStyle = "#339900";
//font points
ctx.font = "60px Michroma";
//point shower
ctx.fillText(level, 10, 55);
};
//gets executed multiple times per second
var step = function () {
update();
draw();
if (gameLive) {
window.requestAnimationFrame(step);
}
};
//check the collision between two rectangles
var checkCollision = function (rect1, rect2) {
var closeOnWidth = Math.abs(rect1.x - rect2.x) <= Math.max(rect1.w, rect2.w);
var closeOnHeight = Math.abs(rect1.y - rect2.y) <= Math.max(rect1.h, rect2.h);
return closeOnWidth && closeOnHeight;
}
//initial kick
load();
step();
});
I tried some things out of hand but i couldn't figure it out. Thanks a lot for your help! :)
Kind regards
Add a new variable to increment then within the movePlayer function increment this value. When the game is over you can reset the variable to 0.
For example, below the current level variable add var clickCount = 0;
Then within the movePlayer function add clickCount += 1;
As you are currently reloading the page once the game ends the variable will be reset.
This variable could be output in a simple DIV on the page and does not have to be part of the canvas.
It would be best if you had a working example with the images too. You could do this on https://codesandbox.io/ or https://codepen.io/
UPDATE
Add a DOM element <div id="clickCount">0</div> onto your page. Then replace the movePlayer with the below.
var movePlayer = function () {
clickCount += 1;
player.isMoving = true;
document.getElementById('clickCount').innerHTML = clickCount;
}
This will then update the DIV with the new count, you can then use CSS to position and style the DIV as you want.

Using Javascript to create HTML5 Canvas Game - Bug Smasher

I'm trying to use Javascript to create a Canvas Game which is similar to Bug Smasher or Ant Smasher game. It means the obj will move randomly, and when u click on it, the score will increase. ( I'm not allowed to use JQuery )
I almost finished all the work. But there's an error I cannot figure out: Everytime I click on the object, the score increases but it overwrites the number "0" like this:
And this is my code:
// Create the canvas
var canvas = document.createElement("canvas");
var ctx = canvas.getContext('2d');
var timer = 0;
var caught = false;
var fps = 10;
document.body.appendChild(canvas);
canvas.width = 800;
canvas.height = 544;
// Background image
var bgReady = false;
var bgImage = new Image();
bgImage.onload = function () {
bgReady = true;
};
bgImage.src = "images/background.png";
// nar image
var narReady = false;
var narImage = new Image();
narImage.onload = function () {
narReady = true;
};
narImage.src = "images/nar.png";
var nar = {};
var narCaught = 0;
// When nar is caught, reset
var reset = function () {
nar.x = 40 + (Math.random() * (canvas.width - 70));
do {
nar.y = 40 + (Math.random() * (canvas.height - 70));
}
while (nar.y < 100)
};
//mousedown event
window.addEventListener("mousedown", onMouseDown, false);
function onMouseDown(e) {
if (e.button != 0) return;
mouseXinCanvas = e.clientX;
mouseYinCanvas = e.clientY;
if (narBody(nar, mouseXinCanvas, mouseYinCanvas)) {
caught = true;
clearInterval(timer);
timer = setInterval(reset, 20000 / fps);
reset();
}
if (ResetScore(mouseXinCanvas, mouseYinCanvas)) {
location.reload();
}
if (ResetSpeed(mouseXinCanvas, mouseYinCanvas)) {
clearInterval(timer);
timer = setInterval(reset, 20000 / fps);
reset();
render();
}
};
//nar's body define
function narBody(nar, x, y) {
if (x <= (nar.x + 80)
&& nar.x <= (x + 80)
&& y <= (nar.y + 80)
&& nar.y <= (y + 80)
) {
fps = fps + 5;
narCaught++;
return true;
}
return false;
};
//Reset Score box
function ResetScore(x, y) {
if (x > (305)
&& x < (545)
&& y > (15)
&& y < (85)
) {
return true;
}
return false;
};
//Reset speed box
function ResetSpeed(x, y) {
if (x > (605)
&& x < (845)
&& y > (15)
&& y < (85)
) {
fps = 10;
return true;
}
return false;
};
// Draw everything
var render = function () {
if (bgReady) {
ctx.drawImage(bgImage, 0, 100);
}
if (narReady) {
ctx.drawImage(narImage, nar.x, nar.y);
}
if (caught == true) {
if (bgReady) {
ctx.drawImage(bgImage, 0, 100);
}
caught = false;
}
// Score, Title
ctx.fillStyle = "rgb(65, 226, 24)";
ctx.font = "34px Helvetica";
ctx.textAlign = "left";
ctx.textBaseline = "top";
ctx.fillText("Catch Naruto!!!", 5, 40);
ctx.font = "20px Helvetica";
ctx.fillText("Score: " + narCaught, 10, 10);
// Reset Score, Speed button
ctx.fillStyle = "rgb(30, 168, 99)";
ctx.fillRect(250, 10, 250, 80);
ctx.fillRect(520, 10, 250, 80);
ctx.fillStyle = "rgb(30, 168, 99)";
ctx.fillRect(255, 15, 240, 70);
ctx.fillRect(525, 15, 240, 70);
ctx.fillStyle = "rgb(255, 255, 255)";
ctx.font = "34px Arial";
ctx.fillText("Reset Score", 275, 30);
ctx.fillText("Reset Speed", 545, 30);
};
// The main game loop
var main = function () {
render();
// Request to do this again ASAP
requestAnimationFrame(main);
};
// Cross-browser support for requestAnimationFrame
var w = window;
requestAnimationFrame = w.requestAnimationFrame || w.webkitRequestAnimationFrame || w.msRequestAnimationFrame || w.mozRequestAnimationFrame;
// Let's play this game!
//var then = Date.now();
reset();
main();
<html lang="en">
<head>
<meta charset="utf-8">
<title>Assignment 5</title>
</head>
<body>
<script src="game.js"></script>
</body>
</html>
Please help ! :(
The problem is simple to solve. You just need to clear all the previous frame's rendering before you render the new frame.
Just add the following line to the render function
ctx.clearRect(0,0,ctx.canvas.width,ctx.canvas.height);
You will notice that the quality of the text also improves. This is because you are no long drawing over the top of the old text,
I dont know what the background image is so I clear the whole canvas. But if the background image is not transparent you only need to clear what it does not cover.
See change below
// Create the canvas
var canvas = document.createElement("canvas");
var ctx = canvas.getContext('2d');
var timer = 0;
var caught = false;
var fps = 10;
document.body.appendChild(canvas);
canvas.width = 800;
canvas.height = 544;
// Background image
var bgReady = false;
var bgImage = new Image();
bgImage.onload = function () {
bgReady = true;
};
bgImage.src = "images/background.png";
// nar image
var narReady = false;
var narImage = new Image();
narImage.onload = function () {
narReady = true;
};
narImage.src = "images/nar.png";
var nar = {};
var narCaught = 0;
// When nar is caught, reset
var reset = function () {
nar.x = 40 + (Math.random() * (canvas.width - 70));
do {
nar.y = 40 + (Math.random() * (canvas.height - 70));
}
while (nar.y < 100)
};
//mousedown event
window.addEventListener("mousedown", onMouseDown, false);
function onMouseDown(e) {
if (e.button != 0) return;
mouseXinCanvas = e.clientX;
mouseYinCanvas = e.clientY;
if (narBody(nar, mouseXinCanvas, mouseYinCanvas)) {
caught = true;
clearInterval(timer);
timer = setInterval(reset, 20000 / fps);
reset();
}
if (ResetScore(mouseXinCanvas, mouseYinCanvas)) {
location.reload();
}
if (ResetSpeed(mouseXinCanvas, mouseYinCanvas)) {
clearInterval(timer);
timer = setInterval(reset, 20000 / fps);
reset();
render();
}
};
//nar's body define
function narBody(nar, x, y) {
if (x <= (nar.x + 80)
&& nar.x <= (x + 80)
&& y <= (nar.y + 80)
&& nar.y <= (y + 80)
) {
fps = fps + 5;
narCaught++;
return true;
}
return false;
};
//Reset Score box
function ResetScore(x, y) {
if (x > (305)
&& x < (545)
&& y > (15)
&& y < (85)
) {
return true;
}
return false;
};
//Reset speed box
function ResetSpeed(x, y) {
if (x > (605)
&& x < (845)
&& y > (15)
&& y < (85)
) {
fps = 10;
return true;
}
return false;
};
// Draw everything
var render = function () {
//===========================================================
// add the following line to clear the display.
ctx.clearRect(0,0,ctx.canvas.width,ctx.canvas.height);
if (bgReady) {
ctx.drawImage(bgImage, 0, 100);
}
if (narReady) {
ctx.drawImage(narImage, nar.x, nar.y);
}
if (caught == true) {
if (bgReady) {
ctx.drawImage(bgImage, 0, 100);
}
caught = false;
}
// Score, Title
ctx.fillStyle = "rgb(65, 226, 24)";
ctx.font = "34px Helvetica";
ctx.textAlign = "left";
ctx.textBaseline = "top";
ctx.fillText("Catch Naruto!!!", 5, 40);
ctx.font = "20px Helvetica";
ctx.fillText("Score: " + narCaught, 10, 10);
// Reset Score, Speed button
ctx.fillStyle = "rgb(30, 168, 99)";
ctx.fillRect(250, 10, 250, 80);
ctx.fillRect(520, 10, 250, 80);
ctx.fillStyle = "rgb(30, 168, 99)";
ctx.fillRect(255, 15, 240, 70);
ctx.fillRect(525, 15, 240, 70);
ctx.fillStyle = "rgb(255, 255, 255)";
ctx.font = "34px Arial";
ctx.fillText("Reset Score", 275, 30);
ctx.fillText("Reset Speed", 545, 30);
};
// The main game loop
var main = function () {
render();
// Request to do this again ASAP
requestAnimationFrame(main);
};
// Cross-browser support for requestAnimationFrame
var w = window;
requestAnimationFrame = w.requestAnimationFrame || w.webkitRequestAnimationFrame || w.msRequestAnimationFrame || w.mozRequestAnimationFrame;
// Let's play this game!
//var then = Date.now();
reset();
main();

Rotate a particular image only in canvas when left or right key is pressed

I am new to canvas and developing a game where a car moves straight and now I want to rotate the image of the car only to rotate anti clockwise when the left key is pressed and clockwise when right key is pressed.
Currently I am trying with
var canvas = document.createElement("canvas");
var ctx = canvas.getContext("2d");
var heroReady = false;
var heroImage = new Image();
heroImage.onload = function () {
heroReady = true;
};
heroImage.src = "images/car.png";
if (37 in keysDown) { // Player holding left
ctx.clearRect(0,0,canvas.width,canvas.height);
ctx.save();
ctx.translate(canvas.width,canvas.height);
ctx.rotate(90*Math.PI/180);
ctx.drawImage(heroImage,hero.x,hero.y);
}
But this rotates the whole screen .I only want the heroImage to be rotated and not the screen.Any help is appreciated.
My source code: working pen
To get key input and rotate paths and what not on the canvas.
/** SimpleUpdate.js begin **/
// short cut vars
var ctx = canvas.getContext("2d");
var w = canvas.width;
var h = canvas.height;
ctx.font = "18px arial";
var cw = w / 2; // center
var ch = h / 2;
var focused = false;
var rotated = false;
var angle = 0;
// Handle all key input
const keys = { // key input object
ArrowLeft : false, // only add key names you want to listen to
ArrowRight : false,
keyEvent (event) {
if (keys[event.code] !== undefined) { // are we interested in this key
keys[event.code] = event.type === "keydown";
rotated = true; // to turn off help
}
}
}
// add key listeners
document.addEventListener("keydown", keys.keyEvent)
document.addEventListener("keyup", keys.keyEvent)
// check if focus click
canvas.addEventListener("click",()=>focused = true);
// main update function
function update (timer) {
ctx.setTransform(1, 0, 0, 1, 0, 0); // reset transform
ctx.clearRect(0,0,w,h);
// draw outside box
ctx.fillStyle = "red"
ctx.fillRect(50, 50, w - 100, h - 100);
// rotate if input
angle += keys.ArrowLeft ? -0.1 : 0;
angle += keys.ArrowRight ? 0.1 : 0;
// set orgin to center of canvas
ctx.setTransform(1, 0, 0, 1, cw, ch);
// rotate
ctx.rotate(angle);
// draw rotated box
ctx.fillStyle = "Black"
ctx.fillRect(-50, -50, 100, 100);
// set transform to center
ctx.setTransform(1, 0, 0, 1, cw, ch);
// rotate
ctx.rotate(angle);
// move to corner
ctx.translate(50,50);
// rotate once more, Doubles the rotation
ctx.rotate(angle);
ctx.fillStyle = "yellow"
ctx.fillRect(-20, -20,40, 40);
ctx.setTransform(1, 0, 0, 1, 0, 0); // restore default
// draw center box
ctx.fillStyle = "white"
ctx.fillRect(cw - 25, ch - 25, 50, 50);
if(!focused){
ctx.lineWidth = 3;
ctx.strokeText("Click on canvas to get focus.",10,20);
ctx.fillText("Click on canvas to get focus.",10,20);
}else if(!rotated){
ctx.lineWidth = 3;
ctx.strokeText("Left right arrow to rotate.",10,20);
ctx.fillText("Left right arrow to rotate.",10,20);
}
requestAnimationFrame(update);
}
requestAnimationFrame(update);
/** SimpleUpdate.js end **/
<canvas id = canvas></canvas>
Looking at you pen bellow is a function that will help.
The following function will draw a scaled and rotated sprite on the canvas
// draws a image as sprite at x,y scaled and rotated around its center
// image, the image to draw
// x,y position of the center of the image
// scale the scale, 1 no scale, < 1 smaller, > 1 larger
// angle in radians
function drawSprite(image, x, y, scale = 1,angle = 0){
ctx.setTransform(scale, 0, 0, scale, x, y); // set scale and center of sprite
ctx.rotate(angle);
ctx.drawImage(image,- image.width / 2, - image.height / 2);
ctx.setTransform(1,0,0,1,0,0); // restore default transform
// if you call this function many times
// and dont do any other rendering between
// move the restore default line
// outside this function and after all the
// sprites are drawn.
}
OK more for you.
Your code is all over the place and the only way to work out what was happening was to rewrite it from the ground up.
The following does what I think you want your pen to do. Not I squash the width to fit the snippet window.
Code from OP pen and modified to give what I think the OP wants.
// Create the canvas
var canvas = document.createElement("canvas");
var ctx = canvas.getContext("2d");
canvas.width = 1024;
canvas.height = 1024;
document.body.appendChild(canvas);
var monstersCaught = 0;
var lastFrameTime;
var frameTime = 0; // in seconds used to control hero speed
// The main game loop
function main (time) {
if(lastFrameTime !== undefined){
frameTime = (time - lastFrameTime) / 1000; // in seconds
}
lastFrameTime = time
updateObjects();
render();
requestAnimationFrame(main);
};
// this is called when all the images have loaded
function start(){
monstersCaught = 0;
resetObjs();
requestAnimationFrame(main);
}
function displayStatus(message){
ctx.setTransform(1,0,0,1,0,0); // set default transform
ctx.clearRect(0,0,canvas.width,canvas.height);
ctx.fillStyle = "black";
ctx.font = "24px Helvetica";
ctx.textAlign = "center";
ctx.textBaseline = "center";
ctx.fillText(message,canvas.width / 2 ,canvas.height / 2);
}
// reset objects
function resetObjs () {
monsters.array.forEach(monster => monster.reset());
heros.array.forEach(hero => hero.reset());
}
// Update game objects
function updateObjects (modifier) {
monsters.array.forEach(monster => monster.update());
heros.array.forEach(hero => hero.update());
}
function drawObjects (modifier) {
monsters.array.forEach(monster => monster.draw());
heros.array.forEach(hero => hero.draw());
}
// Draw everything
function render () {
ctx.setTransform(1,0,0,1,0,0); // set default transform
ctx.drawImage(images.background, 0, 0);
drawObjects();
// Score
ctx.setTransform(1,0,0,1,0,0); // set default transform
ctx.fillStyle = "rgb(250, 250, 250)";
ctx.font = "24px Helvetica";
ctx.textAlign = "left";
ctx.textBaseline = "top";
ctx.fillText("Points: " + monstersCaught, 32, 32);
}
// hold all the images in one object.
const images = { // double underscore __ is to prevent adding images that replace these functions
__status : {
count : 0,
ready : false,
error : false,
},
__onready : null,
__createImage(name,src){
var image = new Image();
image.src = src;
images.__status.count += 1;
image.onerror = function(){
images.__status.error = true;
displayStatus("Error loading image : '"+ name + "'");
}
image.onload = function(){
images.__status.count -= 1;
if(images.__status.count === 0){
images.__status.ready = true;
images.__onready();
}
if(!images.__status.error){
displayStatus("Images remaing : "+ images.__status.count);
}
}
images[name] = image;
return image;
}
}
// Handle all key input
const keys = { // key input object
ArrowLeft : false, // only add key names you want to listen to
ArrowRight : false,
ArrowDown : false,
ArrowUp : false,
keyEvent (event) {
if (keys[event.code] !== undefined) { // are we interested in this key
keys[event.code] = event.type === "keydown";
event.preventDefault();
}
}
}
// default setting for objects
const objectDefault = {
x : 0, y : 0,
dir : 0, // the image rotation
isTouching(obj){ // returns true if object is touching box x,y,w,h
return !(this.x > obj.x +obj.w || this.y > obj.y +obj.h || this.x + this.w < obj.x || this.y + this.h < obj.y);
},
draw(){
ctx.setTransform(1,0,0,1,this.x + this.w / 2, this.y + this.h / 2);
ctx.rotate(this.dir);
ctx.drawImage(this.image, - this.image.width / 2, - this.image.height / 2);
},
reset(){},
update(){},
}
// default setting for monster object
const monsterDefault = {
w : 32, // width
h : 32, // height
reset(){
this.x = this.w + (Math.random() * (canvas.width - this.w * 2));
this.y = this.h + (Math.random() * (canvas.height - this.h * 2));
},
}
// default settings for hero
const heroDefault = {
w : 32, // width
h : 32, // height
speed : 256,
spawnPos : 1.5,
reset(){
this.x = canvas.width / this.spawnPos;
this.y = canvas.height / this.spawnPos;
},
update(){
if (keys.ArrowUp) { // Player holding up
this.y -= this.speed * frameTime;
this.dir = Math.PI * 0; // set direction
}
if (keys.ArrowDown) { // Player holding down
this.y += this.speed * frameTime;
this.dir = Math.PI * 1; // set direction
}
if (keys.ArrowLeft) { // Player holding left
this.x -= this.speed * frameTime;
this.dir = Math.PI * 1.5; // set direction
}
if (keys.ArrowRight) { // Player holding right
this.x += this.speed * frameTime;
this.dir = Math.PI * 0.5; // set direction
}
if(Math.sign(this.speed) === -1){ // filp directio of second car
this.dir += Math.PI; // set direction
}
monsters.array.forEach(monster => {
if(monster.isTouching(this)){
monster.reset();
monstersCaught += 1;
}
});
if (this.x >= canvas.width || this.y >= canvas.height || this. y < 0 || this.x < 0) {
this.reset();
}
}
}
// objects to hold monsters and heros
const monsters = { // dont call a monster "array"
array : [], // copy of monsters as array
};
const heros = { // dont call a monster "array"
array : [], // copy of heros as array
};
// add monster
function createMonster(name, settings = {}){
monsters[name] = {...objectDefault, ...monsterDefault, ...settings, name};
monsters[name].reset();
monsters.array.push(monsters[name]);
return monsters[name];
}
// add hero to heros object
function createHero(name, settings){
heros[name] = {...objectDefault, ...heroDefault, ...settings, name};
heros[name].reset();
heros.array.push(heros[name]);
return heros[name];
}
// set function to call when all images have loaded
images.__onready = start;
// load all the images
images.__createImage("background", "http://res.cloudinary.com/dfhppjli0/image/upload/v1491958481/road_lrjihy.jpg");
images.__createImage("hero", "http://res.cloudinary.com/dfhppjli0/image/upload/c_scale,w_32/v1491958999/car_p1k2hw.png");
images.__createImage("monster", "http://res.cloudinary.com/dfhppjli0/image/upload/v1491959220/m_n1rbem.png");
// create all objects
createHero("hero", {image : images.hero, spawnPos : 1.5});
createHero("hero3", {image : images.hero, spawnPos : 2, speed : -256});
createMonster("monster", {image : images.monster});
createMonster("monster3", {image : images.monster});
createMonster("monster9", {image : images.monster});
createMonster("monster12", {image : images.monster});
// add key listeners
document.addEventListener("keydown", keys.keyEvent);
document.addEventListener("keyup", keys.keyEvent);
canvas {
width : 100%;
height : 100%;
}

HTML 5 Canvas elements not animating correctly in a .setInterval method

The code will render the animation with one of the "boxes" , but acts very strangely when two of the "boxes" are drawn within the setInterval method. I suspect this may have something to do with ctx.clearRect.
JS Fiddle
var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext('2d');
var raf;
var switchDirection = [true, true];
function alien() {
if (canvas.getContext) {
function Spaceships(x) {
this.x = x;
this.y = 100;
this.color = 'rgb(192, 192, 192)';
this.draw = function() {
ctx.beginPath();
ctx.rect(this.x, this.y, 100, 100);
ctx.closePath();
ctx.fillStyle = this.color;
ctx.fill();
};
};
var alienOne = new Spaceships(100);
var alienTwo = new Spaceships(500);
alienOne.draw();
alienTwo.draw();
setInterval(function redraw() {
if (alienOne.x == 200) {
switchDirection[0] = false;
} else if (alienOne.x == 100) {
switchDirection[0] = true;
}
if (switchDirection[0] == true) {
ctx.clearRect(0, 0, 0, 0);
alienOne.draw();
alienOne.x += 10;
} else if (switchDirection[0] == false) {
ctx.clearRect(0, 0, 0, 0);
alienOne.draw();
alienOne.x -= 10;
}
if (alienTwo.x == 600) {
switchDirection[1] = false;
} else if (alienTwo.x == 500) {
switchDirection[1] = true;
}
if (switchDirection[1] == true) {
ctx.beginPath();
ctx.clearRect(0, 0, 0, 0);
alienTwo.draw();
alienTwo.x += 10;
} else if (switchDirection[1] == false) {
ctx.beginPath();
ctx.clearRect(0, 0, 0, 0);
alienTwo.draw();
alienTwo.x -= 10;
}
}, 250);
} else {
alert('you need a better browser to play this game')
}
};
alien();
I have tried placing the second box in its own .setInterval. The animation renders incorrectly by not properly adjusting its width.
Any help would be greatly appreciated.
I fixed your problem, and refactored some of your code:
The main problem was the clearing of the canvas with the clearRect method. You didn't specify the right parameter values.
Some of the code is very repetitive. For now this isn't really a problem since you're only using 2 aliens, however this could become a problem once you have more than two. Imagine writing almost identical code for 40 aliens. This is solved with arrays and for-loops. Also, you use a boolean variable to determine when to add/substract from the alienX. This too can become quite a hassle. Now, we check when the spaceships exceed/go below the tolerated x-value, and change the sign of your velocity accordingly.
As mentioned by #Kaiido in the comments above, you can use requestAnimationFrame for your animations, which is better for this project than setInterval. To maintain the choppy animation effect, I used a really basic counter, with the % operator to only execute the code every 4x in a second (usually, reqAnimFrame callbacks 60x per second, so 60/15 = 4, equal to 250ms in your example) (see below).
The code:
var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
var aliens = [];
var counter = 0;
function alien() {
if (canvas.getContext) {
function Spaceships(x) {
this.baseX = x; // added a baseX to remember where the spaceship started off
this.x = x;
this.y = 100;
this.velocityX = 10;
this.color = "rgb(192, 192, 192)";
this.draw = function() {
ctx.beginPath();
ctx.rect(this.x, this.y, 100, 100);
ctx.closePath();
ctx.fillStyle = this.color;
ctx.fill();
}
}
aliens.push(new Spaceships(100), new Spaceships(500));
drawAllAliens();
function redraw() {
requestAnimationFrame(redraw);
var maxXDiff = 100; //choose how far or near your aliens/squares can go
counter ++;
// remainder/modulo operator:
// reduce animation to every 4x per sec for that "choppy" animation
if(counter%15 === 0){
for (var i = 0; i < aliens.length; i ++) {
if ( ( (aliens[i].baseX + maxXDiff) < aliens[i].x ) || (aliens[i].baseX > aliens[i].x) ) {
aliens[i].velocityX = -aliens[i].velocityX; // switches the sign
}
aliens[i].x += aliens[i].velocityX;
}
}
drawAllAliens();
}
redraw();
function drawAllAliens() {
ctx.clearRect(0,0,canvas.width,canvas.height);
for (var i = 0; i < aliens.length; i++) {
aliens[i].draw();
}
}
} else {
alert("you need a better browser to play this game");
}
}
alien();

Categories