Get distance between a point and a movieclip - actionscript-3

I'm implementing a game and I'm stuck finding a way to calculate the x and y distance from a point and the nearest edge of movieclip.
for example:
I need to calculate the distance between from each black dot, to the nearest edge of the movieclip (The movieclip is not always a circle, it's a random shape).
I'll be more than happy to find a solution. Thanks!

I suspect (though would welcome being proved wrong) that without geometrical data about the shape, pixel based operations might be the only way.
If there is geometrical data, then can possibly just do a linear check of the distances between the point and every other point in the shape (the first naive solution that comes to mind -better ones out there).
Even if the shape is user generated (like drawing) one could sample points during drawing to get point data, and so forth. I'm bringing it up as an aside as I think any of those would be faster/more efficient then my solution below (which assumes pixels only).
With that said, this solution works by using BitmapData's hitTest() to check if two shapes collide. It's hardly efficient and admittedly, I just woke up not too long ago and decided it was a good morning exercise. I didn't test for any error cases (aka, like if the point is inside the shape).
It works by starting at the point end and drawing larger and larger circles around it, at each step converting that in to a bitmap and using BitmapData's hitTest(). When it deemed the bitmaps are intersecting/touching, then the radius of the circle around the point would be the closest distance to the shape.
Efficiency however can be improved by adjusting the 'probe/step size' (in a similar way that binary search is more efficient then linear search). However, I'll leave that up to the reader (example in the code comments).
import flash.display.Shape;
import flash.geom.Point;
import flash.display.BitmapData;
import flash.display.Bitmap;
// assumptions: the movie clip is currenly the only thing on the stage
// first generate the first BitmapData by taking all the pixels on the stage (which should just contain the movieclip)
var stagePixels:BitmapData = new BitmapData(this.stage.stageWidth, this.stage.stageHeight, true, 0xffffff);
stagePixels.draw(this);
function getDistance(inputPoint:Point):int {
var currentSearchDistance:int = 1;
var result:Boolean = false;
var zeroPoint:Point = new Point(0, 0); // just a common reference point for the hitTest() call
var pointShape:Shape;
while(result == false){
// create the shape and draw the circle around the point
pointShape = new Shape();
pointShape.graphics.lineStyle(1);
pointShape.graphics.drawCircle(inputPoint.x, inputPoint.y, currentSearchDistance);
// convert to BitmapData
var pointPixels:BitmapData = new BitmapData(this.stage.stageWidth, this.stage.stageHeight, true, 0xffffff);
pointPixels.draw(pointShape);
// left this here to show the steps and what it is doing
// will slow down stage rendering though since there are potentially a lot of bitmaps being added to the stage
this.addChild(new Bitmap(pointPixels));
result = stagePixels.hitTest(zeroPoint, 0xff, pointPixels, zeroPoint);
// for now, increase the search distance by 1 only, so can return true when it hits the shape for the first time.
// This can be optimized to take larger steps (and smaller) steps as well with multiple probes.
// ex:
// take a big step (+50)... didn't hit shape
// so take another big step (+50)... hit shape so we know the point is between the first 50 to 100
// take maybe half a step back (-25)... hit shape, so we know the point is between the first 50 and 75
// take another half step back (-12)... didn't hit shape so we know the point is between 62 abd 75...etc
// thus can slowly close in on the result instead of taking every small step (would have tkaen 62+ checks to get to this point vs 5)
// (and can also decide to quite early for a "good enough" result)
currentSearchDistance++;
}
return currentSearchDistance;
}
var dot:Point = new Point(100, 100); // input point here
trace(getDistance(dot));
edit: Decided to add a picture to show what it's doing.

Related

(AS3) MovieClip' s motion path as Shape on stage

I'm making a game for a school project. The concept is pretty simple, you need to fix the circuit wires(the path in the form of rectangular shapes) so that electricity can run through the circuit and light up the bulbs.
I'm trying to find a way on how you can make a movie clip travel the wires. I have seen a lot of tutorials where they state coordinates and angles for the motion path but I want to make it so that the movie clip will automatically follow the shape path present on the stage so even if the path changes(for different levels), the movie clip will still follow that path. As of the moment, all I can do is create a predefined guide path inside the movie clip which traces the path.
Follow-up question:
Is there also a way on how I can detect if the shape path is complete or not? The system will check whether or not the wires are connected to each other.
You should instead do a metadata calculation prior to moving something you intend, this way you first calculate whether your puzzle is solved, once it is, or once you have determined the point where your movable object should stop and display the error, you then make a path out of simple sections, then make your object move by them one by one until final point, then display the outcome. This is the general idea. A simple code of moving an object by sections looks like this:
var sections:Vector.<Point>; // we need x&y sequence. Fill this prior to launching the routine
var position:int=0; // where are we now
var velocity:int=8; // pixels per frame, adjust as needed
movable.addEventListener(Event.ENTER_FRAME,moveABit);
function moveABit(e:Event):void {
var nextPoint:Point=sections[position];
var do:DisplayObject=e.target as DisplayObject; // what we are moving
var here:Point=new Point(do.x,do.y);
if (Point.distance(here,nextPoint)<velocity) {
// this means we are too close to interpolate, just place
do.x=nextPoint.x;
do.y=nextPoint.y;
position++;
if (position>=sections.length) {
// movement finished
// TODO make your final animation
do.removeEventListener(Event.ENTER_FRAME,moveABit); // stop moving
}
} else {
// interpolate movement
var angle:Number=Math.atan2(nextPoint.y-here.y,nextPoint.x-here.x);
do.x+=Math.cos(angle)*velocity;
do.y+=Math.sin(angle)*velocity;
// if the object will move to wrong direction, fix this code!
}
}
If you want to see if your 'shape' is complete:
You can create a vector of boolean variables(every variable indicate a node of your wires- you set the variable to true when is connected), and you need a function to check if all the vars from vector are true (with loop), that means your shape is complete. Hope this idea helps!

Flash AS3: Keeping the mouse within certain boundaries

So this one is a tricky one (for me) vital to the development of my project due to the fact that we can't directly modify the position of mouseX and mouseY - they are read-only variables.
Basically, what I want to do is have a player able to move their mouse only within a certain triangular area when a specific instance is active. The latter bit I can manage just fine, however I am having trouble restricting mouse movement -- or apparent mouse movement.
Here's what I have done so far:
1. Assign a library moveclip to the mouseX and mouseY position in the Event.ENTER_FRAME event - although I acknowledge that this should be moved to Mouse.MOUSE_MOVE. (this does not matter yet)
2. Using Corey O'Neils Collision detection kit, do a hit test on the border instances of the area with the crosshair/cursor.
3. Offset the cursor appropriately, and then set a standard Boolean value to false so that the cursor will not keep bouncing back into the cursor over and over.
My problem is, I am not sure what the best way is to go about allowing mouse movement again. Can anyone give me some tips on the best way to do this, or if necessary, point me in another direction where restricting mouse movement is a little easier?
For what it's worth, this is to stop users from aiming in an unrealistic direction with a character in a top-down (ish) shooter.
For those unfamiliar with Corey O'Neil's Collision Detection Kit, I believe it is just a pre-built setup of bitmap (or maybe vector) collision testing - I could be wrong. I'm not sure on the details of how it works, just its basic implementation.
Here is my code regarding mouse movement thus far:
import flash.ui.Mouse;
import flash.events.event
import com.coreyoneil.collision.CollisionList;
Mouse.hide();
var c:crosshair = new crosshair();
addchild(c);
var myCollisionList:CollisionList;
myCollisionList = new CollisionList(c); //sets up detection for the object c
myCollisionList.addItem(mcB); // adds mcB to the list of objects to check c's hittest with
function aim(e:Event) {
var collisions:Array = myCollisionList.checkCollisions();
if (collisions.length>0)
{
hashit = true; // tells the program that the mouse has collided with a boundary
c.x += 1;
c.y += 1;
}
else
{
if (hashit == false)
{
c.x = mouseX;
c.y = mouseY;
}
}
}
Apologies for the code block, but I figure it is best to show all relevant code -- I'm not sure about the complexity of this issue due to the read-only nature of the mouse's X and Y position.
Also, I'm looking for a possible solution which will not be clunky - that is, as soon as the mouse is back in the area, mouse movement will be smooth as it is originally, and where the cursor will still be matching the mouse position (meaning, the cursor is ALWAYS relevant to the mouse and will not change position should the mouse leave the boundaries).
Could anyone please give me some pointers? Sorry for the long question. I gather there might be a bit to get my head around here, being relatively new to AS3 - but I still feel this is a problem I can get past, if one of you can show me the right direction and help me with both the logic and programming side of things slightly.
Here is a diagram of my stage to clarify the boundary areas etc.
Thanks very much for any help in advance, I really do appreciate it!
Cheers, Harry.
How about trying getObjectsUnderPoint which returns an array of objects under a certain point.
If your triangle object is within the array the cursor must be above it.
var pt:Point = new Point(c.x, c.y);
var objects:Array = stage.getObjectsUnderPoint(pt);
if (objects.indexOf(triangleObject) > -1) {
trace("still within bounds");
}
The workaround here could be to hide the system mouse cursor and add a bespoke cursor movieclip to the stage.
Using a MOUSE_MOVE event listener attached to the stage, set the bespoke cursor movieclip to match the stage.mouseX and stage.mouseY values and also test whether the movieclip is outside your bounds. If so, set it back within your bounds.

How can you get different objects working at different framerates working in html5 canvas?

Say I want a ball bouncing at 5 frames per second and only want to have a square bouncing at 2 frames per second, how is this possible?
return setInterval(draw,10) is used in the current simulation to move 1000 particles around, but I also want to draw a radial gradient on a second canvas which gets data from the particle simulation. I cant figure out how to draw the gradient a frame per second and the particles at another framerate
What i do is create a Timer constructor, and everytime I make something animate, i make a var animateThing = new Timer().
It may not be necessary to do this, but it can be a useful peice of code as you get deeper into canvas with more moving parts.
Update
So something sorta like this.
function Timer(fps, callback) {
return setTimout(callback, 1000 / fps);
}
var timer1 = new Timer(33, callback1);
var timer2 = new Timer(55, callback2);
Now that's probably not gonna work, but it's the idea.

Actionscript collisions: solving exceptions and strange cases

I have created a collision class to detect collisions using pixels. In my class I've also developed some functions for determining the collsion angle. Based on this I created some examples:
http://megaswf.com/serve/25437/
http://megaswf.com/serve/25436/
(Space to change gravity, right/left to give some speed to the ball.)
As you will probably notice, there are strange things that happen:
When the ball speed is very low
When the direction of the ball is
almost tangent to the obstacle.
collision http://img514.imageshack.us/img514/4059/colisao.png
The above image shows how I calculate the collision angle.
I call the red dots the keypoints. I search for a maximum number of keypoints (normally 4). If I find more then 2 keypoints, I choose the 2 farthest ones (as shown in one of the blue objects). Thats how I then find the normal angle to where in the surface the object collided. I don't know if this is an obsolete way of doing things.
based on that angle, I rotate the speed vector to do the bouncing.
The piece of code to do the maths is here:
static public function newSpeedVector(speedX: Number, speedY: Number, normalAngle: Number): Object{
var vector_angle: Number = Math.atan2(speedY, speedX) * (180/Math.PI);
var rotating_angle: Number = (2*(normalAngle - vector_angle) + 180) % 360;
var cos_ang: Number = Math.cos(rotating_angle/DEGREES_OF_1RAD);
var sin_ang: Number = Math.sin(rotating_angle/DEGREES_OF_1RAD);
var final_speedX: Number = speedX * cos_ang - speedY * sin_ang;
var final_speedY: Number = speedX * sin_ang + speedY * cos_ang;
return {x_speed: final_speedX, y_speed: final_speedY};
}
This is how the new speed vector is calculated...
My question is, has anyone faced this kind of problem or has some idea on how to avoid this from happening?
Without seeing your code, this is the best I can provide.
Collision physics should have some velocity threshold that is considered "stopped". That is, once the velocity gets small enough you should explicitly mark an object as stopped and exempt it from your collision code. This will help stabilize slow moving objects. Trial and error is required for a good threshold.
When a collision happens, it is important to at least attempt to correct any inter-penetration. This is most likely the reason why tangent collisions are behaving strangely. Attempt to move the colliding object away from what it hit in a reasonable manner.
Your method of determining the normal should work fine. Game physics is all about cheating (cheating in a way that still looks good). I take it rotation and friction isn't a part of what you're going for?
Try this. You have the contact normal. When you detect a collision, calculate the penetration depth and move your object along the normal so that is isn't penetrating anymore. You can use the two points you have already calculated to get one point of penetration, you'll need to calculate the other though. For circles it's easy (center point + radius in direction of normal). There are more complex ways of going about this but see if the simple method works well for you.
I have read and recommend this book: Game Physics Engine Development
I did something a little like that and got a similar problem.
What I did is that when the pixels from the bouncing object (a ball in your case) overlap with the pixels from the obstacle, you need to move the ball out of the obstacle so that they are not overlapping.
Say the ball is rolling on the obstacle, before your render the ball again you need to move it back by the amount of 'overlap'. If you know at what angle the ball hit the obstable just move it out along that angle.
You also need to add some damping otherwise the ball will never stop. Take a (very) small value, if the ball velocity is bellow that value, set the velocity to 0.
You can try one more thing, which I think is very effective.
You can make functions such as getNextX() and getNextY()(Which of course give their position coordinated after the next update) in your game objects and Check collision on objects based on their next position instead of their current position.
This way, the objects will never overlap, you'll know when they are about collide and apply your after collision physics gracefully!

Actionscript 3 pixel perfect collision. How to? (learning purposes)

I know that there are people out there creating classes for this (ie http://coreyoneil.com/portfolio/index.php?project=5). But I want to learn how to do it myself so I can create everything I need the way I need.
I've read about BitMap and BitMapData. I should be able to .draw the MovieClips onto a BitMap so I could then cycle the pixels looking for the collisions. However, It's weird and confusing dealing with the offsets.. And it seams like the MyBitMap.rect has always x = 0 and y = 0... and I can't seam to find the original position of the things...
I'm thinking of doing a hitTestObject first, then if this was positive, I would investigate the intersection betwen the movieclips rectangles for the pixel collisions.
But then there is also another problem (the rotation of movieclips)...
...I need some enlightment here on how to do it.
Please, any help would be appreciated..
If you're using BitmapData objects with transparency you can use BitmapData.hitTest(firstPoint:Point, firstAlphaThreshold:uint, secondObject:Object, secondBitmapDataPoint:Point = null, secondAlphaThreshold:uint = 1):Boolean.
You'll have to change from global coords to the local BitmapData coords which will require a bit of math if it is rotated. That's easily achieved (look up affine transform for more info on wiki):
var coordTransform:Matrix = new Matrix();
coordTransform.rotate(rotationRadians);
coordTransform.translate(x, y);
coordTransform.transformPoint(/* your point */);
A classic reference for pixel perfect collision detection in flash is this Grant Skinner's article. It's AS2, but the logic is the same for AS3 (there are ports available if you google a bit).
If I recall correctly, this particular implementation worked as long as both tested objects had the same parent, but that can be fixed.
About BitmapData x and y values, I understand it could be confusing; however, the way it works makes sense to me. A BitmapData is just what the name implies: pixel data. It's not a display object, and cannot be in the display list; so having x or y different than 0 doesn't really make sense, if you think about it. The easiest way to deal with this is probably storing the (x,y) offset of the source object (the display object you have drawn from) and translate it to the global coordinate space so you can compare any objects, no matter what's their position in the display list (using something like var globalPoint:Point = source.parent.localToGlobal(new Point(source.x,source.y)).
I've previously used Troy Gilbert's pixel perfect collision detection class (adapted from Andre Michelle, Grant Skinner and Boulevart) which works really well (handles rotation, different parents, etc.):
http://troygilbert.com/2007/06/pixel-perfect-collision-detection-in-actionscript3/
http://troygilbert.com/2009/08/pixel-perfect-collision-detection-revisited/
and from there he has also linked to this project (which I've not used, but looks really impressive):
http://www.coreyoneil.com/portfolio/index.php?project=5
I managed to do it after all, and I already wrote my class for collision detections,/collisions angle and other extras.
The most confusing process is maybe to align the bitmaps correctly for comparing. When whe draw() a movieclip into a a BitmapData, if we addChild() the corresponding Bitmap we can see that part of it is not visible. it appears to be drawn from the center to right and down only, leaving the top and left parts away from beeing drawn. The solution is giving a transform matrix in the second argument of the draw method that aligns the bitmap and makes it all be drawn.
this is an example of a function in my class to create a bitmap for comparing:
static public function createAlignedBitmap(mc: MovieClip, mc_rect: Rectangle): BitmapData{
var mc_offset: Matrix;
var mc_bmd: BitmapData;
mc_offset = mc.transform.matrix;
mc_offset.tx = mc.x - mc_rect.x;
mc_offset.ty = mc.y - mc_rect.y;
mc_bmd = new BitmapData(mc_rect.width, mc_rect.height, true, 0);
mc_bmd.draw(mc, mc_offset);
return mc_bmd;
}
in order to use it, if you are on the timeline, you do:
className.createAlignedBitmap(myMovieClip, myMovieClip.getBounds(this))
Notice the use of getBounds which return the rectangle in which the movie clip is embedded. This allows the calculation of the offset matrix.
This method is quite similar to the on shown here http://www.mikechambers.com/blog/2009/06/24/using-bitmapdata-hittest-for-collision-detection/
By the ways, if this is an interesting matter for you, check my other question which I'll post in a few moments.