I need to do bounding box collision detection manually. My current implementation sees bullets passing right by enemies. Not only that, sometimes it seems they get hit later..
For the objects that I want to hittest, I have getters like this:
public function get left():Number{
return x - width / 2;
}
(The 'crosshairs' are at the center of the movieclips)
When I check for collisions, I use this:
if(this.leftX >= Main.player.leftX && this.rightX <= Main.player.rightX && this.topX >= Main.player.topX && this.downX <= Main.player.downX){
The bullet has a x of 4, a y of 13, and the player is a 20 by 20 square.
Are ther better ways to do this or should I fudge the numbers a bit?
You are checking "this square is inside player's square", you want to check if any of corners are inside the other one. Distance between centers will be easier to write and may work as well for such a small objects.
Related
If I have two instances called block1 and block2. And they move off the stage. It scrolls down the y position and it respawns back on top. But I don't want the x/y position colliding with the other blocks? I want it to respawn back to position, but I want it randomized but at the same time I don't want it touching each other?
Heres my code:
if (block1.y > stage.stageHeight)
{
block1.y = -550;
block1.x = (Math.floor(Math.random() * (maxNum - minNum + 5)) + minNum);
}
I'm pretty sure I'm calculating the respawn coordinates the wrong way, but I'm not sure how to put it in a random x and y position without colliding with other blocks.
A very simple method can be just to spawn your box, do a collision check, then if collision, remove and respawn and recheck until you find an empty spot where it fits
This is obviously quite inefficient, but is pretty simple to implement quickly if you have some sort of collision detection already working. Keep in mind if there is no spot that it can fit in, then it'll loop forever so you may want to set a max try count or something of that sort.
How fast/well it'll actually work will depend on if the spawn area is pretty sparse or pretty dense, which will increase/decrease the percentage that it'll find a good empty spot the first few times.
There is some room for improvement, going down this path though, such as if your collision detection system gives a minimum translation vector, you could just move the new shape over and use that position to spawn.
Other simple methods could involve keeping track of known occupied positions and adjusting your random range to avoid those values.
I've been trying to find out how to block the player from moving the correct way. However, the way I've been doing now, stops the player from moving at all.
I want the player to stop moving horizontally if it touches the side of the block's collisionArea, and if it touches the top or bottom of the block's collisionArea, I want it to stop moving vertically only. So that way you can still move up and down when you touch the side, and side to side when you touch top or botttom. Thanks.
if (player.collisionArea.hitTestObject(block.collisionArea))
{
player.y -= vy;
player.x -= vx;
}
Your basic approach is to move your object, test if the current position hits your obstacle, then move it back if it does. This could be adapted to separate out the x and y axis quite easily (reduced code for clarity):
player.x += vx;
if(player.hitTestObject(block)){
player.x -= vx;
}
player.y += vy;
if(player.hitTestObject(block)){
player.y -= vy;
}
However, there are potential problems with this. First of all, DisplayObject/x and y round their values to "twips", so your addition and subtraction of vx and vy will not necessarily result in the object landing back in the original position exactly. This can produce problems with objects getting stuck in walls and such. Sound strange? Try this:
var s:Sprite = new Sprite();
s.x = 1.1925;
trace(s.x); // 1.15
So, to avoid this, you can store the position separately instead of relying on the DisplayObject x and y property.
var oldPosition:Point = new Point(player.x, player.y);
player.x += vx;
if(player.hitTestObject(block)){
player.x = oldPosition.x;
}
player.y += vy;
if(player.hitTestObject(block)){
player.y = oldPosition.y;
}
Second, I thought I would just mention that while hitTestObject() is a convenient API to check the intersection of two display object bounding rectangles, in my experience when you mix it with movement and collision response it starts to break down, because it relies on the state of the display, which is subject to oddities like the twips rounding, and inflexible with timing (you can't, for example, project all your movements, then check collisions, since you need to move your display object to get a valid result from hitTestObject()). The better way IMO is to make collision detection purely math based, for example circle intersection/distance checks. All that hitTestObject() is really doing is Rectangle/intersects() based on display objects bounds anyway. Pure math based collision detection is more work to setup, but more flexible and in my experience more predictable. Just a thought for the future, perhaps!
First of all, this question is very genuine - Just for the next time, make sure you clarify the background of your question (i.e I`m making a game with an actionscript 2d graphics, blah blah blah).
Anyhow, I'll copy you a part of a code i written back in the day when i was into developing javascript games. Since i dont know how your objects are arranged, i`ll modify it in a way that'll just introduce the general algorithm.
// player: a class that holds an array of moves, and other relevant information. Varys on your program.
var optimizePosition = function (player) {
//after each time the player attempts to move, i check if he touches of the blocks. if he does, i move him back.
foreach(Block block in blocks)// replace this with an iterator for all the blocks
{
if (player.x-block.x < 32 || player.y-block.y < 32 ) // if player is touching a block:
undoLastMove(getLastMove(player),player);
}
// a little extra: always good to check if he's going out of the screen in the same function:
if(player.x > canvas.width - 64 || player.y > canvas.height - 64)
undoLastMove(getLastMove(player),player);
}
and each time the player moves, i call the function:
optimizePosition(player);
The content of undoLastMove(player) will contain the code you written above.
I am making an achtung die kurve-like game in AS3.0. So far I've done the movements of the 4 different players, and it works alright.
I am now to make collision detection, in order to test if a 'worm'-so to speak, is colliding with eachother or its own tail.
As I understand it, if I use hitTestObject(); it will use the registration area of the whole object, which would be a huge problem, seeing since this registration makes a 4-sided registration that contains all of the object. So if this is used, it will 'collide' just by entering this rectangle instead of hitting the actual worm. Is this correctly understood?
I've been looking through different methods of collision detection, and can't seem to find an optimal one for my project.
My thought were to check if the 'worms' are drawing their new sprites on a white background. if they aren't, then it must have hit something.
You can see how I used my code here: code in .as format linked to an .fla file
Sorry for my ill-formulated question, hope it makes somewhat sense.
Any help is greatly appreciated!!
Best regards - Jesper
Try this function if you want a Pixel Perfect Collision Detection with efficient CPU usage:
trace("Collided: " + (areaOfCollision(mc1, mc2) != null));
trace("Where: " + areaOfCollision(mc1, mc2));
function areaOfCollision(object1:DisplayObject, object2:DisplayObject, tolerance:int = 255):Rectangle {
if (object1.hitTestObject(object2)) {
var limits1:Rectangle = object1.getBounds(object1.parent);
var limits2:Rectangle = object2.getBounds(object2.parent);
var limits:Rectangle = limits1.intersection(limits2);
limits.x = Math.floor(limits.x);
limits.y = Math.floor(limits.y);
limits.width = Math.ceil(limits.width);
limits.height = Math.ceil(limits.height);
if (limits.width < 1 || limits.height < 1) return null;
var image:BitmapData = new BitmapData(limits.width, limits.height, false);
var matrix:Matrix = object1.transform.concatenatedMatrix;
matrix.translate(-limits.left, -limits.top);
image.draw(object1, matrix, new ColorTransform(1, 1, 1, 1, 255, -255, -255, tolerance));
matrix = object2.transform.concatenatedMatrix;
matrix.translate(-limits.left, -limits.top);
image.draw(object2, matrix, new ColorTransform(1, 1, 1, 1, 255, 255, 255, tolerance), BlendMode.DIFFERENCE);
var intersection:Rectangle = image.getColorBoundsRect(0xFFFFFFFF, 0xFF00FFFF);
if (intersection.width == 0) return null;
intersection.offset(limits.left, limits.top);
return intersection;
}
return null;
}
After a successful preliminary hitTestObject(), this function backgroundly takes a snapshot from the shapes of both objects painted with different colors each, then overlays them intersecting the colors on a new one, returning the Rectangle of the resulting shape. So cool.
To learn more about Pixel Perfect Collision Detection you can google Collision Detection followed by one of these names: "The ActionScript Man", "Troy Gilbert", "Boulevart (wim)", "Grant Skinner (gSkinner)" or "Senocular". Those guys are awesome AS3 references by the way.
The problem you discribe is a very common problem for collission detection because the object has a set width and height and therefor defines a rectangle as the object.
There is a solution however to make a colission detection system on pixel level I have found this on the official site and this made me able to make collission detection for bitmaps on pixel level.
http://help.adobe.com/en_US/ActionScript/3.0_ProgrammingAS3/WS5b3ccc516d4fbf351e63e3d118a9b90204-7d55.html
hope it helps you out in the same way.
Looking at the screenshots of that game, I think the best model would be to describe each worm as a chain of circles. Then divide the world/level in a grid with cells somewhat larger than the circle radii.
The collision check would then be:
clear grid
place each circle into the 1 or more grid cells it falls in
iterate over all cells, for each cell:
for each pair of circles (partially) in this cell, check if they intersect. If they do; collision.
Note that this may result in more than 1 collision occurrence between circle A and B, so you'd also need to check that to avoid duplicates.
Step 1 and 2 can be optimized by not clearing the grid, and instead of step 2, updating each circle's cell after it moves. If you size your cells like 5x the size of a circle, a circle can stay in the same cell for a few frames, avoiding excessive add/remove operations.
I'm doing something similar in a project of mine right now, except with space ships! My grid cells are currently 256x256 (too big for your project I think) and my units have radii of about 20.
I need to do an endless horizontal scroll of elements within a parent MovieClip.
No matter what ever method I try, an element of 'drift' occurs and eventually the elements start to overlap.
I've tried using relative recursive tweening for each element according
but this method seems prone to quite a bit of error after repeated starts and stops.
//CODE START
function doScroll():void {
TweenLite.to(this, .25, {x:"20", ease:Linear.easeNone,onUpdate:checkPos,onComplete:doScroll});
}
//CODE END
I've reverted to doing absolute tweens to a predefined position using a contant speed. This seems to be more accurate but still some 'drift' occurs.
//CODE START
//_dest is predefined
var speed:Number = 500;
var dist:Number = this.x - _dest;
var distAbs:Number = dist < 0 ? -dist : dist;
//kludge to get constant velocity by recalculating time every frame
_time = distAbs / speed;
TweenLite.to(this, _time, {x:_dest, ease:Linear.easeNone,onComplete:reset});
//CODE END
Thought this should be very simple.
Can anyone point me to any possible tutorials or make any suggestions?
Any help appreciated.
Solution/Discussion at http://forums.greensock.com/viewtopic.php?f=1&t=6800
(warning: this is gonna require a rather lengthy explanation...)
It's a logic problem in your code. In your onUpdate, you were running conditional logic such that if the x position is beyond 980, it kills the tween and moves x back to -980 and starts things over. You're doing that for each individual item, each of which begins at a different position. That initial position affects when it crosses that threshold, thus when they reposition, the offsets are different.
For example, let's say item1 starts at an x position of 0 and item2 starts at 490 and both start moving at 400 pixels per second and your frame rate is 60, thus they'll move 6.66666 pixels per frame. Item1 will take 147 frames to hit 980. However, item2 will take 74 frames (actually 73.5, but there's no such thing as a half-frame) to cross the 980 threshold, but when it does so it will be at an x position of 983.333333. At that point it jumps back to -980 due to your conditional logic, but notice that it traveled an EXTRA 3.333333 pixels. You intended Item1 and item2 to travel at the exact same velocities and they do during the tween, but your onUpdate logic is misaligning them on the reposition such that in the end, some are traveling more than others which affects their overall velocity.
Another issue has to do with the fact that Flash rounds x/y coordinates of DisplayObjects to the nearest 0.05. So when you do your manual reposition (wrap), small rounding errors creep in. For example, let's say TweenLite sets the exact x value to 980.799. Flash will actually round that to 980.75. Then when you reposition it like this.x -= 980 and then tween it, the value would have just lost almost 0.05 pixels on that round. Do that many times and it can add up to a half-pixel or whole pixel (or more). All your items are crossing the threshold at slightly different spots, thus the rounding errors aren't the same, thus you start seeing slight variances in the spacing. Again, this is NOT an issue with the tweening engine. You'll see that the engine itself sets the values correctly, but Flash rounds them internally when applied to DisplayObjects.
A solution was posted at http://forums.greensock.com/viewtopic.php?f=1&t=6800 that includes an FLA and support files.
As others have suggested, I'd recommend having a single chunk of code that manages ALL the items that you're aligning/scrolling. It would lay things out from a single reference point so that everything lines up perfectly every time. You could tween a getter/setter that applies the logic. I use that technique all the time and it works great. You can see a smaller-scale example in the code I attached in the above URL (the scrollX getter/setter in ItemBase.as)
If you will be tweening all background elements at the same rate indefinitely on a single dimension - why not use a Timer and bypass tweening libraries entirely?
I am developing a game with Flixel as a base, and part of what I need is a way to check for collisions along a line (a line from point A to point B, specifically). Best way to explain this is I have a laser beam shooting from one ship to another object (or to a point in space if nothing is overlapping the line). I want the line to reach only until it hits an object. How can I determine mathematically / programatically where along a line the line is running into an object?
I could try measuring the length of the line and checking points for collision until one does, but that seems like way too much overhead to do every frame when I'm sure there is a mathematical way to determine it.
Edit: Before checking an object for collision with the line itself, I would first eliminate any objects not within the line's bounding box - defined by the x of the left-most point, the y of the top-most point, the x of the right-most point, and the y of the bottom-most point. This will limit line-collision checks to a few objects.
Edit again: My question seems to still not be fully clear, sorry. Some of the solutions would probably work, but I'm looking for a simple, preferably mathematical solution. And when I say "rectangle" I mean one whose sides are locked to the x and y axis, not a rotatable rectangle. So a line is not a rectangle of width 0 unless it's at 90 or -90 degrees (assuming 0 degrees points to the right of the screen).
Here's a visual representation of what I'm trying to find:
So, you have a line segment (A-B) and I gather that line segment is moving, and you want to know at what point the line segment will collide with another line segment (your ship, whatever).
So mathematically what you want is to check when two lines intersect (two lines will always intersect unless parallel) and then check if the point where they intersect is on your screen.
First you need to convert the line segments to line equations, something like this:
typedef struct {
GLfloat A;
GLfloat B;
GLfloat C;
} Line;
static inline Line LineMakeFromCoords(GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2) {
return (Line) {y2-y1, x1-x2, (y2-y1)*x1+(x1-x2)*y1};
}
static inline Line LineMakeFromSegment(Segment segment) {
return LineMakeFromCoords(segment.P1.x,segment.P1.y,segment.P2.x,segment.P2.y);
}
Then check if they intersect
static inline Point2D IntersectLines(Line line1, Line line2) {
GLfloat det = line1.A*line2.B - line2.A*line1.B;
if(det == 0){
//Lines are parallel
return (Point2D) {0.0, 0.0}; // FIXME should return nil
}else{
return (Point2D) {(line2.B*line1.C - line1.B*line2.C)/det, (line1.A*line2.C - line2.A*line1.C)/det};
}
}
Point2D will give you the intersect point, of course you have to test you line segment against all the ship's line segments, which can be a bit time consuming, that's were collision boxes, etc enter the picture.
The math is all in wikipedia, check there if you need more info.
Edit:
Add-on to follow up comment:
Same as before test your segment for collision against all four segments of the rectangle, you will get one of 3 cases:
No collision/collision point not on screen(remember the collision tests are against lines, not line segments, and lines will always intersect unless parallel), taunt Player for missing :-)
One collision, draw/do whatever you want the segment you're asking will be A-C (C collision point)
Two collisions, check the size of each resulting segment (A-C1) and (A-C2) using something like the code below and keep the one with the shortest size.
static inline float SegmentSizeFromPoints(Vertice3D P1, Vertice3D P2) {
return sqrtf(powf((P1.x - P2.x),2.0) + pow((P1.y - P2.y),2.0));
}
The tricky bit when dealing with collisions, is figuring out ways of minimizing the number of tests you have to make.
Find the formula for the line y = ((y2 - y1)/(x2 - x1)) * (x - x1) + y1
Find the bounding boxes for your sprites
For each sprite's bounding box:
For each corner of the current bounding box:
Enter the x value of the corner's coordinate into the line formula (from 1) and subtract the y value of the coordinate from the result
Record the sign from the calculation in 5
If all 4 signs are equal, then no collision has/will occur. If any sign is different, then a collision is possible, do further checks.
I'm not mathematically gifted but I think you could do something like this:
Measure the distance from the centre of the block and the laser beam.
Measure the distance between the centre of the block and the edge of the block at a given angle (there would be a formula for this I just don't know what it is).
Subtract the result of point 1 from the result of point 2.
Good thing about this is that if point 1 is larger than point 2 you know there hasn't been a collision yet.
Alternatively use box2d, and just use b2ContactPoint
You should look at the Separating Axis Theorem. This is generally used for polygons, but I think that you can make it work for a line and a polygon.
I found a link that explains it in a concise manner, here.