I have an object(which is a ball) having its position at the top of the screen that fall directly whenever I start running the program. The problem is that the ball fall to its constant speed, I want it to fall accelerating with gravity effects and when it reach the ground, I want it to bounce a few more times before it stop moving. Could someone help me about this?
Here's what I've tried:
public class Balls
{
private double x;
private double y;
private double speed;
private double mass;
private final double gravity = -9.8;
private final double width = 100;
private double height = 100;
private final Board board;
private boolean isFalling = false;
private double distance_y;
private double distance_x = 0;
public Balls(double x, double y, double speed, double mass, Board board)
{
this.x = x;
this.y = y;
this.board = board;
this.speed = convertToMeterSpeed(speed);
this.mass = mass;
}
private double convertToMeterSpeed(double speed)
{
return speed / 3.6;
}
public void moveBall(long dt)
{
double time = dt / 1e9; // seconds
double diameter_y = height / 2.0;
double radius = (diameter_y / 2.0);
double velocity_y = speed * dt / 1e9;
distance_y = board.getHeight() - y;
if (distance_y - radius > 0)
{
isFalling = true;
}
if (isFalling)
{
if (distance_y >= height)
{
distance_y = distance_y + (0.5 * gravity * (time * time)); // represents the 1/2,
distance_y = board.getHeight() - height;
y += velocity_y;
}
else
{
isFalling = false;
}
try
{
Thread.sleep(10);
}
catch (InterruptedException e)
{
}
}
}
public void render(Graphics2D g2d)
{
g2d.fillOval((int) x, (int) y, (int) width, (int) height);
}
}
speed = v0 + gt^2/2,
where
v0 - initial speed
g = 9.81 on Earth.
t - time
Now you can calculate the speed at any time.
You probably want to define a maximum speed (terminal velocity) so your ball doesn't accelerate to an enormous speed. Gravity accelerates at 9.8m/s/s. Once the ball hits the "ground" you just reverse the speed and update the current position to make it bounce, then on your next iteration gravity will be applied again so it will go back down. Eventually, the speed will get to 0 as the ball doesnt bounce so much, and will stop.
Here's an (untested) example:
private static final double GRAVITY = 9.8;
private static final double TERMINAL_VELOCITY = 100;
private double speed;
private int current_y;
public void fallAndBounce() {
speed = speed + GRAVITY;
if (speed > TERMINAL_VELOCITY) { speed = TERMINAL_VELOCITY; }
if (current_y >= bottomOfScreen)
{
//We have hit the "ground", so bounce back up. Reverse
//the speed and divide by 4 to make it slower on bouncing.
//Just change 4 to 2 or something to make it faster.
speed = -speed/4;
}
current_y += speed;
}
Your problem is that you are trying to animate a ball falling, but you are instead writing an algorithm for solving its position given a certain time.
This means you should take your time variable dt completely out of the equation, and just move your ball with each iteration of a loop like this:
while (true)
{
moveBall();
render();
try {
Thread.sleep(10)
} catch(InterruptedException e) {
e.printStackTrace();
}
}
Also, change your variables slightly:
// Add this to your variables
private final double GRAVITY = -9.8; // Final variables should be capitalized
private final double TERMINAL_VELOCITY = -30; // Whatever you want it to be
Here is the main change:
public void moveBall()
{
double diameter_y = height / 2.0;
double radius = (diameter_y / 2.0);
double velocity_y = speed * dt / 1e9;
distance_y = board.getHeight() - y;
if (distance_y - radius > 0)
{
isFalling = true;
}
if (isFalling)
{
if (height < distance_y)
{
if (velocity_y <= TERMINAL_VELOCITY)
velocity_y += GRAVITY; // implementing acceleration (gravity)
// just means adding it to velocity.
y += velocity_y;
}
Really, I don't know how this was possibly working before.
Related
I am trying to make a game where enemies spawn from the top (like a vertical scrolling game) and one kind of enemy will basically follow the player's X coordinate while going down. The enemy class is called Follower and right now it does points to the player (see update function on Follower) but it's not as accurate as I need it to be. For example, if the player accelerates, the follower won't be able to see him all the time.
One way to look at it is that I want the position of the player to be a coordinate in a radiant system and make the vertices of my Follower accurately just rotate and create a straight line looking at it every frame
here is the Follower Class:
public class Follower {
Player target; //follow this
//position
private Vector2 position;
private float x;
private float y;
//speed
private Vector2 velocity;
private float speed;
private float radians;
private float faceTarget;
//dimensions
private float[] shapeX;
private float[] shapeY;
private int numPoints; //vertices for the shape
private boolean remove; //to remove from the game
public Follower(float x,float y, Player target){
this.target = target;
this.x = x;
this.y = y;
velocity = new Vector2(0, 0);
numPoints = 4;
speed = 200;
shapeX = new float[numPoints];
shapeY = new float[numPoints];
radians = 3.1415f / 2;
setShape();
}
public void setShape(){
//top vertice
shapeX[0] = x + MathUtils.cos(radians) * 30;
shapeY[0] = y + MathUtils.sin(radians) * 30;
//left vertice
shapeX[1] = x + MathUtils.cos(radians - 4 * 3.1415f / 10) * 30;
shapeY[1] = y + MathUtils.sin(radians - 4 * 3.1415f / 10) * 30;
//bottom vertice
shapeX[2] = x + MathUtils.cos(radians + 3.1415f) * 60;
shapeY[2] = y + MathUtils.sin(radians + 3.1415f) * 60;
//left vertice
shapeX[3] = x + MathUtils.cos(radians + 4 * 3.1415f / 10) * 30;
shapeY[3] = y + MathUtils.sin(radians + 4 * 3.1415f / 10) * 30;
}
public boolean shouldRemove() {
return remove;
}
public void update(float dt) {
float angle = (float) Math.atan2(target.getPosition().y - y, target.getPosition().x - x); //angle between the follower and target
velocity.set((float) Math.cos(angle) * speed , -speed); //setting direction to follow the target
radians += Math.cos(angle) * dt; //THIS HERE IS MAKING IT ROTATE
x += velocity.x * dt;
y += velocity.y * dt;
setShape();
if(y <= 0 - 60)
remove = true;
else
remove = false;
}
public void draw(ShapeRenderer sp){
sp.setColor(1, 1, 1 ,1);
sp.begin(ShapeRenderer.ShapeType.Line);
for(int i = 0, j = shapeX.length - 1;
i < shapeX.length;
j = i++) {
sp.line(shapeX[i], shapeY[i], shapeX[j], shapeY[j]);
}
sp.end();
}
}
I am not adding the GameScreen because I do not see the need of showing how they are rendered, either way, it'll stay the same.
Also, with the line of code, I am using the Follower points to the player with the bottom vertice as the "eyes"
Thanks for the answers!
I'm making a rudimentary particle simulator in Java. For now, all I've done is make the particles atract each other with an equivalent to the electrical force. This part works fine (or at least as well as you would expect for such a basic model).
However, when I add a few particles, the program loses their values for position, velocity and acceleration, but does not lose other data (like, for example, their ID number). This does not always happens with the same amount of particles. Sometimes it happens when I add the fourth, fifth, second or third particle, but never with the first one. It always happens when I click to add a particle, and after it fails, I can no longer add anything (which is odd), and the particles don't move anymore (as you would expect, being their velocities and accelerations 0).
I am storing the particles in an ArrayList. The array does not lose the data (I've checked, the objects are in there, and I can even call their toString() method and retrieve their ID). The problem seems to be related to synchronization (given that it doesn't always happen at the same moment, it seems to be a bit random), but I can't figure out what it is.
I leave all the relevant code below.
public class Scene implements KeyListener, MouseListener, MouseMotionListener{
public static ArrayList<Particle> particleArray = new ArrayList<Particle>();
public static Object particleLock = new Object();
public void update() {
synchronized(particleLock) {
for(Particle particle: particleArray) {
double resultX = 0;
double resultY = 0;
for(int i = 0; i<particleArray.size(); i++) {
if(i != particleArray.indexOf(particle)) {
double[] result = PhysicsEngine.applyElectircalForce(particle, particleArray.get(i));
resultX += result[0];
resultY += result[1];
}
}
particle.netForceX = resultX;
particle.netForceY = resultY;
particle.update();
}
}
}
public void mousePressed(MouseEvent e) {
int mouseX = e.getX();
int mouseY = e.getY();
boolean positive = true;
if(e.getButton() == MouseEvent.BUTTON1) {
positive = true;
} else if(e.getButton() == MouseEvent.BUTTON3) {
positive = false;
}
synchronized(particleLock){
particleArray.add(new Particle(mouseX, mouseY, positive));
System.out.println("New particle added at " + mouseX + ", " + mouseY);
}
}
}
public class Particle{
public double x;
public double y;
public Point2D position;
public double velX;
public double velY;
public double acX;
public double acY;
private Color particleColor;
private int radius = 10;
// PHYSICS
public double mass;
public double charge;
public double netForceX;
public double netForceY;
private boolean positive;
public Particle(double x, double y, boolean positive) {
this.x = x - radius;
this.y = y - radius;
this.velX = 3;
this.velY = 2;
this.acX = 0;
this.acY = 0;
this.mass = 100;
this.positive = positive;
if(positive) {
this.charge = defaultCharge;
} else {
this.charge = defaultCharge*(-1);
}
this.position = new Point2D.Double(x, y);
particleColor = Color.WHITE;
}
public void update() {
acX = netForceX / mass;
acY = netForceY / mass;
velX += acX;
velY += acY;
if(x<=0 || x>=Simulation.WIDTH - 23){
velX = velX * -1;
x+= velX;
}
if(y<=0 || y>=Simulation.HEIGHT - 35){
velY = velY * -1;
y+= velY;
}
synchronized(Scene.particleLock) {
for(Particle otherPart: Scene.particleArray) {
if(otherPart.equals(this)) {
continue;
}
double distance = otherPart.position.distance(position);
if(distance <= radius + otherPart.radius) {
//aplicar lo que sé de choques de alguna manera
}
}
}
x+= velX;
y+= velY;
position.setLocation(x, y);
}
}
public class PhysicsEngine {
static double electricalConstant = 100000;
public static double[] applyElectircalForce(Particle thisPart, Particle otherPart) {
double distance = otherPart.position.distance(thisPart.position);
double angle = Math.asin(Math.abs(thisPart.y - otherPart.y)/distance);
double force = (electricalConstant * thisPart.charge * otherPart.charge)/Math.pow(distance, 2);
double forceX = force * Math.cos(angle);
double forceY = force * Math.sin(angle);
if(otherPart.x < thisPart.x) {
forceX = forceX*(-1);
}
if(otherPart.y < thisPart.y) {
forceY = forceY*(-1);
}
double[] result = {forceX, forceY};
return result;
}
}
I once had a similar problem with synchronization when I was working on an android project, try declaring particleArray volatile so that the compiler knows that particleArray will be changed on other or multiple threads. If that does not work I would suggest using a queue to push changes to the particle array from different threads and then pulling the intended changes to the array list in the update method to update your particle array list. In my experience changing values directly between different threads almost always causes problems.
I'm am using the environment Robocode in Java and am trying to create a robot to go up against the sample robot spinbot. I am calculating the center of the circle that the spinbot goes around and using that to aim at to get the best chances of hitting the spinbot. My code compiles fine but when I run it, it never goes into the onScannedRobot(ScannedRobot e) method. I tested it by changing the color of the robot at different points and I could tell it never entered.
package LaurasRobot;
import robocode.*;
import java.awt.Color;
// API help : http://robocode.sourceforge.net/docs/robocode/robocode/Robot.html
/**
* LaurasRobot - a robot by (Laura)
*/
public class LaurasRobot extends Robot
{
private double x1;
private double x2;
private double x3;
private double y1;
private double y2;
private double y3;
private int count;
private double centerX;
private double centerY;
/**
* run: LaurasRobot's default behavior
*/
public void run() {
setColors(Color.red,Color.white,Color.blue); // body,gun,radar
// Robot main loop, moves the robot forward and back
while(true) {
ahead(100);
back(100);
}
}
/**
* onScannedRobot: What to do when you see another robot
*/
public void onScannedRobot(ScannedRobotEvent e) {
setBodyColor(Color.yellow);//sets body color
//lets the gun, radar and body of the robot move indipendently
setAdjustGunForRobotTurn(true);
setAdjustRadarForGunTurn(true);
setAdjustRadarForRobotTurn(true);
if (count == 3)//creates to sample points to calculate the center of the cirlce with
{
count = 1;
x3 = e.getDistance()*(Math.cos(e.getBearing()));
y3 = e.getDistance()*(Math.sin(e.getBearing()));
}
if (count == 2)
{
count = 3;
x2 = e.getDistance()*(Math.cos(e.getBearing()));
y2 = e.getDistance()*(Math.sin(e.getBearing()));
}
else
{
count = 2;
x1 = e.getDistance()*(Math.cos(e.getBearing()));
y1 = e.getDistance()*(Math.sin(e.getBearing()));
}
while(y3 != 0.0)
{
setBodyColor(Color.blue);
if (count == 3)//creates to sample points to have an updated center
{
count = 1;
x3 = e.getDistance()*(Math.cos(e.getBearing()));
y3 = e.getDistance()*(Math.sin(e.getBearing()));
}
if (count == 2)
{
count = 3;
x2 = e.getDistance()*(Math.cos(e.getBearing()));
y2 = e.getDistance()*(Math.sin(e.getBearing()));
}
else
{
count = 2;
x1 = e.getDistance()*(Math.cos(e.getBearing()));
y1 = e.getDistance()*(Math.sin(e.getBearing()));
}
centerPoint();
double angle = angleGun(e);
turnGunRight(angle);//points the gun at the center of the circle that spinbot is makeing
fire(2);//fires one bullet at power 2
setBodyColor(Color.red);
}
}
/**
* onHitByBullet: What to do when you're hit by a bullet
*/
public void onHitByBullet(HitByBulletEvent e) {
back(10);
}
/**
* onHitWall: What to do when you hit a wall
*/
public void onHitWall(HitWallEvent e) {
// Replace the next line with any behavior you would like
back(20);
}
//returns the midpoint of two numbers
public double midPoint(double x1 , double x2)
{
double midx1;
if (x1 > x2)
{
midx1 = ((x1 - x2)/2)+x1;
}
else
{
midx1 = ((x2-x1)/2)+x1;
}
return midx1;
}
//saves the center points in the instance variables
public void centerPoint()
{
double midx1 = midPoint(x1,x2);
double midx2 = midPoint(x3,x2);
// double midx3 = midPoint(x1,x3);
double midy1 = midPoint(y1,y2);
double midy2 = midPoint(y3,y2);
// double midy3 = midPoint(y1,y3);
centerX = (midy2- (newSlope2())*midx2-midy1+(newSlope1())*midx1)/( newSlope1() - newSlope2());
centerY = midy1 - (newSlope1())*midx1+(newSlope1())*(centerX);
}
//get the angle to move the gun and make it stay their
public double angleGun(ScannedRobotEvent e)
{
double meToCenter = Math.sqrt(((centerX - getX()) * (centerX - getX())) +((centerY - getY()) * (centerY - getY())));
double himToCenter = Math.sqrt(((centerX - x1) * (centerX - x1)) +((centerY - y1) * (centerY - y1)));
double angle = e.getBearing() - Math.cosh(((e.getDistance())*(e.getDistance())+(meToCenter)*(meToCenter)-(himToCenter)*(himToCenter))/(2*(e.getDistance())*(meToCenter)));
return angle;
}
//gets the perpendicular reciprocal of the lines connecting the first two points
public double newSlope1()
{
return (-1)/((y1-y2)/(x1-x2));
}
//gets the perpendicular reciprocal of the lines connecting the second two points
public double newSlope2()
{
return (-1)/((y3-y2)/(x3-x1));
}
//gets the perpendicular reciprocal of the lines connecting the third two points
public double newSlope3()
{
return (-1)/((y1-y3)/(x1-x3));
}
}
It would be great if someone could tell what I did wrong/ how to fix it so that the code goes into this method, thanks.
I'm not sure if this has already been answered or solved ( I sure hope so after 10 months), but for future reference to anyone really. The ScannedRobotEvent will only trigger upon the execution of the Scan() method, or if the radar beam moves.
I'm trying to implement the last game loop on this site
Here is the code from the website:
const int TICKS_PER_SECOND = 25;
const int SKIP_TICKS = 1000 / TICKS_PER_SECOND;
const int MAX_FRAMESKIP = 5;
DWORD next_game_tick = GetTickCount();
int loops;
float interpolation;
bool game_is_running = true;
while( game_is_running ) {
loops = 0;
while( GetTickCount() > next_game_tick && loops < MAX_FRAMESKIP) {
update_game();
next_game_tick += SKIP_TICKS;
loops++;
}
interpolation = float( GetTickCount() + SKIP_TICKS - next_game_tick )
/ float( SKIP_TICKS );
display_game( interpolation );
}
// GetTickCount() returns the current number of milliseconds
// that have elapsed since the system was started
I have used System.currentTimeMillis() in place of GetTickCount() hoping that it would do the trick.
But I keep getting very strange results with my code:
Does anybody knows how to implement this Game loop in java?
Here is my non working example: (I keep getting large numbers for interpolation)
private final int TICKS_PER_SECOND = 25;
private final int SKIP_TICKS = 1000 / TICKS_PER_SECOND;
private final int MAX_FRAMESKIP = 5;
private double nextGameTick = System.currentTimeMillis() ;
private int loops;
private float interpolation;
private boolean isGameRunning = true;
public GameLoop(){
while( isGameRunning ) {
loops = 0;
while( System.currentTimeMillis() > nextGameTick && loops < MAX_FRAMESKIP) {
// update_game();
nextGameTick += SKIP_TICKS;
loops++;
}
interpolation = (float)( System.currentTimeMillis() + SKIP_TICKS - nextGameTick )/ (float)( SKIP_TICKS );
//display_game( interpolation );
view.display(interpolation);
}
}
I draw a ball at the location using the formula from the website but the ball just keeps spazzing out back and forth
view_position = position + (speed * interpolation)
I add the rest of my code so its less confusing:
(although i have a problem even before i hit this code because the interpolation number is huge when i run the debugger and it should be a fraction)
This is my View Class which paints the ball:
public class View extends JPanel
{
private static final long serialVersionUID = -2744215808270823059L;
Ball myBall = new Ball();
public void paintComponent(Graphics g){
super.paintComponent(g);
paintBall(g);
g.drawString(String.valueOf(interpolation), 20, 20);
g.drawString(String.valueOf(myBall.getLocation()), 20, 50);
}
private void paintBall(Graphics g){
g.drawOval(myBall.getLocation().x, myBall.getLocation().y, myBall.getDiameter(), myBall.getDiameter() );
}
private float interpolation;
public void display(float interpolation){
Point location = new Point();
this.interpolation = interpolation;
location.x = myBall.getLocation().x + (int)(myBall.getSpeedX() * interpolation);
location.y = myBall.getLocation().y + (int)(myBall.getSpeedY() * interpolation);
myBall.setLocation(location);
repaint();
}
}
And my ball class:
public class Ball {
private Point location = new Point();
private int diameter;
private double speed;
private double speedX;
private double speedY;
private double angle;
Ball(){
this(new Point(0, 10));
}
Ball(Point location){
this(10, 3, 60, location);
}
Ball(int diameter, double speed, double angleDeg, Point location ){
this.speed = speed;
setAngleDeg(angleDeg);
setDiameter(diameter);
setLocation(location);
}
//Getters and Setters
public double getAngleRad() {
return angle;
}
public void setAngleRad(double angle) {
this.angle = angle;
speedX = Math.cos(angle)*speed;
speedY = Math.sin(angle)*speed;
}
public double getAngleDeg() {
return angle*180/Math.PI;
}
public void setAngleDeg(double angle) {
this.angle = angle * Math.PI/180;
speedX = Math.cos(angle)*speed;
speedY = Math.sin(angle)*speed;
}
public double getSpeedX() {
return speedX;
}
public void setSpeedX(double speedX) {
this.speedX = speedX;
}
public double getSpeedY() {
return speedY;
}
public void setSpeedY(double speedY) {
this.speedY = speedY;
}
public Point getLocation() {
return location;
}
public void setLocation(Point location) {
this.location = location;
}
public int getDiameter() {
return diameter;
}
public void setDiameter(int diameter) {
this.diameter = diameter;
}
public double getSpeed() {
return speed;
}
public void setSpeed(double speed) {
this.speed = speed;
speedX = Math.cos(angle)*speed;
speedY = Math.sin(angle)*speed;
}
}
Using a busy wait in a game loop is bad practice, I'd recommend using a different strategy, like waiting for a display refresh to render the next frame. Most game frameworks include their own game loop logic, and I highly recommend looking into one of those.
The problem looks like you're feeding the time difference into view_position rather than adding it to the time to get the actual time. So the position of the ball is based on the jitter you get between frame times rather than the time itself.
Please try out a game framework before you think of reinventing the wheel with your own; it's a lot more fun working on the game logic rather than debugging the lower level stuff. Come back to this when you're more experienced and if you need it for performance.
I have an image that rotating in a counter clockwise direction. Now, I want it to move in a random direction during or whenever it touch the wall. The problem is I can't do it, please help me about this matter.
This is my code :
private double x;
private double y;
private double speed;
public void move(long dt)
{
double dt_s = dt / 1e9;
double dx = speed * dt_s;
double dy = speed * dt_s;
final double right_border = 100;
final double up_border = 100;
final double down_border = 0.0;
final double left_border = 0.0;
x += dx;
if (x >= right_border)
{
x = right_border;
if (y >= down_border)
{
y += dy;
}
}
if (y > up_border)
{
y = up_border;
if (x >= left_border)
{
speed *= -1;
}
}
if (x <= left_border)
{
x = left_border;
if (y <= up_border)
{
y += dy;
}
}
if (y < down_border)
{
y = down_border;
if (x <= right_border)
{
speed *= -1;
}
}
}
First you must solve the problem of your class being directionless - you have speed, but your direction is fixed at 45 degree north east (increment x and y the same).
Add direction to your class as follows:
...
private double speed;
private double angle; // in radians - makes math easier
public void move(long dt) {
...
double dx = speed * dt_s * Math.sin(angle);
double dy = speed * dt_s * Math.cos(angle);
...
Now to head in a random direction:
myObject.setAngle(Math.PI * 2 * Math.random()); // Math.PI * 2 = 360 degrees
If hitting a wall, you will have to limit your angle to an angle that's away from the wall you are hitting. I'll leave that to you, but it will take the form of:
myObject.setAngle(minAngle + ((maxAngle - minAngle) * Math.random()));
This is one possible solution.
Generate a random point (x,y) on one of the boundaries (other than the boundary that the image just hit), and make the image move towards that point. All you have to do is, find the slope between the point P1(x1,y1) it just hit, and the random point just generated P2(x2,y2). Using the slope you can find the equation of the line, it has to travel in. You're done!!