HTML5 Animation, capture mouse movement without interruption? - html

I have a slight problem here I try to solve. As I start to do animation with HTML5 and Canvas I want to have a constant animation flow and also be able to capture mouse movement without interrupting the animation flow. This right now seems like a problem. Ill bring
some code from my test code here.
function mainInit()
{
canvas = document.getElementById('canvas');
context = canvas.getContext('2d');
ballArray.push(new Ball(30,30,2,4,15,"#EEEEEE"));
setInterval(drawScene,20);
}
function drawScene()
{
// main drawScene function
clear(); // clear canvas
// draw animated objects
for(var i = 0; i < ballArray.length; i++)
{
ballArray[i].draw();
}
Event_MouseMove();
}
var messageMousePos = '';
function Event_MouseMove()
{
canvas.addEventListener('mousemove', function(evt)
{
var mousePos = getMousePos(canvas, evt);
messageMousePos = "Mouse position: " + mousePos.x + "," + mousePos.y;
context.font = '10pt Calibri';
context.fillStyle = 'black';
context.fillText(messageMousePos , 5, 15);
}, false);
}
The problem is that when I move the eventListner for mouse movement overrides the draw interval and makes it go much slower. How/where should I put the code for the mouse event so it do not interrupt this draw interval, but still draw the mouse events according to the interval?

At a glance, it looks like the code will try to add an event listener every frame...While JS will dump duplicate handlers, it will slow your code down. It's unclear whether you are trying to only capture mouse movement every interval, or constantly, because your code is kinda trying to do both. Here's the best of both worlds solution:
Call addEventListener once outside the loop, and have the function it calls save the mouse position in messageMousePos. Then, within the drawScene function, put your font/fillstyle/filltext code if you really do only want the text outputting every 20ms. This might look choppy compared to how smoothly the text would change if you were constantly rendering the mouse position text.
Here is an example of constantly capturing and displaying the mouse position, as you might actually want to do.

Related

Drawing a path of points html canvas

I made a double pendulum with canvas.
Here is the result: https://jsfiddle.net/zndo9vh4/
As you guys can see a trace is drawn everytime the second part of the pendulum moves, and my way of doing that is by appending each coordinate to a "trace" array.
var trace = []
trace.push([x2,y2]);
And then I draw the trace by joining each coordinate with the last one:
for (let i = 1; i < trace.length; i++) {
c.moveTo(trace[i][0], trace[i][1])
c.lineTo(trace[i-1][0], trace[i-1][1])
}
I want to improve it. What i've tried so far is only adding coordinates that aren't already in the array, but it's not a big improvent because the lines are drawn every loop
var trace = []
if(trace.includes([x2, y2]) != true){
trace.push([x2,y2]);
}
The way I think could be a good improvement is by having 2 canvas (I don't know if its possible) and then draw each point but only in that canvas so I doesnt have to be redrawn. But I dont know how to implement that.
Thanks in advice
Your improvement idea is great. You can indeed have two canvases!
There are two ways to go about it.
Offscreen canvas
Using what's called an offscreen canvas (a canvas that is created in JavaScript but not added to the DOM), you can draw all the points onto it and then using drawImage (which can accept a canvas element) pass the canvas to the main context.
var offscreenCanvas = document.createElement('canvas');
var offscreenC = offscreenCanvas.getContext('2d');
offscreenCanvas.width = canvas.width;
offscreenCanvas.height = canvas.height;
// in animate function, draw points onto the offscreen canvas instead
// of the regular canvas as they are added
if(trace.includes([x2, y2]) != true){
trace.push([x2,y2]);
var i = trace.length-1;
if (i > 1) {
offscreenC.strokeStyle = 'white'
offscreenC.beginPath();
offscreenC.moveTo(trace[i][0], trace[i][1])
offscreenC.lineTo(trace[i-1][0], trace[i-1][1])
offscreenC.stroke();
}
}
c.drawImage(offscreenCanvas, 0, 0);
Layered Canvases
One of the downsides to the offscreen canvas approach is that you have to draw it to the main canvas every frame. You can further improve the approach by layering two canvases on top of one another, where the top one is just the pendulum and the bottom one the trace.
This way, you never have to redraw the offscreen canvas onto the main canvas, and save yourself some rendering time.
Updated jsfiddle

AS3 - How to use pixel/point detection with mouse event instead of object detection

This seems like it should be so easy that I'm embarrassed to ask, but I just can't get it.
I have a large round MovieClip (being used as a button). This MovieClip contains a PNG with a transparent background inserted into the MovieClip.
Due to its size there are large empty registration areas on the 4 corners (the bounding box).
How can I have the mouse register as being over only the circle pixels and not the blank space (of Alpha channel pixels) in the square boundary box?
Simple sample code:
public function simpleSample () : void
{
mc1.buttonMode = true;
mc1.addEventListener(MouseEvent.CLICK, doStuff);
}
public function doStuff (event:MouseEvent) : void
{
mc2.gotoAndStop(2);
}
Here are 3 different ways to accomplish this.
EDIT Since you've later explained that your button is an image, this first option won't work for you
If the shape flag on hitTestPoint works with your button (eg it's a shape), you can use hitTestPoint inside your mouse click handler to figure out if the click is actually over the object:
public function doStuff(event:MouseEvent){
//only continue if hit test point is true,
//the x and y values are global (not relative to the mc your testing as one might suppose)
//the third parameter should be true, so it takes into account the shape of object and not just it's bounds
if(mc1.hitTestPoint(stage.mouseX, stage.mouseY, true)){
mc2.gotoAndStop(2);
}
}
If the above doesn't work because you have bimtap data in your button, then an easy way to accomplish this is to just add a shape mask to the button.
So, either inside your button using FlasPro, mask everything with a circle shape, or, do it via code by doing the following when you first show the button:
var s:Shape = new Shape();
s.graphics.beginFill(0);
s.graphics.drawCircle(mc1.x + (mc1.width * .5), mc1.y + (mc1.height * .5), mc1.width / 2);
addChild(s);
mc1.mask = s;
If using an image as the button, or you want to set a threshold of how transparent to consider a click, then you can check the transparency of the pixel under the mouse:
function doStuff(event:MouseEvent){
//only continue if pixel under the mosue is NOT transparent
//first, you need a bitmap to work with
//if you know for sure the position of your bitmap, you can do something like this:
var bm:Bitmap = mc1.getChildAt(0) as Bitmap;
//annoyingly though, FlashPro makes timeline bitmaps shapes,
//so the above won't work UNLESS you take your bitmap in the FlashPro Library
//and export it for actionscript, giving it a class name, then it will be an actual bitmap on the timeline.
//As an alternative, you could (very CPU expensively) draw the whole button as a bitmap
var bmd:BitmapData = new BitmapData(mc1.width,mc1.height,true,0x00000000);
bmd.draw(mc1);
var bm:Bitmap = new Bitmap(bmd);
//we get the 32bit pixel under the mouse point
var pixel:uint = bm.bitmapData.getPixel32(bm.x + event.localX,bm.y + event.localY);
//then we grab just the Alpha part of that pixel ( >> 24 & 0xFF ).
//if the value is 0, it's totally transparent, if it's 255, it's totally opaque.
//for this example, let's say anything greater than 0 is considered good to be a click
if((pixel >> 24 & 0xFF) > 0){
mc2.gotoAndStop(2);
}
}

Canvas Animation Not Rendering

I'm new to the canvas tag and am playing around with some animation. Basically, I'm trying to setup a "ground" section composed of multiple images (similar to an 8bit side scroller game like Mario Brothers). The ground will be composed of multiple images, which I've built a constructor function to load these and tile them across the bottom.
function Ground(context,ImageName,ImgX,ImgY,ImgW,ImgH){
this.width=ImgW;
this.height=ImgH;
this.x=ImgX;
this.y=ImgY;
img=new Image();
img.onload=function(){context.drawImage(img,ImgX,ImgY,ImgW,ImgH);};
img.src='images/'+ImageName;};
This seems to work out just fine. I've then setup the rest of the animation, including a basic setup for Key Left/Right events, like so:
window.onload=function(){
var canvas=document.getElementById('canvas'),
context=canvas.getContext('2d'),
Grounds=[],
ImgX=-150; // INITIAL STARTING X FOR FIRST GROUND TILE
// INSERT GROUND ELEMENTS
for(var i=0,l=8; i<l; i++){
var ImgX+=150;
Grounds[i]=new Ground(context,"ground.png",ImgX,650,150,150);
};
// ASSIGN LEFT/RIGHT KEYS
window.addEventListener('keyup',function(event){
switch(event.keyCode){
case 37:
for(var i=0,l=Grounds.length; i<l; i++){
Grounds[i].x+=10;
};
break;
case 39:break;
};
});
// ANIMATION LOOP
(function drawFrame(){
window.mozRequestAnimationFrame(drawFrame,canvas);
context.clearRect(0, 0, canvas.width, canvas.height);
}());
};
I know exactly what my problem is, but don't know how to solve it. The animation loop is clearing the canvas every frame, but not redrawing the updated position (if any) when the user presses the left arrow key.
I'm missing the redraw part here and I'm not exactly sure how to handle this or if I'm approaching this entirely wrong. Any help is very appreciated! Thanks!
First of all you're incrementing the property x of the ground tiles but that property is not even used anywhere in your code. Modify your code so that the onload event of those image objects draws the image according to their own x property so changes to it will actually affect what is drawn. Also add the image object as a property of the Ground object so you can access it later on from outside.
Your approach is really not so good but if you want to do it without going back to 0 do it as follows:
function Ground(context,ImageName,ImgX,ImgY,ImgW,ImgH){
this.width=ImgW;
this.height=ImgH;
this.x=ImgX;
this.y=ImgY;
var self = this; // Add local reference to this Ground instance
this.img=new Image(); // img is now a property too
this.img.onload=function(){context.drawImage(this, self.x, self.y,self.width,self.height);};
this.img.src='images/'+ImageName;};
Ok so now you can change the property x of the ground tiles and call the draw function of it again (which is the onload event).
Grounds[i].x+=10;
Grounds[i].img.dispatchEvent(new Event("load"));
Please note that you should really make the updates of all the values first and then all the draw calls separately.
Can you not just add a draw method? You usually so something like this:
init -> update -> clear, redraw -> update -> clear, redraw -> ...
// ANIMATION LOOP
(function drawFrame(){
window.mozRequestAnimationFrame(drawFrame,canvas);
context.clearRect(0, 0, canvas.width, canvas.height);
contect.drawImage(...);
}());

action script 3 - is it possible to trigger click event only when mouse is clicked on the image part?

I have a problem and I have potential solution. But I wanted to confirm if there is an easy and simple way to solve my problem.
App type:
Isometric Game
Problem statement:
I am loading images in my flash app and have mouse events attached to them.
The images I load are prop images like vehicles, trees, buildings etc., and all of them are transparent.
Example: Red ball asset (please ignore the yellow background which I applied to describe the problem)
If I click on the actual image area (colored in red), then every thing works perfect
I don't want to trigger mouseevent when I click on empty image part (or transparent area, which I have shown in yellow color)
There is one way I know by creating masks in flash. I don't want to do it unless that is the final option left because I load image assets instead of flash assets and I don't want to create a new mask asset for all the assets
There is another method I was going to adopt by using getPixel method of Bitmap. Which is discussed here.
But there is another problem with this method.
I might be able to ignore the click event when I click on the empty part of the asset but if there is some other asset is behind the image in the same location, then I need to process the click event for the occluded image.
Well, thinking of solution to this problem takes me to the getObjectsUnderPoint where I can scan the occluded assets
Well, what you proposed as a solution is 100% valid. Just move the logic of determining what game object is clicked outside of that object.
Listen for MOUSE_DOWN/MOUSE_UP events at container which contains your game objects.
Catch an event
Check if the game object which is the target of this event is transparent at this point using BitmapData.getPixel32
If it is use getObjectsUnderPoint to find out all other game objects at this point
Find in a loop the first object which is not transparent at this point
Now you got the actual object which is hit.
One interesting solution is to use Sprite objects with the individual non-transparent pixels burnt onto them.
Suppose this is your Loader "complete" handler:
private function loaderCompleteHandler(event:Event):void
{
// Loader is not our child, we use a Sprite instead (below).
var loader:Loader = Loader(event.target);
var sprite:Sprite = new Sprite();
addChild(sprite);
var w:Number = loader.content.width;
var h:Number = loader.content.height;
// Use transparent bitmap.
var bitmapData:BitmapData = new BitmapData(w, h, true, 0);
bitmapData.draw(loader.content);
// Now burn the image onto the Sprite object, ignoring
// the transparent pixels.
for (var xPos:int = 0; xPos < w; xPos++) {
for (var yPos:int = 0; yPos < h; yPos++) {
var pixel32:uint = bitmapData.getPixel32(xPos, yPos);
var alpha:int = pixel32 >>> 24;
if (alpha != 0) {
sprite.graphics.beginFill(pixel32 & 0xFFFFFF, alpha / 0xFF);
sprite.graphics.drawRect(xPos, yPos, 1, 1);
sprite.graphics.endFill();
}
}
}
}
Essentially you want "empty" pixels that aren't clickable, and fully transparent pixels aren't quite the same thing. With this solution you get empty pixels.
Only problem is that this might be slow. Give it a shot.

HTML5 webpage animation

Does anybody know how to achieve something like that?
http://teamviget.com/#!lift-off
I want to do something similar but I'm something new in html5 and all this stuff
Thanks!
Of course you can do. First of all the you gotta draw the background image. And provide two buttons on either side. Onclick of these buttons you call a function... which inturn calls an setInterval() function that animates(here in your case the image has to fade and a new image has to be formed) . For providing fading effect we have a popular parameter. ctx.globalAlpha(). In each animation step change the value of it. Lemme provide a sample code so that you can understand it properly.
canvas = document.getElementById("canvas");
ctx = canvas.getContext("2d");
var ms = new Image();
ms.src = "images/asdf.jpg"
ctx.drawImage(ms,0,0); // Will draw the initial image (assume)
ctx1 = canvas.getContext("2d");
Now let me define the onclick function.
onclick="caller()";
The caller function should be made to call the animate function
function caller()
{
i=1;
inter=setInterval(animate(),500); // Calls the animate function every 500 msec
}
And the animate function would look as shown below
function animate()
{
i=i-0.1;
ctx1.globalAlpha=i;
if(i=0)
{
clearInterval(inter);
ctx1.drawImage(ms2,0,0); // This will draw the next image defined in ms2.
}
}
So the image will be faded out and a new image appears in 5 secs. Use an array if you have several images and definitely javascipts would help you to implement them all the way you want. Let me know if you need any more clarifications to a SPECIFIC problem that you are facing.