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.
Related
I am trying to find a good way to simulate bouncing in my 3D program. Here is how I am trying to do it: I am saying if the position.y < the limit (which is -5) then bounce back up. Here is the code
if(position.y > LIMITS.y)
velocity.y += Main.GRAVITY/ 1000;
else{
velocity.y = -velocity.y / 1.5f;
System.out.println(true);
}
However, the bouncing sometimes works and sometimes stops very short, if anyone knows why this is happening and can help me improve this I would be extremely appreciative.
So I think what you mean by stops very short is it is bouncing well then randomly stops at the bottom. This could be because the object goes more than 50% of it's distance that it will travel the next frame below the LIMIT of y. So the way to combat it is to reset the y position to its position before it went below.
else {
position.y -= velocity.y; // reset to position before going under
velocity.y = -velocity.y / 1.5f; // then adjust the velocity
System.out.println(true);
}
I am writing a physics engine and when the ball hits a surface it bounces up at half the velocity it came down at(velocity.y = -velocity). However when the ball is almost at rest it switches velocities constantly and starts falling through the platform incredibly slow but still will eventually fall through if I let it run long enough, and this is not acceptable. I tried writing some code to stop it but it checks way too fast here is the update method that attempts to check it.
public void update() {
velocity.y += Globals.GRAVITY.y;
if(canFall)
position.y += velocity.y;
position.x += velocity.x;
oldPosition.y = position.y;
oldPosition.x = position.x;
elapsedTime += 1 * Gdx.graphics.getDeltaTime();
if(elapsedTime >= 5){
if(oldPosition.y - 5 <= position.y && oldPosition.y + 5 >= position.y){
elapsedTime = 0;
canFall = false;
}else{
canFall = true;
elapsedTime = 0;
}
}
}
The collision handler knows when it hits the top of the ball which is the only solution I need for this. How do I check when the ball is at rest.
This code attempts to check if the ball hasn't moved in a couple seconds, if it hasn't it sets canFall to false. I need a generic check that will see if the ball should be at a stop. The velocity of the ball when it is falling through the platform you can see from the picture below. The picture shows the ball "at rest" after ten seconds so as you can see the ball is slowly but surely falling through. Every three seconds with this "rest" velocity the y position goes down 1, the velocity changes from positive to negative so the velocity you see in the picture isn't constantly negative. Ignore the elapsed time variable Any help is greatly appreciated!
Why let time have anything to do with it? I'm not saying it coudln't, but should it? So maybe lose the if(elapsedTime ... ) conditional.
Isn't this what you want? If the magnitiude of the vertical difference between the last two positions is negligible (set tolerance accordingly; maybe it's 5), stop bouncing:
if(Math.abs(position.y - oldPosition.y) < tolerance)
{
canBounce = false;
...
}
else
{
canBounce = true;
...
}
or, if nothing else needs to change at the ... above:
canBounce = Math.abs(position.y - oldPosition.y) > tolerance;
Also, don't you need { and } somewhere in the segment below? Maybe not, if ball is bouncing vertically, but it looks like x can change, too, which might make the code above need adjusting. But the way code below is indented makes me think there's supposed to be more to do than just changing position.y:
if(canFall)
position.y += velocity.y;
position.x += velocity.x;
oldPosition.y = position.y;
oldPosition.x = position.x;
Finally, you're addding velocity to position. That seems questionable. Multiply velocity times time? Or is time = 1 always? (Doubt it.)
The problem may be external to this method. Something needs to keep ball's y from becoming less than the y of the top of the dark blue box. This code can't do that without knowing y of top of dark blue box (unless you apply physics formulas?). Maybe include this value in parameter list as topOfDarkBlueBox?
Then add code such as:
if(position.y < topOfDarkBlueBox.y) position.y = topOfDarkBlueBox.y
I'd rather see physics at work, but you might say, "Who'd notice?"
EDIT
You wrote, "The collision handler knows when it hits the top of the ball," but I assume you meant "when the ball hits the top of the dark blue box". Maybe call the collision handler instead of passing new parameter topOfDarkBlueBox?
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
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.
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.