I have a homework problem that I could use a little help with.
I have an exploratory robot that I need to create a class for in which I can command it to move and return various different things about its status.
It has an initial rate at which it is moving of 5.0 units. I used this rate and the distance is has traveled to calculate the time it has been exploring.
I have to create a method that allows the user to change the rate multiple times and still calculate the time it has been traveling, with each part calculated at the rate it was traveling at the time.
Ex: The robot moves 50 fields at the rate of 5.0, then the rate is changed to 6.0 for 20 fields, then 2.0 for 80 fields.
Something along those lines.
Here's what I have for the object class so far.
private int xcoord, ycoord;
private int identification;
private double rate;
private double traveled;
//Sets up a robot with the given ID number and beginning x and y coordinates
public Robot (int id, int x, int y)
{
identification = id;
xcoord = x;
ycoord = y;
traveled = 0;
rate = 5.0;
}
//Has the robot travel to the set coordinates
public double setDestination (int x, int y)
{
double distance = Math.pow(x - xcoord, 2) + Math.pow(y - ycoord, 2);
traveled += Math.sqrt(distance);
xcoord = x;
ycoord = y;
return traveled;
}
//Gets the time spent travelling
public double getTimeSpent()
{
return traveled/rate;
}
//Sets the rate at which the robot travels
public void setRate(double setrate)
{
rate = setrate;
}
//Returns the ID of the robot
public int getID()
{
return identification;
}
I figure I will need to change my getTimeSpent() method, but I'm not sure how to change it so that it takes each leg of the journey at its individual rate. As set up right now, it will return the time of the whole journey at the last rate that was set.
Thanks for any help.
Couldn't you do something along the lines of this? Pretty much create an instance variable timeSpent and update that in setDestination using the distance traveled that time only instead of the whole distance, with the current rate and return it in getTimeSpent
private int xcoord, ycoord;
private int identification;
private double rate;
private double traveled;
private double timeSpent;
//Sets up a robot with the given ID number and beginning x and y coordinates
public Robot (int id, int x, int y)
{
identification = id;
xcoord = x;
ycoord = y;
traveled = 0;
rate = 5.0;
}
//Has the robot travel to the set coordinates
public double setDestination (int x, int y)
{
double distance = Math.pow(x - xcoord, 2) + Math.pow(y - ycoord, 2);
traveled += Math.sqrt(distance);
xcoord = x;
ycoord = y;
timeSpent += Math.sqrt(distance)/rate;
return traveled;
}
//Gets the time spent travelling
public double getTimeSpent()
{
return timeSpent;
}
//Sets the rate at which the robot travels
public void setRate(double setrate)
{
rate = setrate;
}
//Returns the ID of the robot
public int getID()
{
return identification;
}
Introduce another member to the class, say travelLog, which will be a list of pairs TravelLogEntry: (rate, distanceTraveledAtRate) -- that can be another class you'll have to create.
Something like this:
List<TravelLogEntry> travelLog = new ArrayList<TravelLogEntry>();
In setRate() you'll need to save the current rate and the distance traveled at the current rate to the travelLog, and then set the new rate:
travelLog.add(new TravelLogEntry(this.rate, this.traveled));
this.rate = newRate;
distance = 0;
In getTimeSpent() iterate over travelLog and compute time spent for each of its entries while accumulating the time in some temporary variable:
long totalTimeSpent = 0;
// go throught all the previous rates/distances
for(TravelLogEntry entry: travelLog){
totalTimeSpent += entry.traveled/entry.rate;
}
// and don't forget the current rate:
totalTimeSpent += traveled/rate;
In the end totalTimeSpent will contain the total time the robot traveled, adjusted to different travel rates.
This should do the trick.
UPDATE: Nevermind, I guess, #austin's solution is way simpler.
Related
I am writing a small libgdx program in java that was inspired by Kerbal Space Program and I am now writing the class that controls objects that will have forces acted on them. Each of these objects have a velocity vector that is changed by a forces vector.
The program runs around 60 frames per second and every frame the calculations done on the force to change velocity are done 1000 times. ( I have played with this number a lot however). Right now the program is incredibly simple and the only force that is exerted and calculated every iteration is from the planet.
forcedub = ((gravConstanat*parentBody.getMass())/Math.pow(loc.distance(parentBody.getLoc()),2));
force = new Point2D(((-1)*forcedub*Math.cos(a)),((-1)*forcedub*Math.sin(a)));
This changes the velocity sightly, the position is adjusted and the loop continues. The process works very well and seems stable. I haven't run it for days on end, but the orbit even at relatively high eccentricities seems stable. UNFORTUNATELY I need to be able to speed this process up so it doesn't take 2 days real time to get to the moon. So I needed a system that puts the orbit "on rails" and doesn't need to recalculate the forces each iterations. Once the multiplier value there gets set too high the orbit falls apart.
Good news is I already have this system in place, I just can't switch between the two.
I need a few values from the orbit to do this in my system. (I know some values are a bit redundant but it is what it is).
The semi major axis
the semi minor axis
the eccentricity vector
eccentricity
true anomaly
focus information.
To cut to the chase, the biggest issue is the eccentricity vector / eccentricity. My 'bake' function is the one that attempts to compute the values from the state vectors of the orbit every iteration and the value of the eccentricity varies drastically where it should stay the same in a standard orbit.The direction the vector is all over the place as well.
I have hard coded a single object that should have an eccentricity of about .62 and the eccentricity vector should point to pi, but the value wanders between .25 and .88 and the direction wanders between pi and pi / 3 ish.
Here are two versions of how to get the eccvecc from the state vectors, and I have tried them both. They both give the exact same results:
https://space.stackexchange.com/questions/37331/why-does-the-eccentricity-vector-equation-always-equal-1
https://en.wikipedia.org/wiki/Eccentricity_vector
public void bake(){
double velSq = Math.pow(vel.distance(0,0),2);
double r = loc.distance(parentBody.getLoc());
double gm = gravConstanat*parentBody.getMass();
Point2D posr = new Point2D(loc.getX()-parentBody.getX(), loc.getY()-parentBody.getY());
Point2D calc1 = posr.scale((velSq/gm));
Point2D calc2 = vel.scale((dotProd(posr,vel)/gm));
Point2D calc3 = posr.scale(1/r);
Point2D eccVecc = (calc1.minus(calc2)).minus(calc3);
ecc = eccVecc.distance(0,0);
w = Math.toRadians(90)-(Math.atan2(eccVecc.x(),eccVecc.y()));
semiA = (gm*r)/(2*gm - r*velSq);
semiB = semiA*(Math.sqrt((1-Math.pow(ecc,2))));
focus = findFocus(semiA,semiB);
System.out.println("ecc " + ecc + " W " + w + " SEMI A " + semiA);
System.out.println();
}
Here is the entire class:
**initial distance is about 900,000 to the left of the parent body
**parent mass is 5.3*Math.pow(10,22)
public class Klobject {
String name;
TextureAtlas textureAtlas;
Sprite sprite;
Cbody parentBody;
Point2D loc;
Point2D vel;
public boolean acceleration;
double MULTIPLIER;
static double gravConstanat = 6.67*Math.pow(10,-11);
double semiA, semiB, ecc, w;
protected double t;
protected double mass;
protected double rotateRate;
protected double focus;
public Klobject(Cbody cb){
mass = 1;
MULTIPLIER = 1;
rotateRate = 0;
parentBody = cb;
acceleration = false;
cb.addKlob(this);
loc = new Point2D((parentBody.getX() - 900_000f ),
(parentBody.getY()));
vel = new Point2D(0,2526.733);
sprite = textureAtlas.createSprite(name);
sprite.setOrigin(sprite.getWidth()/2, sprite.getHeight()/2);
bake();
}
public void update(float dt){
oneXupdate(dt);
bake();
}
private void oneXupdate(float dt){
int timesLooped = 1000;
double a;
double forcedub;
Point2D force;
Point2D velout;
double dx;
double dy;
dt = dt/timesLooped;
for (int i = 0; i < timesLooped; i++){
velout = vel.scale(MULTIPLIER);
dx = (dt*velout.getX());
dy = (dt*velout.getY());
loc = new Point2D(loc.getX()+dx, loc.getY()+dy);
a = Math.atan2(loc.getX()-parentBody.getX(), loc.getY()-parentBody.getY());
a = Math.toRadians(90)-a;
forcedub = ((gravConstanat*parentBody.getMass())/Math.pow(loc.distance(parentBody.getLoc()),2));
force = new Point2D(((-1)*forcedub*Math.cos(a)),((-1)*forcedub*Math.sin(a)));
force = force.scale(MULTIPLIER*MULTIPLIER);
velout = velout.plus(new Point2D(force.getX()*dt,force.getY()*dt));
vel = velout.scale(1/MULTIPLIER);
}
}
public void bake(){
double velSq = Math.pow(vel.distance(0,0),2);
double r = loc.distance(parentBody.getLoc());
double gm = gravConstanat*parentBody.getMass();
Point2D posr = new Point2D(loc.getX()-parentBody.getX(), loc.getY()-parentBody.getY());
Point2D calc1 = posr.scale((velSq/gm));
Point2D calc2 = vel.scale((dotProd(posr,vel)/gm));
Point2D calc3 = posr.scale(1/r);
Point2D eccVecc = (calc1.minus(calc2)).minus(calc3);
ecc = eccVecc.distance(0,0);
w = Math.toRadians(90)-(Math.atan2(eccVecc.x(),eccVecc.y()));
semiA = (gm*r)/(2*gm - r*velSq);
semiB = semiA*(Math.sqrt((1-Math.pow(ecc,2))));
focus = findFocus(semiA,semiB);
System.out.println("ecc " + ecc + " W " + w + " SEMI A " + semiA);
System.out.println();
}
public double findFocus(double a, double b){
return Math.sqrt(a*a - b*b);
}
public double getX(){
return loc.getX();
}
public double getY(){
return loc.getY();
}
public void setRotateRate(double rr){rotateRate = rr;}
public String getName(){
return name;
}
public Sprite getSprite(){
return sprite;
}
public void setMultiplier(double mult){
MULTIPLIER = mult;
}
public Point2D getLoc(){
return loc;
}
public void setLoc(Point2D newLoc){
loc = newLoc;
}
public double dotProd(Point2D a, Point2D b){
return a.x()*b.x() + a.y()+b.y();
}
}
when shooting (slow) bullets in my Java game, they move at incorrect angles, however when sped up they become more and more accurate.
My x, y, speed and directions are all int, however I've tried converting to floats for more accuracy but I'm still having the same error. I believe it's happening because the lowest movement steps I can have are in integers like (+2x and +1y a step and not +1.7x and +0.88y - and I can't be on 0.5 of a pixel)
How do I 'microstep' the bullets to shoot them on the correct angle?
The only other solution I can think of to shoot them at the correct angle is to calculate the end collision point and step towards that point.
Desired behavior is for bullets to shoot at the correct angle (player to mouse) rather then at 'off' angles based on the bullets speed.
public class Bullet extends GameObject
{
private int x;
private int y;
private int speed = 2;
private int direction;
private int length = 70;
public Bullet(int x, int y, int direction)
{
this.x = x;
this.y = y;
this.direction = direction; //Set the direction.
}
public void update(Game game, GameController gc, float dt)
{
x += GameController.lengthdir_x(speed, direction);
y += GameController.lengthdir_y(speed, direction);
}
public void render(Game game, Renderer r)
{
//Draw the bullet with the tail behind it.
r.drawLine(x, y, x + GameController.lengthdir_x(length, direction - 180), y + GameController.lengthdir_y(length, direction - 180), color);
r.drawText("Dir: " + direction, x + 50, y + 20, 0xff0077ff); //Draws the players angle.
}
}
Lengthdir Code: (The angle calculates correctly as I can draw a line between two points perfectly, just when I add movement it messes up)
public static int lengthdir_x(int len, int dir)
{
return (int) (len * Math.cos(Math.toRadians(dir - 90)));
}
public static int lengthdir_y(int len, int dir)
{
return (int) (len * Math.sin(Math.toRadians(dir - 90)));
}
I've also tried doubles for variables: https://pastebin.com/fbrF17bD
Example: http://puu.sh/x9OnN/be4e3f2c80.png
The long blue line is from the player to the mouse, the yellow lines are bullets which are at the correct angle it was shot at - but not travelling the correct direction which should be exactly on the blue line. This was at a bullet speed of 2 - if the bullets are at a speed of 20, they are much closer to the blue line as per the next img: http://puu.sh/x9OwY/a54f201c91.png
I got your Problem: you use Integer-cast on the calculation result, that means you just remove everything after ., so if you get 1.9 as result you will return 1 as length. If you increase speed this error will be reduced, thats why you get better result for higher speed. You need to round your result before you return it. On the other hand you should really change to double. In the code you shown where you use double you didn't changed it in length-function, thats why you don't get better result using double. So your code should look like this:
public static double lengthdir_x(int len, int dir)
{
//don't cast here to int!!!!
return len * Math.cos(Math.toRadians(dir - 90));
}
public class Bullet extends GameObject
{
private double x;
private double y;
private int speed = 2;
private int direction;
private int length = 70;
public Bullet(double x, double y, int direction)
{
this.x = x;
this.y = y;
this.direction = direction; //Set the direction.
}
public void update(Game game, GameController gc, float dt)
{
x += GameController.lengthdir_x(speed, direction);
y += GameController.lengthdir_y(speed, direction);
}
public void render(Game game, Renderer r)
{
//Draw the bullet with the tail behind it.
r.drawLine((int)Math.round(x), (int)Math.round(y), x + GameController.lengthdir_x(length, direction - 180), y + GameController.lengthdir_y(length, direction - 180), color);
r.drawText("Dir: " + direction, (int)x + 50, (int)y + 20, 0xff0077ff); //Draws the players angle.
}
}
Maybe you will need to convert something to int or double somewhere, but make sure lengthdir returns double as result or at least (int)Math.round(...)
I am making a game which needs an "arrow" to be shot from a stationary location (a set coordinate). The arrow's trajectory is based on the location that the user Clicks in the GUI. This is essentially an Aiming feature. I cant get the arrow to follow a working path, any equations ie used have led to weird, glitchy, and buggy results.
public class ReShoot implements ActionListener
{
public void actionPerformed(ActionEvent e){
ArrowShoot shoot = new ArrowShoot();
shoot.ReShoot();
}
}
public class ArrowShoot implements ActionListener
{
public Timer T = new Timer(5, this);
Arrow A = new Arrow();
public void ReShoot(){
T.start();
arrow_x=0;
arrow_y=200;
A.setBounds(0,200,10,10);
}
// MAIN: y=-16t^2 + Vy * t + h
//Vy = v * sin(a)
//Vx = v * cos(a)
//a = arctan( (200-mouse_y)/v
//v = Mouse_x - Arrow_x
//t = x / Vx
public void actionPerformed(ActionEvent e)
{//arrow_y = 0.0025 * Math.pow((mouse_x-arrow_x), 2)+ mouse_y;
Container container_arrow = getContentPane();
container_arrow.setLayout(null);
container_arrow.add(A);
A.setBounds(0,200,10,10);
arrow_x++;
double v = mouse_x/2; //height change
double a = 50* Math.atan((200-mouse_y) / (v));
double Vy = v * Math.sin(a);
double Vx = v * Math.cos(a);
double t = arrow_x/Vx;
double h = 200;
arrow_y = (16) * Math.pow(t, 2) + (Vy * t) + h;
int x = (int)Math.round(arrow_x);
int y = (int)Math.round(arrow_y);
A.setBounds(x, y,10,10);
if (arrow_y>=500)
T.stop();
}
I am pretty sure im doing this all wrong, and there has to be a more effective method to accomplish this task.
It doesn't look like you are calculating the trajectory path correctly. In actionPerformed, you are incrementing the x coordinate of the arrow, and then calculating the corresponding y. This will not work at all, since even though you can calculate y as a function of x, x is itself a function of t (time). Hence you have to calculate x at time t instead of assuming that x will always increase by 1 at the next invocation.
Given that you can calculate the angle, you can calculate the position of x and y as a function of time and the angle using the following formulas:
So your algorithm will essentially be:
time++; //time variable that you maintain
arrow_x = ... //calculate using (1)
arrow_y = ... //calculate using (2)
I am working on a game (just for my own fun) in Processing (a variant of Java), and have run into a problem. I have a projectile class that is created and managed by a Castle class, and it goes towards an Enemy class (which is a moving target). What I am trying to do (conceptually) is make this projectile find its intended target (Euclidian distance), say its 20 units away, and move 5 units along that line (i.e. 1/4 of the way there). My problem is that I don't know how to extract the x and y components of that vector to update this projectile's position. Here is my projectile class currently:
class Projectile{
private PImage sprite;
private Enemy target;
private int x;
private int y;
private int speed;
public Projectile(PImage s, Enemy t, int startx, int starty, int sp) throws NullPointerException{
if(t == null){
if(debug){
println("Null target given to Projectile(), throwing exception");
}
throw new java.lang.NullPointerException("The target of the projectile is null");
}
sprite = s;
target = t;
x = startx;
y = starty;
speed = sp;
if(debug){
println("Projectile created: " + t + " starting at position: " + startx + " " + starty);
}
}
public void update(){
if(target != null){
int goingToX = target.getCenterX() ;
int goingToY = target.getCenterY();
//find the total distance to the target
float d = dist(this.x, this.y, target.getCenterX(), target.getCenterY());
//divide it by the velocity vector
d /= speed;
//get the dx and dy components of the vector
}else{//target is null, i.e. already destroyed by something else
//destroy this projectile
//if the higher functions were correct, then nothing needs to go here
//this should be deleted as long as it checks for this.hitTarget()
return;
}
}
public void render(){
image(sprite, x, y, 10, 10);
}
//checks if it hit the target, but does a little bit of rounding because the sprite is big
//done this way in the interest of realism
public boolean hitTarget(){
if(target != null){
if(abs(x - target.getCenterX()) <= 5 && abs(y - target.getCenterY()) <= 5 ){
return true;
}else{
return false;
}
}
//this activates if the target is null, which marks this for deletion
return true;
}
}
I've been researching this for hours and realized my approach was unnecessarily complicated when I was looking into converting floats into strings, formatting them to some number of decimal places, then trying to convert that into a fraction which I would then reduce. I feel like this is far easier than I realize, but I am lacking the math background to do it. All necessary changes should only need to be done in Projectile.update(). Thanks!
Assuming that you want your projectile to 'track' the target, then you can use a simple bit of trig to work out the relative speeds in x and y:
//Calculate the differences in position
float diffX = target.getCenterX() - this.x;
float diffY = target.getCenterY() - this.y;
//Calculate the angle
double angle = Math.atan2(diffY, diffX);
//Update the positions
x += Math.cos(angle) * speed;
y += Math.sin(angle) * speed;
This essentially calculates the angle between the projectile and the target, then moves the projectile in that direction, based on the speed given.
I've read the article from here.
But it seems i can't translate that to Java, and by that I mean this:
double t = 0.0;
const double dt = 0.01;
double currentTime = hires_time_in_seconds();
double accumulator = 0.0;
State previous;
State current;
while ( !quit )
{
double newTime = time();
double frameTime = newTime - currentTime;
if ( frameTime > 0.25 )
frameTime = 0.25; // note: max frame time to avoid spiral of death
currentTime = newTime;
accumulator += frameTime;
while ( accumulator >= dt )
{
previousState = currentState;
integrate( currentState, t, dt );
t += dt;
accumulator -= dt;
}
const double alpha = accumulator / dt;
State state = currentState*alpha + previousState * ( 1.0 - alpha );
render( state );
}
What is the State class he is using? I've downloaded the code and i couldn't find it's declaration? How would the code look like in Java?
State is more an abstract idea. He's just interpolating a number. For example, state could be the x position of an entity.
An example for you:
float x = x*alpha+oldX*(1-alpha);
In my physics game, I passed the alpha value to all my entities during each render. They would use this during the render to calculate the best approximation of their position. I would suggest you do the same. Just have your render routines accept alpha, and have each object track its old state.
So every entity guesses where it really is at the time of rendering using its last position and its current position.
EDIT:
public class Entity{
double oldX;
double oldY;
double x;
double y;
public void render(Graphics g, float alpha){
float estimatedX = x*alpha+oldX*(1-alpha);
float estimatedY = y*alpha+oldY*(1-alpha);
g.drawRect((int)estimatedX,(int)estimatedY,1,1);
}
}
It's a simple structure containing the current position and velocity before each integration step. It's defined in the previous tutorial, and also near the beginning of Timestep.cpp in the code you can download from that page:
struct State
{
float x; // position
float v; // velocity
};