Collision Detection - Any Language - java

I'm writing a simple game right now and I need to be able to detect collisions between many objects (checking if 10 objects collide with any 20 other objects but not between the two groups). I've written some simple code that works now but causes the game to slow down extremely after I detect the collision (in Java by the way):
//Check for collisions between tanks and bullets
ArrayList<Object> objectsToRemove = new ArrayList<Object>();
for (int i = 0; i < tanksOnScreen.size(); i += 1) {
//Get tank
Tank tank = tanksOnScreen.get(i);
for (int e = 0; e < bulletsOnScreen.size(); e += 1) {
//Get bullet
Bullet bullet = bulletsOnScreen.get(e);
//Check for collision
if (tank.collides(bullet.x, bullet.y, 10, 10)) {
System.out.println("Collide");
objectsToRemove.add(bullet);
objectsToRemove.add(tank);
break;
}
}
}
for (Object obj:objectsToRemove) {
if (obj.getClass().equals(Bullet.class)) {
bulletsOnScreen.remove(bulletsOnScreen.indexOf(obj));
} else if (obj.getClass().equals(Tank.class)) {
tanksOnScreen.remove(tanksOnScreen.indexOf(obj));
}
}
And the collides() method of the tank:
public boolean collides(float px, float py, float pwidth, float pheight) {
// If the distance between the two centers of the lines on x and y axis
// Is less than the distance of half the w and h added together, the objects
// Are colliding
float x1 = (px > x) ? x : px, x2 = (px > x) ? px : x, y1 = (py > y) ? y : py, y2 = (py > y) ? py : y;
float w1 = (x1 < x2) ? width : pwidth, w2 = (x1 < x2) ? pwidth : width, h1 = (y1 < y2) ? height : pheight, h2 = (y1 < y2) ? pheight : height;
if ((x2 + w2/2) - (x1 + w1/2) < (w1/2 + w2/2)&&(y2 + h2/2) - (y1 + h1/2) < (h1/2 + h2/2)) {
return true;
} else {
return false;
}
}
I assume the lag is because of the double for loops, to iterate over the objects. I'm not sure how to eradicate these for loops or how to get the bullets in a certain region of the screen and only check these bullet without using another for loop (segregation, I think). Can anyone point me in the right direction for collision detection with many objects? I don't mind what language the answer is in, even if it is pseudo code.
Thanks,
Ben
Edit 1
I'm right now using the Slick graphics API for java, which provides you with an update and render method to add rendering and game logic. I placed this collision detection in the update method (which is getting called every frame - about 60 times a second). The slowness occurs after the collision happens, and the objects are removed from the screen - which I find odd. Maybe a break command after deleting the objects in the for loop will eradicate it?
Edit 2
Thanks for all the answers guys, and the references are a great help for the future. I fixed the problem only by swapping the bullet and tank for loops, so it didn't continue to loop after the bullet was destroyed. I shouldn't have asked the question, as it was quite easy to fix in the end. Dave and Banthar were right in saying that the problem wasn't with the code, and that it should be instantaneous.

One good idea is to use octree. As the bullets will be moving I assume that you will need a kinetic version of it - there are a bunch of articles on kinetic data structures on the internet.
Also if you want to detect collisions between more complex convex polygons, I recommend you to use gjk algorithm which is very fast for such calculation. Note that this will speed up only the collision detection time for a pair of objects, the number of pairs will still remain the same.

Unless I'm missing something, or there's additional code you haven't shown, you're running in O(n^2), where n is 20. It should seem instantaneous to the user.
Try stepping through it in the debugger to see where it's slowing down.
Edit to elaborate: your expensive operation is not in the code you've posted. It's somewhere else, being called by the code you've posted.

Thanks for all the answers guys, and the references are a great help for the future. I fixed the problem only by swapping the bullet and tank for loops, so it didn't continue to loop after the bullet was destroyed. I shouldn't have asked the question, as it was quite easy to fix in the end. Dave and Banthar were right in saying that the problem wasn't with the code, and that it should be instantaneous.

Related

2D Collision, how to transfer forces?

I've got 3 main elements at work here.
Momentum, Mass, and Momentum rotation.
Mass is worked out by:
this.mMass = (this.getHeight() + this.getWidth()) / 2.0f;
I've created a system that automatically creates polygons around transparent pngs and detects collision perfectly (with high performance) but now I'm stuck on how to apply forces when they collide.
I'm using LibsGDX but theres nothing about how to detect collisions using polygons and how to deal with them anywhere (manually without using their world)
Only needs to be basic collision forces, when I look online everything seems to be way too complicated!
What I have so far..
//Collision detection - loop though all physical objects.
for(PhysicalObject physicalObject1 : AllPhysicalObjects)
{
for(PhysicalObject physicalObject2 : AllPhysicalObjects)
{
//Check that it's no trying to collide with it-self.
if(physicalObject1 != physicalObject2 && physicalObject1.mIsCurrentlyPhysical)
{
if(Intersector.overlapConvexPolygons(physicalObject2.mPolygon, physicalObject1.mPolygon))
{
//Functions.out("Class:" + eachPhysicalObject.getClass().toString());
//Now the fucking collision detection...
//Gonna be hard, but worth it when done right.
//Get the amount of momentum from the first physical object.
float physicalObject1Momentum = physicalObject1.mMomentum - physicalObject2.mMass;
float physicalObject2Momentum = physicalObject2.mMomentum - physicalObject2.mMass;
//If the momentum is negative, reverse the direction the object is going in.
if(physicalObject1Momentum < 0.0f)
{
//Reverse the direction of object1.
physicalObject1.setMomentumRotationRotation(Functions.getRotationalMaxMinStatic(180f, physicalObject1.getMomentumRotation()));
//Decrease the momentum of object2.
}
else
{
//Slow down the physical objects 1 momentum.
physicalObject1.increaseMomentum(-physicalObject1Momentum);
physicalObject2.increaseMomentum(physicalObject1.mMaxMomentum);
physicalObject2.setMomentumRotationRotation(Functions.getRotationalMaxMinStatic(180f, physicalObject1.getMomentumRotation()));
}
//Compare both momentums.
//Compare mass.
}
}
}
}
}

Slow down enemy movement

I'm making a game using slick2d - and ive created a pathfinding algorithm, that will allow a 'zombie' to find the shortest path to the main hero.
public void findPrey(int characterXPosition,int characterYPosition){
Pathfinder p = new Pathfinder();
n = p.aStar(xPosition,yPosition,characterXPosition,characterYPosition);
//n is a linked list which holds node objects in the path
if(!n.isEmpty()){
xPosition = (n.get(0).x);
yPosition = (n.get(0).y);
}
}
At the moment this works, but it just moves the zombie a tile (32x32) really quickly - like way too quickly!
I tried this instead:
if(xPosition > n.get(0).x){
xPosition -= .1f * delta;
}
else if(xPosition < n.get(0).x){
xPosition += .1f * delta;
}
if(yPosition < n.get(0).y){
yPosition += .1f * delta;
}
else if(yPosition > n.get(0).y){
yPosition -= .1f * delta;
}
Which only works if the zombie goes up or left - even then its really jumpy and if its meant to go down or right it goes mental and just keeps going up out of the screen.
So anyone any idea how I can either slow down the movement of the first technique - or know why the second one isnt working?
Thanks for any help!
EDIT - ANSWER
Okay figured a solution out - was pretty basic , I think just staring at the same code for a few hours did me.
In the render method of my 'world' class where the zombies were getting rendered I just put this change in:
Iterator<Zombie> i = zombies.iterator();
while (i.hasNext()) {
Zombie z = i.next();
if (!z.isDead()) {
z.updateDelta(newDelta);
z.incrementCounter(); //put a counter variable in
if(z.getCounter() % 40 == 0){
z.findPrey((int)shiftX,(int)shiftY);
}
z.render(gc, sbg, g);
}else{
i.remove();
}
}
So i basically just added a counter variable in the Zombie class and then used modular so that it wouldnt get called as frequently.
Thanks for everyone for trying to help.
I suggest you use timers. Then on every computer game will work with the same speed and the movement of your units will be with fixed time.
Units move too fast, because every loop unit is moved. Amount fo loops should be less or decrease the distance moved by units.

Proper Collision

So basically im trying to figure out how to make a proper collision between two Rectangles.
Detecting isn't the problem, but the rectangles begin to clip. I wanted to reset the position, but how do I do that.
I'm trying to use dx and dy to reset, but it won't reset to the right coordinates.
http://i.stack.imgur.com/IU6sK.png (Sorry I can't use images yet)
System.out.println(this.y + this.h + " " + e.getY());
if(this.y + this.h >= e.getY())
{
if(this.dy > 0)
{
this.y -= delta * this.dy + 0.1;
this.dy = 0;
}
else
{
this.y += delta * this.dy;
this.dy = 0;
this.inAir = false;
}
}
This code is just an example to show how I am trying it for the top. (this = the white Rectangle and e = the orange one) I used my class Entity, which extends Rectangle.
I'm checking intersection before I call this. This is a function in the "white" Entity and the intersection is checked in the update function of the main loop.
If I use this, there is like 1px between the rectangles.
Any ideas?
Thanks for any help :)
http://docs.oracle.com/javase/6/docs/api/java/awt/Rectangle.html
Use the Rectangle class.
Here, some code
http://pastebin.com/raw.php?i=TzkST3Hm
The best way to do rectangular collision is to use the Rectangle class to detect collision using the .intersects(Rectangle) method, and then calculate a new variable called displacementX and displacementY.
displacementX = Math.abs(entitiy1.getX() - entity2.getX());
displacementY = Math.abs(entitiy1.getY() - entity2.getY());
So what we have currently is the amount of pixels entity1 is intruding on entity2 (or vice versa due to the absolute value). Then, run some comparisons and move entity1 (or entity2) by the value of the lesser displacement, which should yield perfect-looking collision.
This is at least how I do it. The correct method for rectangular collision is to:
1) Determine if they collide
2) Correct it
3) Render
Simply preventing movement after detecting collision will look horrible (especially on low frame rates).
Hope I helped!
~Izman

Continuous movement after touch?

Found plenty of questions that were similar, but nothing that answers my own problem. It's probably something really bloody simple, but it's late and I can't fathom it. I've got an android game I'm working on, where you touch the screen and it 'fires' a sprite in that direction. I've got most of the code working, however, after the sprite fires and moves off, it gets to the touch point and then just wiggles. I would like it to carry on along that angle and eventually bounce around...
Here's my code (well the bits that matter):
List<TouchEvent> touchEvents = game.getInput().getTouchEvents();
int len = touchEvents.size();
for(int i = 0; i < len; i++) {
TouchEvent event = touchEvents.get(i);
if(event.type == TouchEvent.TOUCH_UP) {
touchPoint.set(event.x, event.y);
guiCam.touchToWorld(touchPoint);
}
}
//Log.d("PANDAM", touchPoint.x + "|" + touchPoint.y);
float speed = 112f;
double theta = 180.0 / Math.PI * Math.atan2(panda_y - touchPoint.y, panda_x - touchPoint.x);
Log.d("PANDAM", " > "+theta+" < ");
movePanda(theta, speed, deltaTime);
And the "movePanda" method:
private void movePanda(double angle, float speed, float deltaTime)
{
panda_x += speed * Math.cos(angle)*deltaTime;
panda_y += speed * Math.sin(angle)*deltaTime;
}
My question is, how do I get the panda to carry on along the touch vector and not spaz out when it reaches the original touch point?
You seem to be recalculating the angle each step of the animation, but you actually need to remember what the angle was when you first started moving. As you pass the original touch point, the angle changes to point the other direction, so if you reclcalculate it every animation step, it will change and eventually point the other way.

Moving objects getting stuck in a corner

I am working on a program which simulates objects moving in a field. The field has a boundary of 1024x1024. The object cannot go below 0 in terms of x,y coordinate and it cannot go above 1024. I have a method for each object called "move()" which moves the object in its current direction at its current speed. If the object approaches the boundary, it then turns around with a new direction and same speed.
The problem I am having is that when one of my objects gets close to both the x and y bound (corner of the field), it gets stuck in the corner. It is almost as if it is trying to move away from the corner, but then it turns back. It must love that corner. I looked over my code and to me, my logic seems correct. I check to make sure the new direction is not negative or over 359. I check to make sure the new x,y coordinate with the new direction is within the bounds too. I even have a method to set a new direction.
I have tried re-implementing this method with different logic, but no luck. If anyone could possibly find a flaw in my programming or point out what may be causing it, then that would be much appreciated.
I have tried to debug and step through my program and I see that when it gets to the corner, it changes direction to turn around, moves about 3 spaces, then goes back to the corner. Must be a wonderful corner.
Code for move method is below:
public void move(){
localX = super.getX();
localY = super.getY();
float newX=0, newY=0;
float testX, testY;
boolean acceptX = false, acceptY = false;
testX = (float) (Math.cos(direction)*10) + localX;
testY = (float) (Math.sin(direction)*10) + localY;
int testDirection;
while(!acceptX){
if(testX >= 0 && testX <= bound){
newX = testX;
acceptX = true;
}//end if statement
else{
if(direction+180 > 359){
setDirection(direction-180);
testX = (float) (Math.cos(Math.toRadians(direction))*speed) + localX;
}
else{
setDirection(direction+180);
testX = (float) (Math.cos(Math.toRadians(direction))*speed) + localX;
}
}//end else
}//end while that checks for X value
while(!acceptY){
if(testY >= 0 && testY <= bound){
newY = testY;
acceptY = true;
}//end if statement
else{
if(direction+180 > 359){
setDirection(direction-180);
testY = (float) (Math.sin(Math.toRadians(direction))*speed) + localY;
}
else{
setDirection(direction+180);
testY = (float) (Math.sin(Math.toRadians(direction))*speed) + localY;
}
}//end else
}//end while that checks for Y value
super.setX(newX);
super.setY(newY);
}
and here is the code for setDirection
public void setDirection(int d) {
direction = d;
}
Say you have an object in the upper left corner, going up. Your first test turns it around so it goes down. Then comes your second check, which turns it around again to go up... again.
Your code could also use some more readability. The very first thing I noticed is that you're using the >359 checks to normalize the new direction to go in. Yet all cases include the movement code as well. I would do something like:
setDirection(direction + 180); //turn around
if (direction >= 360) direction -= 360; //normalize
testY = ...; //move
to move the movement code out of the direction checking if/else blocks. 360 is also a better magic number to use; 359 degrees means nothing. As has been suggested, you should ultimately use a vector library and thus throw away most of the math.
I'd really recommend storing your direction as a vector (x, y) instead of calculating that vector from a scalar; I think that would help you immensely with your code.
Issue: When your object hits an edge, you turn it 180 degrees. If it hits both edges, it'll spin in place, and the test coordinates will always be in the wrong spot.
When one of your objects hits an edge, it needs to bounce, not About Face! Angle of incidence == angle of refraction, or some such. In other words, if you're checking the x coordinate and it bounces, negate the x velocity, not both x & y.

Categories