//making custom function for a fish
drawFish=function (centerX,centerY){
//using draw function for animation
draw=function(){
var bodyLength = 115;
var bodyHeight = 74;
var bodyColor = color(162, 0, 255);
noStroke();
fill(bodyColor);
// body
ellipse(centerX, centerY, bodyLength, bodyHeight);
// tail
var tailWidth = bodyLength/4;
var tailHeight = bodyHeight/2;
triangle(centerX-bodyLength/2, centerY,
centerX-bodyLength/2-tailWidth, centerY-tailHeight,
centerX-bodyLength/2-tailWidth, centerY+tailHeight);
// eye
fill(33, 33, 33);
ellipse(centerX+bodyLength/4, centerY, bodyHeight/5, bodyHeight/5);
centerX++;
};
};
//calling custom function
drawFish(146,208);
drawFish(207,212);
drawFish(305,306);
drawFish(114,309);
drawFish(300,100);
I am trying to make a simple animation of 5 fishes in a tank moving horizontally. I wrote the code for one fish and then I make it a custom function so I can call it as many times as I want. Then I put the
draw =function(){} for animation to move the fishes. This code works until I put the draw() function into it otherwise only one fish remains and others disappear. How can we use the draw function to make an animation inside this custom function so that it works on every fish.
You can try using the operator new. I am not entirely sure if it will work in the way you coded it, but you can do something like:
function drawFish(centerX, centerY) {
this.centerX = centerX;
this.centerY = centerY;
// draw your fish here using centerX and centerY as it's X and Y
}
var fish = new drawFish(0,0);
var fish1 = new drawFish(50,50);
function Loop() {
fish.centerX++ ; fish.centerY++ ;
fish1.centerX++; fish1.centerY++;
console.log('Fish position:', fish.centerX, fish.centerY)
console.log('Fish1 position:',fish1.centerX, fish1.centerY);
}
setInterval(Loop, 500)
Related
I'm trying to draw a circle in the canvas in javascript but it's not working and I'm not getting an error. I've done it before and it usually works, but for some reason now it isn't. Any help would be highly appreciated.
// VARIABLES
var x = 100 ;
var y = 100;
var r = 50;
var c = 272;
var a = 0.9;
// EXECUTABLE CODE
circle();
// FUNCTION
function circle(x,y,r,c,a){
ctx.beginPath();
ctx.arc(x,y,r,0,Math.PI*2);
ctx.fillStyle = "hsl("+c+", 100%, 50%,"+a+")";
ctx.fill();
}
The reason why it is not working is because you did not pass in the arguments x,y,r,c,a when invoking the circle function. So, do this circle(x,y,r,c,a) and it should work for you.
I've been working on a game that's sort of a Worms clone. In it, the player rotates a cannon with the up up and down keys (it's a 2D game) to fire at enemies coming from above. I use the context.rotate() and context.translate() methods when drawing the cannon, then immediately context.restore() back to the default canvas.The cannon is the only thing (for now) that's rotated.
The problem is, I want to accurately show projectiles coming from the top of the cannon. For this, I need to know the top of the cannon's coordinates at all times. Normally, this is something I could easily calculate. However, because the canvas is rotated only before the cannon is drawn, it's not as simple.
Just use simple trigonometry to track the top:
var canonTopX = pivotX + Math.cos(angleInRadians) * canonLength;
var canonTopY = pivotY + Math.sin(angleInRadians) * canonLength;
You can choose to render the canon using transformations of course, or share the math.
ctx.translate(pivotX, pivotY);
ctx.rotate(angleInRadians);
//render canon from (0,0) pointing right (0°)
ctx.setTransform(1,0,0,1,0,0); // instead of save/restore
// calc canon top for projectiles here
var ctx = c.getContext("2d");
var canonLength = 70;
var angleInRadians = 0;
var angleStep = 0.03;
var pivotX = ctx.canvas.width>>1;
var pivotY = ctx.canvas.height>>1;
ctx.fillStyle = "#000";
ctx.strokeStyle = "#c00";
(function loop() {
angleInRadians += angleStep;
render();
requestAnimationFrame(loop);
})();
function render() {
ctx.clearRect(0,0,ctx.canvas.width,ctx.canvas.height);
ctx.translate(pivotX, pivotY);
ctx.rotate(angleInRadians);
ctx.fillRect(0, -5, canonLength, 10);
ctx.setTransform(1,0,0,1,0,0); // instead of save/restore
var canonTopX = pivotX + Math.cos(angleInRadians) * canonLength;
var canonTopY = pivotY + Math.sin(angleInRadians) * canonLength;
ctx.beginPath();
ctx.arc(canonTopX, canonTopY, 9, 0, 6.3);
ctx.stroke();
}
<canvas id=c width=600 height=180></canvas>
I'm trying to execute a function 'draw' when a button is clicked (button id is also draw). When clicking the button the function runs successfully, however the repeated iterations do not run. I've therefore narrowed the issue to the setTimeout. I get the following message "draw is not a function". This is confusing because it definitely IS a function. Any help is appreciated. Thanks.
var draw1 = document.getElementById('draw');
draw1.addEventListener('click',draw);
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
var x = 0;
var y = 0;
function draw(aaa,bbb){
ctx.save();//save the cavas state if required
ctx.clearRect(0,0,100,100)//clear canvas for redrawing
ctx.fillStyle = 'rgba(0,200,0,1)';//style a green box
ctx.fillRect (x, 20, 50, 50);//draw the rectangle
ctx.restore();//restore the canvas state if saved
x += 5;//increment the x position by some numeric value
console.log(x);
console.log(y);
var loopTimer = setTimeout('draw(' + x +','+ 0 +')',200);
}
Don't use strings for function call. It is a really bad practice.
Change it to an anonymous function:
var loopTimer = setTimeout(function() {
draw(x, 0);
}, 200);
As long as your x and y are global and you don't use arguments, you can remove them from your draw method and call it even simpler, without closures:
function draw(){
ctx.save();//save the cavas state if required
ctx.clearRect(0,0,100,100)//clear canvas for redrawing
ctx.fillStyle = 'rgba(0,200,0,1)';//style a green box
ctx.fillRect (x, 20, 50, 50);//draw the rectangle
ctx.restore();//restore the canvas state if saved
x += 5;//increment the x position by some numeric value
console.log(x);
console.log(y);
var loopTimer = setTimeout(draw, 200);
}
I am trying to draw the first Green tank inside my canvas but i think i am missing something in my code
jsfiddle:
draw: function () {
tankImg.onload = function () {
ctx.drawImage(tankImg, this.Pos * this.w, 0, this.w, this.h, this.x, this.y, this.w, this.h);
};
}
Can anyone help me please?
Ok, first of all thanks so much for the fiddle - makes everything a billion times easier.
There are two three errors in your code - the first is the tankImg.onload function. The onload function only fires once - when the image first loads.
What you want is tankImg.complete which will return true if loaded and false if not.
Secondly, you cannot assign 'ch - this.h' for the y property because 'this' isn't defined until, well, you finish defining it. What you can do is set the y value in your draw code.
Thirdly in javascript you can't do var cw, ch = 400;
$(document).ready(function () {
var cw = 400;
var ch = 400;
var ctx = $("#MyCanvas")[0].getContext("2d");
var tankImg = new Image();
tankImg.src = "http://oi62.tinypic.com/148yf7.jpg";
var Fps = 60;
var PlayerTank = {
x: cw / 2,
w: 84,
h: 84,
Pos: 2,
draw: function () {
ctx.drawImage(tankImg, this.Pos * this.w, 0, this.w, this.h, this.x, ch - this.h, this.w, this.h);
}
};
var game = setInterval(function () {
if (tankImg.complete) {
PlayerTank.draw();
PlayerTank.x++;
}
}, 1000 / Fps);
});
Here is the completed jsfiddle with bonus movement for fun.
Edit: Ken's version of handling the .onload is much better.
There are a few minor issues with the code which prevents:
Image to be loaded properly
Some uninitialized variables
Some inaccessible variables
The first variable that is undefined (producing NaN for the drawImage() method) is:
var cw; /// is not defined
The second more important issue is the way you handle the image loading.
You are currently setting the onload handler inside the draw method and re-setting it for each frame. Here the onload will probably not be caught and using the draw code inside it will at best only draw the image once as onload is only called once.
Change the code around a little like this:
var tankImg = new Image();
tankImg.onload = start; /// add the onload handler before setting src.
tankImg.src = "http://oi62.tinypic.com/148yf7.jpg";
Then move your invoke of setInterval to start:
var game; /// keep this var outside (in global)
function start() {
game = setInterval(function () {
PlayerTank.draw();
}, 1000 / Fps);
}
The third issue is that this.h is not defined when you try to use it. Add a manual value (as in the modified fiddle) or wait until draw() is called to calculate it.
Now it should work:
Modified fiddle here
Hello and thank you for your help in advance.
I am trying to push/create a new "ring" every couple seconds. I have a ring with a couple variables for the X and Y. The problem I am encountering is, how do I get a new ring and also increment the variables? I need a new variable name for every ring?
Here is how far I have gotten so far:
http://codepen.io/hossman/pen/AfwkF
You can see in the demo how 1 ring goes out, but I want more than 1 ring to go out of my eyes. So for instance 1 ring goes and then it waits a second and then shoots out another ring, so now there are 2 rings on the canvas, then 3, then 4, etc.... I have thought of multiple ways like using arrays and setTimeouts, but I cant put my finger on it. The only other idea I have is to create multiple variables with different names and have each ring be incremented, but thats not very D.R.Y.
Anyhelp?
Please ask questions if I didn't explain it good enough. Thanks again!
Add this to your global vars at the top (and set to whatever you want the distance to be between circles):
var distanceApart = 40;
Then update your main loop like this:
requestAnimationFrame(function print() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
var leftRing = new Ring(x, y);
var rightRing = new Ring(x2, y2);
var temp = startRadius;
var temp2 = 0;
while(temp > 0){
leftRing.draw(ctx, startRadius - temp2 , 'red');
rightRing.draw(ctx, startRadius - temp2 , 'red');
temp2 = temp2 + distanceApart;
temp = temp - distanceApart;
}
startRadius += increase;
requestAnimationFrame(print);
});
Forked here: http://codepen.io/anon/pen/plBmj
(Looks very memorizing!)
I would rewrite parts of your code to enable this. For example I would rewrite your Ring class as follows:
var Ring = defclass({
constructor: function (x, y, r) {
this.x = x;
this.y = y;
this.r = r;
},
draw: function (context) {
context.beginPath();
context.arc(this.x, this.y, this.r, 0, Math.PI * 2);
context.stroke();
return this;
},
addRadius: function (r) {
return new Ring(this.x, this.y, this.r + r);
}
});
Your Ring class constructor now takes x, y and a radius r. The addRadius function returns a new Ring instead of mutating the original one. This is good because immutability makes your code easier to work with. Oh, and defclass is declared as:
function defclass(prototype) {
var constructor = prototype.constructor;
constructor.prototype = prototype;
return constructor;
}
Then we create the two rings for your eyes:
var radius = 10;
var delta = 0.1;
var left = new Ring(cx - (cx / 3.6), cy - 5, radius);
var right = new Ring(cx + (cx / 3.6), cy - 10, radius);
After that we call the animation loop:
var interval = 50 / 3;
var start = Date.now();
loop(start, [left, right]);
Since we want to playback at 60 FPS the interval is 1000 / 60 which can be simplified to 50 / 3. The animation loop is defined as follows:
function loop(last, rings) {
var next = last + interval;
context.clearRect(0, 0, width, height);
var newRings = rings.map(function (ring) {
return ring.draw(context).addRadius(delta);
});
var now = Date.now();
setTimeout(loop, next - now, next,
Math.floor((now - start) / 1000) === rings.length / 2 ?
[left, right].concat(newRings) : newRings);
}
Here's what's happening:
First we clear the screen.
Then we draw all the rings and increase their size.
If one second has elapsed we add two new rings to the array.
Finally we calculate when to call loop again so that it fires after the correct interval.
See the demo: http://jsfiddle.net/LAr76/