Java 2d game - Issues with delta time and collision - java

I'm trying to make a java 2d game, and it seems to work out fine in general. The only problem is, that I can't figure out how to place my "delta" time, to make the movements move the same on 30 FPS as on 1000 FPS.
This is my code for the Entity class:
import java.awt.Rectangle;
import map.Tile;
import graphics.Sprite;
public class Entity {
private String name;
private float positionx, positiony; // Current coordinate
private int targetx,targety; // Target coordinate
private double vx, vy; // Current vector
private double lx, ly; // Last vector
private float speed;
private Sprite sprite;
public Entity(String name, int x, int y, Sprite sprite){
this.name = name;
this.speed = 1f;
this.positionx = x;
this.positiony = y;
this.sprite = sprite;
main.Main.e.addEntity(this); // These kind of calls are ugly, and should be fixed.
}
public void remove(){
main.Main.e.removeEntity(this);
sprite.remove();
}
public void setVector(double vx, double vy){
this.vx = vx;
this.vy = vy;
}
public void update(long delta){
//Multiply modifier to make it act the same on 30 fps as 1000 fps.
vx = vx*delta;
vy = vy*delta;
// Calculate vector
double distance = Math.sqrt((vx * vx) + (vy * vy));
if(distance > 0){ // Have we reached the target yet?
vx = ((vx / distance));
vy = ((vy / distance));
}else{
vx = 0;
vy = 0;
}
//Check collision with objects:
Rectangle rx = new Rectangle((int) (vx+positionx), (int)positiony, 32, 32);
Rectangle ry = new Rectangle((int) positionx, (int)(vy+positiony), 32, 32);
for(Entity e : main.Main.e.getEntities()){
if(this != e){
if(isIntersecting(rx, e.getBounds())){
vx = 0; // Disallow x direction.
}
if(isIntersecting(ry, e.getBounds())){
vy = 0; // Disallow y direction.
}
}
}
//Check tiles:
for(Tile t : main.Main.m.getNeighbours(positionx,positiony)){
if(t.isBlocking()){
if(isIntersecting(rx, t.getBounds())){
vx = 0;
}
if(isIntersecting(ry, t.getBounds())){
vy = 0;
}
}
}
//Update the position:
positionx += vx*speed;
positiony += vy*speed;
//Animate:
animate(vx, vy);
}
public boolean isIntersecting(Rectangle r1, Rectangle r2){
return r1.intersects(r2);
}
public Rectangle getBounds(){
return new Rectangle((int) positionx,(int) positiony,32,32);
}
public void setMoveTo(int x, int y){
this.targetx = x;
this.targety = y;
}
//This function is used by the bots, and not on players (they are setting the vector and use update directly):
public void moveTo(long delta){
setVector((targetx-positionx),(targety-positiony));
update(delta);
}
public void animate(double dx, double dy){
sprite.setPosition((int)positionx, (int)positiony);
if(dx > 0){
sprite.setAnimation(0, 7, 100); // Walk right.
}else if(dx < 0){
sprite.setAnimation(1, 7, 100); // Walk left.
}else{
if(lx > 0){
sprite.setAnimation(2, 3, 200); // Stand right.
}else if(lx < 0){
sprite.setAnimation(3, 3, 200); // Stand left.
}
}
lx = dx;
ly = dy;
}
}
The two problems, that I always run into:
1# The game runs differently on 60FPS than on 500FPS.
2# The game runs the same on 60FPS as 500FPS, but my collision screws up, and I can't move closer than 15px from the other object. I think I need to implement something like: If I can't get 10px closer, then move it 10px closer, but I don't know how to implement it.
How can I implement it correctly? That would help a lot!

The easiest way would be to consider that if you want a constant displacement with a constant velocity you can scale all the deltas relative to the delta of 30 FPS like so:
So if you run at 60 FPS but want the same displacement as on 30FPS alpha would be (1/30)/(1/60) = 2
So
Remove vx = vx*delta;
vy = vy*delta;
and change your position update to
alpha = (1.0/30)*delta;
positionx += alpha*vx*speed;
positiony += alpha*vy*speed;
This is only a crude solution, let me know how it works, I will drop in later and update for a more correct solution (taking into account that delta is not always 1/FPS due to rendering and computation taking some time).
Edit: Variable delta will come later. But some optimizations:
You don't need to construct a rectangle in both Y and X for collisiondetection, try drawing two rectangles, if they intersect they do so on both axis. Just create a rectangle from vx + posx, vy+posy and check for intersection with this.
The above should half your collisionchecks. For further optimization consider using a QuadTree an implementation can be found here.
For the problem of "blocky" collision testing (where you stop X pixels from the blocking object). You can do the following, in pseudocode:
if(new position will make this colide)
while(this.position is more than one pixel away from blocking object)
keep moving one pixel
This will make you stop 1px from the target.

Related

Remove enemy when bullet hits them

class Bullet {
float bulletX, bulletY;
float angle;
int x;
int y;
int score; // add a score variable
static final float BULLET_SPEED = 5; // define a constant for the bullet's speed
Bullet(float x, float y, float angle) {
this.bulletX = x;
this.bulletY = y;
this.angle = angle;
}
// Updates the position of the bullet based on its angle and speed.
void update() {
bulletX += cos(angle) * BULLET_SPEED;
bulletY += sin(angle) * BULLET_SPEED;
}
// Draws the bullet image on the screen.
void show() {
drawBullet();
}
// Draws the bullet image on the screen.
void drawBullet() {
image(Bulletimg, bulletX, bulletY);
Bulletimg.resize(30, 30);
}
//Returns true if the bullet is off screen, false otherwise.
boolean offScreen() {
return bulletX < 0 || bulletX > width || bulletY < 0 || bulletY > height;
}
//Checks if the bullet hits the enemy, and updates the score and enemy position accordingly.
// check for collision
void checkCollision(Enemy e) {
float distance = dist(bulletX, bulletY, e.x, e.y);
if (distance < e.x / 2) {
// assuming enemy.size is the radius of the
}
}
}
I tried changing around the check collision(enemy e) block and I'm not sure how i would go about removing an enemy object and also updating my score. i've tried messing about with the draw(); method but i cant seem to figure it out without breaking my entire game. any help with this class would be much appreciated.
You can use/create some attribute in your Enemy object to know/check if is alive or death.
For example in your check collision you can add
if (distance < e.x / 2) {
// assuming enemy.size is the radius of the
e.alive = false
}
Edit: I dont know how your manage the Enemy object and if it can be modified directly in the check collision method if this is not possible then you need to find a way to have access inside the method or use a return and manage that return outside.

Processing angle calculation on rotated object

I am making a little ant colony simulation in Processing (4).
I have an Ant class, with a sense() , a move()and a render() function.
I also have a Food class with only a position PVector.
My sense class loops through all Foods in a given radius, and it is meant to only 'see' the ones inside a given view angle.
In my render() function I have an arc to visualise this (I do some division and addition so the arc centres in front of the rectangle):
void render() {
// Draw a rectangl rotated in the direction of velocity
float theta = velocity.heading() + radians(90);
if(detectFood) // a Boolean set in sense()
fill(0,173,67); // turns green
else {
stroke(255);
pushMatrix();
translate(position.x, position.y);
fill(200, 100);
rotate(theta); // I copied the rotation code from somewhere :)
rect(0-r/2,0-r,r,r*2); // r is a float used to control size
arc(0, 0, viewRadius * 2, viewRadius * 2, radians(270 - viewAngle/2), radians(270 + viewAngle/2)); // viewRadius is a float set in the constructor
popMatrix();
}
}
This ends up looking like this:
My sense() code uses trigonometry to calculate the angle and the distance (I am using my own calculations because wasn't sure the inbuilt ones did what I thought they did):
void sense() {
if (!detectFood) {
float closest = viewRadius;
Food selected = null;
for (Food fd : foods){
float foodDist = position.dist(fd.position);
if(foodDist <= viewRadius) {
float xs = position.x-fd.position.x;
float ys = position.y-fd.position.y;
float Angle = atan2(abs(ys), abs(xs));
float begin = radians(270 - viewAngle/2);
float end = radians(270 + viewAngle/2);
if(begin < Angle && Angle < end && foodDist < closest){
selected = fd;
closest = foodDist;
println("found food");
}
}
}
if (selected != null){
detectFood = true;
foodFocused = selected;
}
} else {
if(position.dist(foodFocused.position) < r) {
takeFood();
detectFood = false;
}
}
}
The problem is that because I rotate the shape (and the arc with it), my sensing code basically never works. Is there a way to account for rotation in trigonometry or maybe an easier way of doing this? Any help would be apreciated

Libgdx intersection of polygons

I'm learning libgdx by adding some more features to the open source jumper game from Mario Zechner. I'm trying to make some platforms with an angle and run into the problem of collision detection of rotated rectangles.
I followed this solution and used Polygons along with my rectangle bounds.
For testing purposes I don't set an angle yet. I just want to verify that bob jumps correctly off the platforms. But for some reason this doesn't work. the bounds are either too far to the left, above the platform, or not there at all. Am I not setting the polygon correctly?
Would it be easier to use Box2d? I don't have any experience with that and I'm wondering if that's overkill for simple platforms.
public PlatformClient(int platformType, float x, float y) {
this.platformType = platformType;
float x1 = x - Platform.PLATFORM_WIDTH/2;
float y1 = y + Platform.PLATFORM_HEIGHT/2;
this.polyBounds = new Polygon(new float[]{x1, y1, x1+Platform.PLATFORM_WIDTH, y1, x1+Platform.PLATFORM_WIDTH, y1-Platform.PLATFORM_HEIGHT, x1, y1-Platform.PLATFORM_HEIGHT});
polyBounds.setPosition(x-Platform.PLATFORM_WIDTH/2, y-Platform.PLATFORM_HEIGHT/2);
}
class Platform {
public static final float PLATFORM_WIDTH = 2f;
public static final float PLATFORM_HEIGHT = 0.35f;
}
In Bob class update the polygon bounds when he moves:
public void update(float deltaTime) {
...
position.add(velocity.x * deltaTime, velocity.y * deltaTime);
bounds.x = position.x - BOB_WIDTH / 2;
bounds.y = position.y - BOB_HEIGHT / 2;
float newX = position.x - BOB_WIDTH / 2;
float newY = position.y - BOB_HEIGHT / 2;
polyBounds.setVertices(new float[]{
newX, newY,
newX+BOB_WIDTH, newY,
newX+BOB_WIDTH, newY-BOB_HEIGHT,
newX, newY-BOB_HEIGHT});
}
In World class:
private void checkPlatformCollisions () {
int len = platforms.size();
for (int i = 0; i < len; i++)
{
PlatformClient platform = platforms.get(i);
if (bob.position.y >= platform.position.y)
{
if(Intersector.overlapConvexPolygons(bob.polyBounds, platform.polyBounds))
{
System.out.println("it overlaps");
// jump off platform
}
}
}
}
EDIT
Thanks to the shape renderer, I was able to set the polygons correctly. I fixed some +,- issues in the code above. But the following code: Intersector.overlapConvexPolygons() still doesn't work (see image). He jumps before the polygons are making contact or he doesn't jump at all.
Any further ideas?
That's how I draw the polygon of Bob and the platforms that clearly overlap.
public void render() {
shapeRenderer.setProjectionMatrix(cam.combined);
shapeRenderer.begin(ShapeType.Line);
for(int i=0; i<world.platforms.size(); i++) {
shapeRenderer.setColor(1, 0, 0, 1);
shapeRenderer.polygon(world.platforms.get(i).polyBounds.getVertices());
shapeRenderer.polygon(world.bob.polyBounds.getVertices());
}
shapeRenderer.end();
}
ok, I solved it by removing
polyBounds.setPosition(x-Platform.PLATFORM_WIDTH/2, y-Platform.PLATFORM_HEIGHT/2);
from the constructor. Now the collision works correctly.

how can i make a graphic object solid in java?

I'm working on a simple game and i need these squareBumpers which simply stands idle and when got hit, collides and reflects the ball. But currently the ball just flies through my squareBumpers. I can only use java awt and swing libraries. Here's the code:
class squareBumper {
private int x = 300;
private int y = 300;
private Color color = new Color(66,139,139);
public void paint(Graphics g) {
Rectangle clipRect = g.getClipBounds();
g.setColor(color);
g.fillRect(x, y, 31, 31);
}
}
class BouncingBall {
// Overview: A BouncingBall is a mutable data type. It simulates a
// rubber ball bouncing inside a two dimensional box. It also
// provides methods that are useful for creating animations of the
// ball as it moves.
private int x = 320;
private int y = 598;
public static double vx;
public static double vy;
private int radius = 6;
private Color color = new Color(0, 0, 0);
public void move() {
// modifies: this
// effects: Move the ball according to its velocity. Reflections off
// walls cause the ball to change direction.
x += vx;
if (x <= radius) { x = radius; vx = -vx; }
if (x >= 610-radius) { x = 610-radius; vx = -vx; }
y += vy;
if (y <= radius) { y = radius; vy = -vy; }
if (y >= 605-radius) { y = 605-radius; vy = -vy; }
}
public void randomBump() {
// modifies: this
// effects: Changes the velocity of the ball by a random amount
vx += (int)((Math.random() * 10.0) - 5.0);
vx = -vx;
vy += (int)((Math.random() * 10.0) - 5.0);
vy = -vy;
}
public void paint(Graphics g) {
// modifies: the Graphics object <g>.
// effects: paints a circle on <g> reflecting the current position
// of the ball.
// the "clip rectangle" is the area of the screen that needs to be
// modified
Rectangle clipRect = g.getClipBounds();
// For this tiny program, testing whether we need to redraw is
// kind of silly. But when there are lots of objects all over the
// screen this is a very important performance optimization
if (clipRect.intersects(this.boundingBox())) {
g.setColor(color);
g.fillOval(x-radius, y-radius, radius+radius, radius+radius);
}
}
public Rectangle boundingBox() {
// effect: Returns the smallest rectangle that completely covers the
// current position of the ball.
// a Rectangle is the x,y for the upper left corner and then the
// width and height
return new Rectangle(x-radius, y-radius, radius+radius+1, radius+radius+1);
}
}
Take a look at the classes that implement the Shape interface. There are ellipses and other shapes, and they all implement a intersects(Rectangle2D) method. It might help you if you don't want to perform intersection yourself.
As for dealing with the collision, well, it depends on the level of accuracy you want. Simply deflecting the ball of edges is quite easy. Just determine whether the collided side of the rectangle is vertical or horizontal, and negate the corresponding velocity component accordingly. If you want to handle the corners, well that is a bit more complicated.
You need to detect when the ball has collided with the bumper. You have the boundingBox() method of BouncingBall, this will get you a rectangle that contains your ball. So you need to check if this rectangle intersects your square bumper (which implies a collision), and then do something with that.

Simulate the gravitational pull of a star?

I'm making a game where the player will (on release of mouseclick) shoot a "star" in a certain direction at an initial speed determined by how far he dragged the mouse before releasing. I have a "planet" (stationary circle) on the canvas that I want to exert a gravitational pull on the moving planet. I believe I'm using the right formulas for gravitational force and such, and I have it partially working - the planet affects the planet's trajectory up until a certain point, when the star seems to endlessly speed up and stop changing direction based on it's angle to the star. Any advice? (I know that stars aren't supposed to orbit planets, it's the other way around. I coded the whole thing with the names interchanged so forgive that).
main class:
import acm.graphics.GCompound;
import acm.graphics.GImage;
import acm.graphics.GLabel;
import acm.graphics.GLine;
import acm.graphics.GMath;
import acm.graphics.GObject;
import acm.graphics.GPen;
import acm.graphics.GPoint;
import acm.graphics.GRect;
import acm.graphics.GOval;
import acm.graphics.GRectangle;
import acm.program.GraphicsProgram;
import acm.util.RandomGenerator;
import java.awt.Color;
import java.awt.event.MouseEvent;
import java.util.*;
public class Space extends GraphicsProgram {
public static int APPLICATION_WIDTH = 1000;
public static int APPLICATION_HEIGHT = 1000;
private int size = 15;
public static double pMass = 1000;
public static int sMass = 20;
public static double G = 200;
private RandomGenerator rand = new RandomGenerator();
GOval planet, tempstar;
shootingStar star;
GLine line;
double accel, xAccel, yAccel, xspeed, yspeed, angle;
public void init(){
planet = new GOval(APPLICATION_WIDTH/2, APPLICATION_HEIGHT/2, 30, 30);
planet.setFilled(true);
planet.setFillColor(rand.nextColor());
add(planet);
}
public void mousePressed(GPoint point) {
// draw a line
tempstar = new GOval(point.getX() - size/2, point.getY() - size/2, size, size);
tempstar.setFilled(true);
tempstar.setColor(rand.nextColor());
add(tempstar);
line = new GLine(tempstar.getX() + size/2, tempstar.getY() + size/2,
point.getX(), point.getY());
add(line);
line.setVisible(true);
}
public void mouseDragged(GPoint point) {
line.setEndPoint(point.getX(), point.getY());
}
public void mouseReleased(GPoint point){
xspeed =
-.05*GMath.cosDegrees(getAngle(line))*GMath.distance(line.getStartPoint().getX(),
line.getStartPoint().getY(), line.getEndPoint().getX(), line.getEndPoint().getY());
yspeed =
.05*GMath.sinDegrees(getAngle(line))*GMath.distance(line.getStartPoint().getX(),
line.getStartPoint().getY(), line.getEndPoint().getX(), line.getEndPoint().getY());
System.out.println(xspeed + " " + yspeed);
star = new shootingStar(xspeed, yspeed, this);
if(xspeed != 0)
add(star, tempstar.getX(), tempstar.getY());
new Thread(star).start();
remove(tempstar);
remove(line);
}
private double getAngle(GLine line) {
return GMath.angle(line.getStartPoint().getX(), line.getStartPoint().getY(),
line.getEndPoint().getX(), line.getEndPoint().getY());
}
public void checkPlanet(){
accel = .06*GMath.distance(star.getX(), star.getY(), planet.getX(),
planet.getY());
angle = correctedAngle(GMath.angle(planet.getX(), planet.getY(), star.getX(),
star.getY()));
xAccel = accel*GMath.cosDegrees(GMath.angle(planet.getX(), planet.getY(),
star.getX(), star.getY()));
yAccel = accel*GMath.sinDegrees(GMath.angle(planet.getX(), planet.getY(),
star.getX(), star.getY()));
double newX = xspeed - xAccel*.01;
double newY = yspeed + yAccel*.01;
xspeed = newX + xAccel*Math.pow(.01, 2)/2;
yspeed = newY + yAccel*Math.pow(.01, 2)/2;
star.setSpeed(xspeed, yspeed);
}
public double correctedAngle(double x) {
return (x%360.0+360.0+180.0)%360.0-180.0;
}
}
Pertinent parts of shootingStar class:
public void run() {
// move the ball by a small interval
while (alive) {
oneTimeStep();
}
}
// a helper method, move the ball in each time step
private void oneTimeStep() {
game1.checkPlanet();
shootingStar.move(xSpeed, ySpeed);
pause(20);
}
public void setSpeed (double xspeed, double yspeed){
xSpeed = xspeed;;
ySpeed = yspeed;
}
}
EDIT:
Current Main Class Method:
public void checkPlanet(){
double xDistance = star.getX() - planet.getX();
double yDistance = star.getY() - planet.getY();
double distance = Math.sqrt(Math.pow(xDistance, 2) + Math.pow(yDistance, 2));
accel = G*pMass/Math.pow(distance, 2);
xAccel = accel * xDistance/distance;
yAccel = accel * yDistance/distance;
xspeed += xAccel;
yspeed += yAccel;
star.setSpeed(xspeed, yspeed);
}
Current Star class Method:
public void run() {
while (alive) {
oneTimeStep();
}
}
private void oneTimeStep() {
game1.checkPlanet();
shootingStar.move(xSpeed, ySpeed);
pause(20);
}
public void setSpeed (double xspeed, double yspeed){
xSpeed = xspeed;;
ySpeed = yspeed;
}
}
Wow, that's a lot more effort than what you "HAVE" to do.
If the thing is on the board calculate it's distance from the object. If it's farther away than D do nothing. If it's D away then it's within the objects gravitational pull. Just add a small amount of velocity to it pointing at the object. Let's say it was 1000 X away and 500 z away. Just do something simple like divide by 100, and add that to the objects velocity so it moves 10 x and 5 y towards the object. Each time you update add the velocity again.
You'll probably want a maximum velocity also. This is a LOT easier to calculate works well, and will give you effects like in the game STAR CONTROL where there's a planet, or the ships gravitationally pull towards each other a tiny bit. I did this with 10 planets and a star, and the user could basically do lunar lander with each planet. It was a blast but I never turned it into a real game. This has the advantage of being rockingly fast to calculate. There some edge conditions like if you make the map a torus so they warp through the sides of the map, but basically it's all just simple addition and subtraction.
It's GOOD enough for a game. You're not making a simulator. You're making a game.
I am not sure, but try to change the part where you calculate the xAccel and yAccel values to something like this.
xDistance = XComponentObject1 - XComponentObject2;
yDistance = YComponentObject1 - YComponentObject2;
(xDistance and yDistance can have negative values)
Distance = sqrt( xDistance^2 + yDistance^2 );
gConstant = constant Value for gravitational strenght in your world;
MassObject1 = some Mass;
MassObject2 = some other Mass;
Accel = gConstant*MassObject1*MassObject2 / (Distance^2 );
''NOW COMES THE IMPORTANT PART''
xAccel = Accel * xDistance/Distance;
yAccel = Accel * yDistance/Distance;
I think your whole yadayada with sine and cosine creates a whole bunch of hard-to-trackdown-errors.

Categories