How can I get coordinates of object collision in AS3? - actionscript-3

I'm trying to write a simple flash game like Space Invaders. When the ship shoots I check if bullet hits the enemy with simple if like below:
if (bullet.hitTestObject(enemy)) {
var explosion = new Explosion(enemy.x, enemy.y);
stage.addChild(explosion);
explosions.push(explosion);
//Rest of logic like removing bullet and enemy from stage
}
What I expected to see was an Explosion instance appearing somewhere around the coords where bullet hit the enemy and that it would stay in place. Instead explosion seems to be appearing completely elsewhere and is moving in the same direction the enemy was (opposite direction to bullet). It seems that my assumption about successfully getting coordinates in a way presented above isn't right. Is there any other way to get it at least approximately? It doesn't have to be pixel-perfect, but I don't want explosion to appear on the other side of the stage.
Thanks for any suggestions.

It's not about getting the coordinates but having in mind where your children are added.
If the container is moved around, and you add the explosion to other container, the coordinates will mess up - each object has an internal coordinate system starting from 0,0.
Best advise would be to manually understand where's the difference and where are your children added. Common way to fix this is to add all your children at 0,0. This will give you full control and nevertheless an idea of how Flash works.
If you are unable to do so, you can always use globalToLocal and localToGlobal methods that will help you convert those coordinates to a global (Stage) ones, and vise versa.

Related

AS3 collision detection in an object itself

I´m programing a space ship side scroll in as3. The bottom of the stage are mountains and here comes the problem, when I try to detect the ship collision against the mountains..
Because the poor collision detection and the need of avoid large loops my idea is create an object that works as a collider itself detecting a collision and avoiding parse all the stage or more selective metod.
I place "by hand" in the flash stage several instances of circles with a class for manage them where I place the If(this.collider.hits(ship)....
I spent looong time but I can find the way to make it work some of the mistakes i get are like this
Error 1061: Call to a possibly undefined method hitTestObject through a reference with static type Class.
some Idea? Thanks in advance
when you hit test with points it is important that the point being tested is relative to the object being tested against, eg
if(mountain.hitTestPoint(this.x + circle1.x, this.y + circle1.y))
will return true if the circles are inside the object calling the function because their position relative to the mountain is now relative to it rather then relative to the ships xy position within the clip... hope that makes sense.
btw I have done this myself in the past but I would have to remind you that you can only hit test with the points so there is no need to have circles, use blank sprites instead and set the visible flag in the properties panel to false, no drawing will make it slightly faster... not that you will notice, also sprites/graphics use less memory then movie clips.
also I would recommend hard coding some points in the clips rather then actually adding the clips in the sprite/clip itself, this will make it easier to work with them and scale later on (believe me this will annoy the hair from your head to do something later and slow the game to scale on the fly)
try something like this... you can determine the points values by adding a clip to the movie clip and getting its position from the properties if you must.
private var hitPoints:Vector.<Point> = new Vector.<Point>
hitPoints.push(new Point(10, 40));
hitPoints.push(new Point(30, 40));
//...do this for all your points
//loop through all your points and check if the hit relative to the ships position.
for(var i:int = 0; i < hitPoints.length; i++)
{
if (scene.hitTestPoint(ship.x + hitPoints[i].x, ship.y + hitPoints[i].y))
{
//do your hit stuff here
break;//don't forget to break
}
}
in this code you will need to make sure the scene object is a reference to your scenery at the bottom of the screen.
I hope this helps but if this is not enough help then you should post some of your code here so we can have a look and see where it can be improved.

Moving the "camera" of an HTML Canvas element

I'm trying to find a clean way to "move the camera" of a canvas element.
This for my prototype game (side scroller). I'd love to think there's a better solution than moving the whole set of nodes to simulate a "camera" moving around.
Am almost certain to have read a simple how-to (using offsets?) but the fact I don't find anything like that starts to raise doubts... have I imagined reading that!?
Thanks to help me clarify...
J
Presumably you redraw your whole game scene 30 times a second (more or less)
You need to redraw your whole game scene but first translate the Canvas context by some offset.
context.translate(x,y) is precisely what you want. You'll want to read up on the use of that as well as the save() and restore() methods.
When you translate the context, everything drawn afterwards is shifted by that amount.
So you constantly draw something (maybe an enemy) at 50,50 using drawImage(badguy,50,50). Then the player moves, which changes the x of translate to -1 (because the player is moving to the right) instead of 0. You still draw the enemy sprite with the command drawImage(badguy,50,50), but when you draw it the enemy shows up as if it were at 49,50 because of the context.translate(-1,0) command shifting everything before its drawn.
Of course when you get into performance you'll want to be making sure that you are only ever drawing things that can actually be seen on the screen! If your are far down the level with context.translate(-2000,0), you dont want to be drawing objects at 50,50 anymore, only ones that intersect the viewable area.

Mouse interaction with nested movieclips in Away3D

I am building a globe with the countries. I have all of the spheres built and everything works fine. The problem is to get the globe to look right I had to put all of the movieclips into one big moveclip then broke down from there. The problem is I cannot get Away3D to recognize the secondary movieclips. If I apply the listener to the whole sphere it works fine (but that isn't functional). Is there a way to use nested movieclips in away3d?
//what works
var materialMovie:MovieClip = new causticsMovie() as MovieClip;
var causticsMaterial:MovieMaterial = new MovieMaterial( materialMovie);
var sphere:Sphere = new Sphere({material:causticsMaterial, radius:300,segmentsH:18,segmentsW:26, interactive:true});
causticsMaterial.interactive = true;
view.scene.addChild(sphere);
sphere.addEventListener(MouseEvent3D.MOUSE_DOWN, NA);
//what doesn't
world_map.northAfrica_mc.addEventListener(MouseEvent3D.MOUSE_DOWN, NA);
Is there a solution to this problem?
If I understand how 3d engines in flash generally work, this won't be possible. They create a texture from the original movieclip(s) which they then transform. So there are no movieclips left to click on.
There is a couple of ways around this I think. You could transform the click location into polar coordinates (I'm not sure about the maths there, but google should be helpful), and figure out which location was clicked that way.
Or, you could (probably) have a second, invisible sphere (off stage or not added as a child, not sure which will work), where you create a different texture where each country has a different color. You would rotate this to the same angles as the visible sphere. Then, on click, render that to a BitmapData and check the pixel value of the point you clicked (translated so the point on the visible sphere and the invisible sphere are the same). I think this way is the easier of the two, and will have better results.

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.

Is it possible to move the stage in actionscript 3.0?

Hi to keep it short and simple let's say I have a stage with 400x400 size in pixels, but I've drawn a map of 1000x1000 size in pixels. I want my player to be able to "walk" about the stage, but it appears stage.x and stage.y are read-only? Is there any method or way to have the stage "scroll" about, without having to move each object on the map?
Don't move the stage, move the 1000x1000 object,then it'll look like the whole thing is moving.
You should see the stage like a window. You can see everything behind it depending on the size of the window. You cannot change the size of the stage, or move it.
Just like a window you can measure the size of the stage. You can use this to navigate for example movieclips across the stage with actionscript.
Why don't you put the map and the other objects in a seperate layer, and move the map around. Other objects (for example a big red dot to tell the user its' location on the map) are on a fixed position on the map. Just move the map following a sort of path according the red dot.
Not entirely sure what you want to do, but it isn't possible to move the stage.
You can put all the movieclips (the player and the map, if you want) in one movieclip, put only that movieclip on the stage and move that.
But if you only want the map to scroll, just move the map around.
The other answers are correct, but there's an alternative to moving the map:
ScrollRect
Attach a rectangle to a your map's scrollRect property. Moving that rectangle will have the same apparent effect as moving the stage around.
There are minor pros and cons to using scrollRect vs. moving the world, but try them both and see which works better for you.