I've created a function that adds a graphic to the canvas stage and animates it via a tween, waits a few milliseconds then spawns another
There are a few things I could do with some help with,
firstly I need to slow down the assets to a stop after a few seconds of them playing at normal speed (I'm animating lines in the middle of a road)
secondly when the animation starts there's nothing on the screen,because they are road marking something has to display at start
and any ideas on how I remove each item when animation finished
Here's what I have so far
//this is called from the tick handler
function lines(){
duration = 1000;
spawnCounter--;
console.log(spawnCounter)
if(spawnCounter == 0){
spawnCounter = sNum//20
bolt = new lib.Bolt();
bolt.x=280
bolt.y = 120;
bolt.rotation = -66;
stage.addChild(bolt);
createjs.Tween.get(bolt).to({x:0,y:0, scaleY:.6, scaleX:.6},duration)
}
}
Removing items at the end of the tween is fairly simple:
createjs.Tween.get(bolt)
.to({x:0,y:0, scaleY:.6, scaleX:.6}, duration)
.call(function(event) {
stage.removeChild(bolt);
});
Slowing down the entire animation the way you have made it might be tricky, since you would probably want the assets to slow down at the same rate, so you can not just change the duration of the tween. You might want to consider NOT using a tween for the animation, and instead just controlling the "visible" items in the tick, and removing them when they get too far.
I created a quick sample showing how this could work.
http://jsfiddle.net/wj15awj4/
Generate the items after a certain "distance" has elapsed
Remove items past the edge
Scale and alpha the items based on the position. The scale is kind of odd, since the road has no perspective. This would be better solved transforming the canvas using CSS or WebGL.
When the road is clicked, the "speed" is tweened down (or back up), and since the items are created based on how much "distance" has passed, they will continue to be created at roughly the same rate, despite moving slower over time.
Hope this helps!
Related
I have a working animation that uses only EaselJS to load and display images. The whole animation works quite well, but images appear and disappear immediately. I would like them to fade in and out over time. Here's a small jsfiddle that might illustrate the problem better: http://jsfiddle.net/tNLyx/
var stage = new createjs.Stage("canvas");
var shape = new createjs.Shape(new createjs.Graphics().f("#f00").dc(0,0,100)).set({x:100,y:100});
stage.addChild(shape);
stage.update();
shape.addEventListener("click", function(){
//Shape will now disappear quickly. I would like it to fade out, by tweening its alpha or opacity or something. Any help would be greatly appreciated!
stage.removeChild(shape);
stage.update();
});
When you click the red circle, it simply disappears, immediately. I would like it to fade out slowly. I have done some research but am having trouble finding good documentation - it appears that what I need is the TweenJS "sister" library, and at least some of the following code:
createjs.Ticker.setFPS(30); //Sets frames-per-second for TweenJS
createjs.Tween.get(shape).to({alpha: 0},1000);
I believe the last line is supposed to get the "shape" object which I made previously, then set up an animation which animates its alpha property (which I assume is 1 by default when added to the stage, but I'm not sure), and reduces it to this 0 over 1000 milliseconds. The code doesn't actually do anything - any help would be much appreciated!
You need to ensure you update the stage during a tween, or whenever a property changes.
Here is a quick fiddle using your code. I added a tick listener to the stage, which will redraw the stage constantly. http://jsfiddle.net/lannymcnie/FVw7E
createjs.Ticker.addEventListener("tick", stage);
Note that you may want to control when the tick is added and removed, so it isn't unnecessarily redrawing the stage when nothing is changing. A quick way would be to add a call to the end of the tween.
createjs.Tween.get(shape).to({alpha: 0},1000).call(doneAnimating);
function doneAnimating() {
createjs.Ticker.removeEventListener("tick", stage);
}
Cheers.
I've created a jQuery plugin based on somebody else's Chrome experiment that inserts a canvas element into your target element, and draws an interactive starfield in the canvas.
Each time you resize the window, the canvas element is removed and then restored so that its size matches its parent element and everything animates properly; it's responsive.
However, whenever it's restored, the speed of the animation increases. Why does it do this? I thought all the variables (including speed) were reset to their defaults with the this.start() method.
You can see the code (and demo) on CodePen; you can also fork it on Github, though I think the Github version is several commits behind my own.
(Also, this is my first real jQuery plugin, so if you see any issues, by all means, let me know.)
Any clues?
Using cancelAnimationFrame alone won't necessary stop the animation loop (it turns out).
To be absolute sure you will need to use a conditional check as well - a generic example:
var isPlaying; /// our condition
function loop() {
/* funky stuff here */
If (isPlaying === true)
requestId = requestAnimationFrame(loop);
}
Then starting it:
functiom start() {
isPlaying = true;
loop();
}
Now when you want to stop the animation you need to do:
function stop() {
isPlaying = false;
/// kill any request in progress
if (requestId) cancelAnimationFrame(requestId);
}
If you don't do this you risk stacking calls to the loop - for example:
If you resize and cAF isn't stopping rAF from re-trigger the loop, the old loop will still run in the background and you will start a new loop on top of that.
That is why you see speed increases as the old and the new loop will both increment the positions before the stars are drawn to screen.
On the third re-size yet another loop is started, and eventually the whole thing will block the browser.
However
Instead of utilizing start and stop of the loop I would recommend you the following approach:
Create canvas once
Start the loop only once
In this case, a re-factoring of the whole re-size mechanism could be beneficial (for instance, separate needed initializations (width and height of element) from first time initializations that can be re-used later).
There is no need to re-init the stars for each re-size as you will use the width and height to check their boundaries (canvas will do the clipping).
When resizing you can consider using a conditional flags to prevent render while re-sizing.
Although generally, a condition to block rendering while canvas changes size is really not necessary due to the single-thread nature of JavaScript and in cases such as this you do boundary check on current element size. Canvas itself will take care of the clipping for you.
And that being said: there should be no need to re-create the canvas element each time.
This creates an unnecessary overhead. Simple set new width and height on its properties if canvas is already created:
if (typeof canvas === 'undefined')
canvas = /* only create if it doesn't exist */
canvas.width = width;
canvas.height = height;
PS: I "hampered" a version with some brute-force-ish implementations of the above. It's far from complete or of high quality but takes out some of the pain for the sake of example to give you a couple of pointers.
Please adopt to suit your needs.
Update:
To include more info from the additional comments:
when a new size is set on a canvas element its context is reset to default (fillStyle becomes transparent, strokeStyle black, transform is reset and so on).
This means that all non-default settings must be set again after each new size is set.
Setting a new size may (and typically do) clear the content of the canvas as well so that all pixels becomes transparent black.
For anybody struggling with manually updating a canvas element's dimensions:
Resizing the canvas element results in it discarding anything that's been drawn to it up to the point of the resize.
This script's animation should have continued to draw to the canvas after resize, but the only thing that would update was the fillRect of the background; the stars disappeared.
The only way to get the stars back after changing the dimensions of the canvas element: an extra call to context.strokeStyle. I have no idea why; if anybody could shed some light on the matter, I'd be much obliged.
Edit: As per comments below, everything in the canvas resets—including stroke and fill style (both default to black, apparently). So as the resize fires, I had to re-define stroke and fill styles.
I'm writting a js game with "gameQuery" jQuery plugin, a shooting game.
While there are many bullets (for examples 100 or more), the animation would turn very slowly.
I use code blow for cycling moving DOM, means excute function per 20 millisecond. All bullets are stored in an array,
$.playground().registerCallback(function(){
for(var i = 0; i < bulletList.length; i++) {
//move bullet
...
}
}, 20);
How could I optimize my code to enhance efficiency? Thx!
Here are a few things I can think of:
Are you doing collision detection with the bullets. If yes this is
probably the point where things slow down since displaying hundreds
of sprites should be a problem in itself.
Are those bullet animated (with more than one frame?) If yes you may
want do try without animation to see how this impact the
performances.
If all the bullets move in the same direction at the same speed you
can put them all in a group and then move the group instead.
If they don't move in the same direction you can still put them into
a group. You will then detach this group before moving them all.
Once you are done you can just append you group again to the game.
This one is more complicated to implement but you could try to
detect that the player fired a series of bullets at regular
intervals in a given direction and represent them with a single
sprite with a repeating image of a bullet.
I'm making a little game on jsbin and everything so far is going well but I'm have a slight problem. The goal of the game is to click the randomly appearing circle as many times as possible in one minute. I want it to output the time left and the score in the corners, and I have done so. The problem is that they are overwriting each other. This is because to prevent flickering I decided not to use
c.clearRect(0,0,canvas.width,canvas.height);
instead drawing a clearRect just over the circle when its clicked. I want to do a similar thing with text. I used this line:
c.clearRect(0,fontSize,c.measureText(timeLeft),fontSize);
this should work but it has no effect. I've tried everything, but I don't know what's wrong with this line. My only other theroy is that is in the wrong spot in the code, but I haven't found a problem with that.
Here is the link to the current version I'm working on:
http://jsbin.com/touchgame/10/edit
Thanks!
measureText() returns an object with a width property, so you need to use c.measureText(timeLeft).width.
Also, you decreased the timeLeft and then called clearRect, which will clear a rectangle based on the new width for timeLeft. You want to clear based on the width for the "old" timeLeft value and then decrease the timeLeft:
if (timeLeft < 1){
c.clearRect(0,fontSize,c.measureText(timeLeft).width + 5,fontSize*1.5);
timeLeft--;
//clear over time output
console.log(c.measureText(timeLeft));
}
This should work. Because the way drawing text works, it's not trivial to know exactly the bounding box of the text, so that's why we clear a larger area than fontSize. You could use c.textBaseline = 'top', which would place the text with the top coordinate at the y you specify instead of the baseline of the text at y.
Finally, I think it's an easier approach to clear the canvas completely and redraw everything when you want to update the graphics. If you clear the canvas and then immediately redraw evrything you won't get any flickering. The performance hit of redrawing everything is usually neglible in most cases, and it makes things a lot simpler.
I wrote a little drawing script (canvas) for this website: http://scri.ch/
When you click on the document, every mousemove event basically executes the following:
- Get coordinates.
- context.lineTo() between this point and the previous one
- context.stroke() the line
As you can see, if you move the cursor very fast, the event isn’t triggering enough (depending on your CPU / Browser / etc.), and a straight line is traced.
In pseudocode:
window.addEventListener('mousemove', function(e){
myContext.lineTo(e.pageX, e.pageY);
myContext.stroke();
}, false);
This is a known problem, and the solution is fine, but I would like to optimize that.
So instead of stroke() each time a mousemove event is triggered, I put the new coordinates inside an array queue, and regularly draw / empty it with a timer.
In pseudocode:
var coordsQueue = [];
window.addEventListener('mousemove', function(e){
coordsQueue.push([e.pageX, e.pageY]);
}, false);
function drawLoop(){
window.setTimeout(function(){
var coords;
while (coords = coordsQueue.shift()) {
myContext.lineTo(coords[0], coords[1]);
}
myContext.stroke();
drawLoop();
}, 1000); // For testing purposes
}
But it did not improve the line. So I tried to only draw a point on mousemove. Same result: too much space between the points.
It made me realize that the first code block is efficient enough, it is just the mousemove event that is triggering too slowly.
So, after having myself spent some time to implement a useless optimization, it’s your turn: is there a way to optimize the mousemove triggering speed in DOM scripting?
Is it possible to “request” the mouse position at any time?
Thanks for your advices!
If you want to increase the reporting frequency, I'm afraid you're out of luck. Mice only report their position to the operating system n times per second, and I think n is usually less than 100. (If anyone can confirm this with actual specs, feel free to add them!)
So in order to get a smooth line, you'll have to come up with some sort of interpolation scheme. There's a whole lot of literature on the topic; I recommend monotone cubic interpolation because it's local, simple to implement, and very stable (no overshoot).
Then, once you've computed the spline, you can approximate it with line segments short enough so that it looks smooth, or you can go all-out and write your own Bresenham algorithm to draw it.
If all this is worth it for a simple drawing application... that's for you to decide, of course.
Cool site, unfortunately there is no way to request the current position of the mouse with JavaScript, the only hooks you have are the events you're already using. If you must have more control I'd look at using flash where you can change the frame rate and request the mouse position.
trace("Mouse X: " + _xmouse);
trace("Mouse Y: " + _ymouse);