var context = document.getElementById("canvas").getContext("2d");
for(var i = 0; i< savedMove.length; i++){
doSetTimeout(i);
}
function doSetTimeout(i) {
setInterval(function() { animate(savedMove[i][0], savedMove[i][1]); }, 100);
}
function animate(xPos, yPos) {
context.fillStyle = "red";
context.fillRect(xPos, yPos, 5, 5);
}
I have every x and y position move inside of 2D array (savedMove) and I want to draw with array information with delay. But Canvas does not draw this. I keep debugging but I cannot figure out the problem.
You're setting savedMove.length timers to tick parallelly every 100 milliseconds. I'm pretty sure this is not what you want, though it's hard to guess what it is. First I would change setInterval to setTimeout and make them fire at different times, 100 ms away from each other:
function doSetTimeout(i) {
setTimeout(function() { animate(savedMove[i][0], savedMove[i][1]); }, 100 * i);
}
Note that this is not the best way to do it, but certainly better than the original code.
Then you can debug it, 'cause you might draw out of the visible canvas:
console.log("canvas size:", document.getElementById("canvas").width, document.getElementById("canvas").height);
function animate(xPos, yPos) {
context.fillStyle = "red";
context.fillRect(xPos, yPos, 5, 5);
console.log("animate:", xPos, yPos);
}
Related
I'll like to make some elements in an array appear at different times, the time will be decreasing over time (so the elements will appear faster and faster). I had tried with setTimeout and setInterval with no luck, I think it is because I'm looping through the array.
Here's a simple p5.js example that should hopefully point you in the right direction.
I'm calling the setTimeout function for every object on initialisation. The delay of the timeout is incremented by a value incrementor which decreases each iteration.
let circles = [];
let count = 100;
let incrementor = 500;
let delay = 500;
function setup() {
createCanvas(400, 400);
for (let i = 0; i < count; i++) {
let circle = {
x: random(width),
y: random(height),
show: false,
}
incrementor *= 0.9;
delay += incrementor;
setTimeout(() => circle.show = true, delay);
circles.push(circle);
}
}
function draw() {
background(220);
noStroke()
fill(0, 128, 128);
for (let circle of circles) {
if (circle.show) {
ellipse(circle.x, circle.y, 10, 10);
}
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/p5.min.js"></script>
You cannot achieve that via intervals. Yet, it's possible with recursive timeouts. For example, let's say that the time is decreasing by 2x:
const initialDuration = 10000;
function someAnimation(duration) {
// Your animation code here...
setTimeout(() => someAnimation(duration / 2), duration);
}
someAnimation(initialDuration);
I want the program to loop trough each number in the for loop and create a circle with the radius of that number squared but it doesn't seem to work. I only creates a circle with the radius of the last number in the for loop.
I've tried creating a separate function and return the value and putting into my draw function, but that didn't seem to work.
function setup() {
createCanvas(600, 600);
}
function draw() {
for (i = -1; i <= 10; i++) {
newI = i ** 2;
};
background(250);
circle(300, 300, newI);
//ignore the lines those are just the axis//
line(300, 0, 300, 600);
line(0, 300, 600, 300);
}
I want each new radius of each new circle to be that of the number in the for loop squared.
As mentioned by #Tim Biegeleisen - the circle() and line() should be in the loop, but another approach is to have them separate.
Rather than putting the logic into the loop - have the loop iteration call a separate named frunction and pass the new i value as the argument.
EDIT: loop changed to decrement in order to reverse the order of radius.
function setup() {
createCanvas(600, 600);
}
function draw() {
for (i = 10; i >= -1; i--) {
createCircle(i ** 2)
};
}
function createCircle(newI){
background(250);
circle(300, 300, newI);
line(300, 0, 300, 600);
line(0, 300, 600, 300);
}
I am new to Javascript in a canvas, and javascript in general.
Basically, what I am trying to do is:
have many different randomly spawning fire balls (images), that all start at a fixed y value and a random x value.
They should then fall at a speed of a variable.
I got the random x position, and the fixed y value, but I don't know how I can have a separate falling variable for each new image that tracks it's speed, such as applying this to each individual fire ball:
fireBallSpeed = 10;
fireBallTop = 0;
if (randomSpawn == 1){
fireBallTop += fireBallSpeed;
fireBall.style.top = fireBallTop + 'px';
ctx.drawImage(fireBall, randomX, fireBallTop, 50, 50);
}
You should save each fireball into an array and loop over the array updating each one's position.
let fireballs = []
const canvas = document.querySelector('canvas')
const ctx = canvas.getContext('2d')
function gameLoop() {
// Clear the canvas
ctx.clearRect(0, 0, 800, 300)
// Loop over each fireball and update their positon
fireballs.forEach(fireball => {
ctx.fillRect(fireball.x, fireball.y, 10, 10)
// Set the new position for the next frame using the speed
fireball.y += fireball.speed
})
// Request another frame
requestAnimationFrame(gameLoop)
}
function gameInit() {
// Create 5 fireballs
for (let i = 0; i < 5; i++) {
fireballs.push({ x: Math.random() * 280, y: 5, speed: Math.random() * 2 })
}
}
// Init the game
gameInit()
// Start the game loop
// This function should only be used for the drawing portion
// and setInterval should be used for the logic
// For simplicity I am going to use this for both
requestAnimationFrame(gameLoop)
<canvas width="800" height="300"></canvas>
I'm curious to know how applications such as Adobe Photoshop implement their drawing history with the ability to go back or undo strokes on rasterized graphics without having to redraw each stroke from the beginning...
I'm wanting to implement a similar history function on an HTML5 drawing application I'm working on but duplicating the canvas after every stoke seems like it'd use too much memory to be a practical approach, especially on larger canvas'...
Any suggestions on how this might be implemented in a practical and efficient manner?
I may have a solution.....
var ctx = document.getElementById("canvasId").getContext("2d");
var DrawnSaves = new Array();
var Undo = new Array();
var FigureNumber = 0;
var deletingTimer;
function drawLine(startX, startY, destX, destY) {
ctx.beginPath();
ctx.moveTo(startX, startY);
ctx.lineTo(destX, destY);
ctx.stroke();
var Para = new Array();
Para["type"] = "line";
Para["fromX"] = startX;
Para["fromY"] = startY;
Para["toX"] = destX;
Para["toY"] = destY;
DrawnSaves.push(Para);
FigureNumber++;
}
function undo() {
ctx.beginPath();
ctx.clearRect(0, 0, 500, 500);
Undo[FigureNumber] = DrawnSaves[FigureNumber];
DrawnSaves[FigureNumber] = "deleted";
FigureNumber--;
drawEverything();
startTimeoutOfDeleting();
}
function undoTheUndo() {
FigureNumber++;
DrawnSaves[FigureNumber] = Undo[FigureNumber];
drawEverything();
clearTimeout(deletingTimer);
}
function drawEverything() {
for (i = 0; i < DrawnSaves.length; i++) {
if (DrawnSaves[i].type == "line") {
ctx.beginPath();
ctx.moveTo(DrawnSaves[i].fromX, DrawnSaves[i].fromY);
ctx.lineTo(DrawnSaves[i].toX, DrawnSaves[i].toY);
ctx.stroke();
}
}
}
function startTimeoutOfDeleting() {
setTimeout(function() {Undo[FigureNumber] = "deleted";}, 5000);
}
This is really simple, first I draw a line when the function is called and save all his parameters in an array. Then , in the undo function I just start a timer do delete the figure drawn i 2000 miliseconds, clears the whole canvas and makes it can't be redrawn. in the undoTheUndo function, it stops the timer to delete the figure and makes that the figure can be redrawn. In the drawEverything function, it draws everything in the array based on it's type ("line here"). That's it... :-)
Here is an example working : This, after 2sec UNDOs then after 1sec UNDOTHEUNDO
I am currently writing a simple snake game.
http://jsfiddle.net/jhGq4/3/
I started with drawing the grid for the background
function fill_grid() {
ctx.beginPath();
var row_no = w/cw;
var col_no = h/cw;
for (var i=0;i<row_no;i++)
{
for (var j=0;j<col_no;j++)
{
ctx.rect(i*cw, j*cw, (i+1)*cw, (j+1)*cw);
ctx.fillStyle = 'black';
ctx.fill();
ctx.lineWidth = 1;
ctx.strokeStyle = '#135d80';
ctx.stroke();
}
}
}
It works great but when i paint the snake, the position gets wrong and the length is doubled. I tried to console.log the x position of my snake but they are correct.
function paint_cell(x, y)
{
console.log(x*cw);
console.log((x+1)*cw);
ctx.fillStyle = '#fff799';
ctx.fillRect(x*cw, y*cw, (x+1)*cw, (y+1)*cw);
ctx.lineWidth = 1;
ctx.strokeStyle = '#135d80';
ctx.strokeRect(x*cw, y*cw, (x+1)*cw, (y+1)*cw);
}
***Because someone wants to learn how to make a snake game,
this is my final solution for this game.
http://jsfiddle.net/wd9z9/
You can also visit my site to play:
use WSAD to play.
http://www.catoyeung.com/snake2/single.php
:D
I tested this alternative init function:
function init()
{
fill_grid();
// create_snake1();
// paint_snake1();
paint_cell(5, 5)
}
Which paints a square starting at coords (5,5), but of size 6x6.
I believe you are misusing the fillRect() method. Use
ctx.fillRect(x*cw, y*cw, cw, cw);
Instead of
ctx.fillRect(x*cw, y*cw, (x+1)*cw, (y+1)*cw);
the same probably applies to strokeRect.
Incidentally, I was looking at your grid-fill function. You fill i*j adjacent squares, which works, but you really only need i vertical lines and j horizontal ones - which is a lot less processing. Run a quicker loop with fewer calculations:
function fill_grid() {
ctx.beginPath();
ctx.fillStyle = 'black';
ctx.fillRect(0,0,w,h);
for (var i=0;i<=h;i+=cw)
{
ctx.moveTo(0,i);
ctx.lineTo(w,i);
ctx.moveTo(i,0);
ctx.lineTo(i,h);
}
ctx.stroke();
}
I would also only define line width and stroke colour once, as you initialise the canvas. You may not need to worry about this of course. But this kind of care can make a difference if you refresh the grid often to animate your snakes.