as3 how to ignore MOUSE_DOWN outside mask - actionscript-3

I am working on a jigsaw-like game in as3 where irregularly shaped layers imported from photoshop are used to mask parts of their original background.
By setting cacheAsBitmap=true on the mask and its contents the result is a nice irregular shape with its transparent bounding portions left out.
However the invisible bounding areas are still detected at MOUSE_DOWN. I would prefer the mouse not be detected anywhere but on the visible masked part. At the moment I cannot detect the mouse on any other clips on the stage that might appear behind the overlapping transparent areas.
I have seen a solution here involving bitmap pixel detection which I have not found a way to apply as a solution. The contents of my masked areas are either shapes or MovieClips.
I hope someone can help me find a solution

The simplest and the most stable approach to prevent the mouse events on the transparent area of bitmap graphics is to create a separate vector shape as the target for mouse and set the mouseEnabled flag to false to the bitmap or set hitArea property to this shape.
You can create such shape manually in the Flash IDE for the tests and even for the production. Sometimes it's more suitable to write the bitmap tracert script that creates contour shape in runtime by checking the pixel transparency.

Related

How do I create collision detection with an object and part of a background?

I am just starting to attempt to make my own game using java and libgdx, and the extent of my success so far has been showing the background image on screen, and spawning a little square the user controls with WASD. The background is just a solid color, with a vertical rectangle that is red inside and has black edges. I want to make it so the tiny square (player) can move anywhere within the red rectangle, but not be able to cross over the black edges (out of the rectangle). How would I go about doing this?
Since I am a complete beginner to this stuff I must ask these related questions...
Should the player be just a texture? Should the background be a texture? or a sprite?
I'm not sure the difference between the two yet.
I recommand you to read tutorials about libGDX and Box2D like this one : http://www.gamefromscratch.com/post/2014/08/27/LibGDX-Tutorial-13-Physics-with-Box2D-Part-1-A-Basic-Physics-Simulations.aspx
to answer you're questions, in short :
a texture is an image in memory
a sprite is a part of a texture (or the whole texture) transformed (translation, scale, rotation) to be drawn on screen.
so basically, in the view model, your player is represented by a sprite, your background is a sprite as well.
Player 1 and 2 are 2 different sprites but may reffer to the same texture (bitmap).
with box2D, in the physics model, your player will be represented as a dynamic body and your background as a static body.

How to use bitmapdata.draw to get a specific area of the stage?

I'm using a bitmapdata.draw(stage) to draw the stage as a bitmap but I would like to draw an area which is 32 pixels left of the stage instead, so that the area I am drawing as a bitmap is no longer in the viewing window, but the bitmap being draw is (so the stage is a bitmap). How do I draw a specific area with multiple bitmaps and display objects?
This is a very nice article that can help you: http://www.tomauger.com/2013/flash-actionscript/actionscript-3-bitmapdata-draw-offset-and-positioning
You should basically use a Matrix and work your way around with it :)
My honest advise would be not to use such odd techniques as if you want to draw something it should be within the stage..

how to get a tolerance for mouseOver behaviour in as3?

i'm making an application that draws curves with as3 and i ant the curves to highlight when the mouse is over.
I managed to do it with mouseOver, but the interaction is not natural because you have to be exactly on the curve (1px wide) to highlight it. So i was wondering if it was possible to have some sort of 'tolerance' on the mouseOver behaviour.
I know i could use a enterFrame event and check there the distance between the curve and the cursor, but it seems to me it will be a lot of calculations for such a simple task.
thanks.
ps: my curves are not real curves (like bezier), but a succession of lineTo commands.
There is no tolerance in mouse_over, so the quickest solution that I can imagine is to draw thicker line with alpha set to 0, and then addEventListener to that thicker invisible line.

Canvas: Mouse Events

I know it is not possible to add eventhandlers to specific circles or rectangles in canvas. But there are some nice frameworks like EaselJS, KineticJS, Paper.js, Fabric.js that support the eventhandling on specific elements.
Can someone explain me how do they work?
I think there are only two solutions.
1. You create for each element a new canvas region and put them on each other. In this way you can give each region an event handler.
2. You have only one canvas region and one event handler. In this way you have to do complex mathematical calculations to find out if a specific element was clicked. If you have only circles or rectangles, this solution might be easy. But if you have path with lots of curves, this solution is quite difficult.
I don't want to use the libraries. So it would be nice, if someone can help me.
Here's a BRIEF summary of how canvas drawing libraries work
An unaltered canvas is just a big bitmap. Once you draw shapes on the canvas, they are unaccessible, forgotten pixels.
Canvas drawing libraries store all your shapes into “retained” objects. Each shape object has sufficient information about itself to allow the drawing library to redraw it whenever necessary.
The canvas drawing libraries are the "controllers" for objects. The libraries have the algorithms necessary to track, manipulate and redraw all shape objects as necessary.
The following information is retained about every shape object:
Basic identification
ID,
Shape name
Parent or Container
Inherent properties of the shape:
Rectangular shapes( rect, image, text) know width and height.
Circular shapes (circles, elipses, regular polygons, stars) know radius and sidecount.
Lines know length.
Curved shapes (arcs, beziers, paths) know anchor points and control points.
Text also knows…well, the text!
Images also know their pixel data (usually stored in javascript Image objects)
Transformational information:
Starting X/Y coordinate
Translations—accumulated movements off the starting coordinate.
Rotations—accumulated rotations of this shape (usually in radians).
Scalings—accumulated resizings
Other transforms (less common) are skews and warps
Layering information—the current z-index
Styling information:
StrokeColor,
StrokeWidth,
FillColor,
Opacity,
isVisible,
lineCaps,
cornerRadius
Tracking abilities:
Bounding box—the smallest rectangle that completely contains this shape
This is used for “hit testing” to see if the mouse is inside this object (for selecting and dragging)
If you don't want to use a library, you may find my answer in this thread helpful. As markE says once the canvas is written to there is no way of tracking that data (unless you care to loop through each individual pixel and test its colour; though that is only really useful for pixel level collision detection).

Clear Canvas Rect (but keep background)

I'm trying to animate a circle and just moving it horizontally which works fine. However while the circle is moving, I have to do a clearRect over that circle so that it redraws it self in the horizontal direction. When I do a clearRect it also makes the background have white box around so effectively its going to be one white horizontal line in the direction the circle is moving.
Is there a way to clear the circle without clearRect?
If I have to keep redrawing the background after clearRect the canvas will flicker when theres say 10 circles moving in that area.
Any other approaches to solving this?
function drawcircle() {
clear();
context.beginPath();
context.arc(X, Y, R, 0, 2*Math.PI, false);
context.moveTo(X,Y);
context.lineWidth = 0.3;
context.strokeStyle = "#999999";
context.stroke();
if (X > 200)
{
clearTimeout(t); //stop
}
else
{
//move in x dir
X += dX;
t = setTimeout(drawcircle, 50);
}
}
function clear() {
context.clearRect(X-R, Y-R, 2*R, 2*R);
}
Basics: HTML5 Canvas as a Non-Retained Drawing Mode Graphics API
First, let us discuss the manner in which the HTML5 Canvas works. Like a real-world canvas with fast-drying oil paints, when you stroke() or fill() or drawImage() onto your canvas the paint becomes part of the canvas. Although you drew a 'circle' and see it as such, the pixels of the circle completely replaced the background (or in the case of anti-aliasing at the edges of the circle, blended with and forever changed them). What would Monet say if you asked him to 'move' one of the people in a painting a little bit to the right? You can't move the circle, you can't erase the circle, you can't detect a mouseover of the circle…because there is no circle, there is just a single 2D array of pixels.
Some Options
If your background is fully static, set it as a background image to your canvas element via CSS. This will be displayed and overlaid with content you draw, but will not be cleared when you clear your canvas.
If you cannot do the above, then you might as well just clear the entire canvas and re-paint it every frame. In my tests, the work needed to clear and redraw just a portion of the canvas is not worth the effort unless redrawing the canvas is very expensive.
For example, see this test: http://phrogz.net/tmp/image_move_sprites_canvas.html
In Safari v5.0.4 I see 59.4fps if I clear and re-draw the entire canvas once per frame, and 56.8fps if I use 20 clearRect() calls and 20 drawImage() calls to re-draw just the dirtied part of the background each frame. In this case it's slower to be clever and keep track of small dirty regions.
As another alternative, use a retained-drawing graphics system like SVG or HTML. With these, each element is maintained independently. You can change the position of the item and it will magically move; it is up to the browser to intelligently draw the update in the most efficient manner possible.
You can do this while retaining the power of custom canvas drawing by creating and layering multiple canvases in the same HTML page (using CSS absolute positioning and z-index). As seen in this performance test, moving 20 sprites via CSS is significantly faster than trying to do it all yourself on a single canvas.
Flickering?
You wrote:
If I have to keep redrawing the background after clearRect the canvas will flicker when theres say 10 circles moving in that area.
That has never been my experience. Can you provide a small example showing this 'flicker' problem you claim will occur (please specify OS, browser, and version that you experience this on)? Here are two comments by prominent browser developers noting that neither Firefox nor Safari should ever show any flickering.
This is actually very easy to accomplish by simply positioning more than one canvas on top of each other. You can draw your background on a canvas that is (wait for it...) in the background, and draw your circles on a second canvas that is in the foreground. (i.e. stacked in front of the background canvas)
Multiple canvases is actually one of the best ways to increase performance of anything animation where elements of the final image move independently and do not not necessarily move in every frame. This allows you avoid redrawing items that have not moved in every frame. However, one thing to keep in mind is that changing the relative depth (think z-index) of items drawn on different canvases now requires that the actual <canvas> elements be reordered in the dom. In practice, this is rarely an issue for 2D games and animations.
Contrary to what the accepted answer suggests; yes, you can restore previous draw states, and contrary to what the other answers imply; no, you don't need additional canvases to do so:
The CanvasRenderingContext2D API includes the functions getImageData() and putImageData(). After creating a background image, store the whole thing in a variable const background = context.getImageData(x, y, width, height) (a simple RGBA bitmap of type Uint8ClampedArray), then after wiping the canvas with clearRect() or whatever, restore the background image simply by passing that variable back in the opposite direction: context.putImageData(x, y, background).
There are two ways you can do it that may reduce the flickering, esp if you have many circles.
One is double buffering, and for a brief question on this you can look at:
Does HTML5/Canvas Support Double Buffering?
Basically, you draw on two canvases, and swap them in and out as needed.
This would be the preferable option, esp with many changes per frame, but, the other way I have done this is to just draw over the circle I want to erase, using the background color, then draw with the correct color the new circle.
The only problem is that there is a small chance that you may leave some evidence of the attempted erasing, as it seems that for some shapes it is hard to get it to draw exactly on top.
UPDATE:
Based on a comment you can look at this discussion about double buffering on the canvas:
HTML canvas double buffering frame-rate issues
The basic idea is to keep track of everything you have drawn, with the current position, then on a separate canvas, you redraw everything, then, flip them out, and then I would just redraw again, in the new positions, to ensure that the image looks exactly like it should. Swapping them in and out is a quick operation, the only problem would be if you put event handlers on the canvas, in this case, have them on the div or span surrounding the canvas, so this information doesn't get lost.