I currently have an array of points (x,y) from the result of an A* pathfinding function. This array is set up so that the first index is the point closest to the character and the next one is the next point that needs to be traveled in the path.
These points are on a grid (currently 8 pixels between each point on the grid, this is changable.)
My current strategy is to move the character to the first point, when he has arrived at that point, then move to the next one, simple as that.
I move to the first point by creating a vector from the character to that point and find how far it is. Then I find the angle and move in that direction.
// How the character is moved
double xMove = Math.cos(charAngle * (Math.PI / 180)) * 0.1 * delta;
double yMove = Math.sin(charAngle * (Math.PI / 180)) * 0.1 * delta;
x += xMove;
y += yMove;
absVx -= Math.abs(xMove);
absVy -= Math.abs(yMove);
absVX and absVy store the absolute distance left to go and it is decremented after each movement. If they are both below or equal to zero, then we have reached our destination, we remove it from the array and recalculate everything again with the next point.
I have two issues.
Sometimes the character skips over a point and then he just travels forever. This is most likely due to the delta the game engine adds to the movement (slick) and the character moves too far, I'm not sure on this one though.
This works fine when I single click the destination but what I need is to be able to hold down the mouse button. Currently the character just "stands still" on the first point if I hold the mouse down.
I had an idea for a solution to the 2nd problem but I'm not sure it's a good one. It is to store the location you want to go from the last mouse click but not actually calculate it untill you have passed the point you were moving to.
So, I hope someone really smart and fun can have a little conversation with me about this :D
About 1, the most probably cause is a rounding issue; adding these xMove / yMove introduce an small error and the x and y never really get the value of the destination, so the algorithm keeps running.
Ways to solve:
1 Define "reaching destination" so it allows a degree of error
2 Find out how many "ticks" will take to the character to arrive to destination, when it "arrives", force the character position to its destination (this allows to correct accumulated error).
Also, I would go back to graphics theory. IIRC, your path moving between points should be equal to Bresenham's line drawing algorithm. For later stages, your character could follow a B-Spline along his path.
Related
I have a source component and a target component and I want to calculate the corner point where they will be connected. I am implementing a method that takes the source and target points and their orientations (either horizontal or vertical) as inputs. Here is the skeleton of the method:
private final static int HORIZONTAL = 0;
private final static int VERTICAL = 1;
private PointF computeCornerPoint(PointF sourcePoint, int sourceComponentOrientation, PointF targetPoint, int targetComponentOrientation) {
PointF cornerPoint = new PointF();
// TODO: Calculate the corner point here
return cornerPoint;
}
I have created a diagram that shows all the possible cases. In the diagram, the green points are the source and target points, and the red point is the corner point that I want to compute.
Also, note that this problem is symmetric, so the source and target components can be swapped, and the diagram I provided only shows one case.
In Android, the x-coordinate increases from left to right, and the y-coordinate increases from top to bottom.
Can you suggest an algorithm or a solution to compute the corner point for all these cases?
Additionally, please let me know if there is any information missing that would be helpful in solving this problem.
Horizontal/vertical isn’t enough – we need to know which side of the
component the connection point is on. Also I’m not sure how you want to
handle connection points on opposite sides.
For the cases you’ve shown, the answer will be either (source.x,
target.y) or (target.x, source.y). If (for example) the source point is
on the right side of its component, then (target.x, source.y) is vetoed
if target.x < source.x or preferred if source.x < target.x; (source.x,
target.y) is a middling option. The other seven cases (three source
directions and four target directions) are symmetric. We demand an
option that is not vetoed, and should choose one that is preferred if
possible.
Let’s assume that (source.dx, source.dy) and (target.dx, target.dy) give
the coordinates of their respective connection points relative to the
center of the component (so using the usual mathematical coordinate
system with positive dx pointing right and positive dy pointing up, (dx,
dy) = (1, 0) is right, and (dx, dy) = (0, 1) is up, etc.). The generic
condition for a component is, a point (x′, y′) is
vetoed/preferred/middling if component.dx * (x′ - component.x) +
component.dy * (y′ - component.y) is less than/greater than/equal to
zero respectively. If we let “vetoed” be -2 points, preferred be 1
point, and middling be 0 points, we can add up the scores for both
candidate points and take the max.
I'm making a billiards game in Java. I used this guide for collision resolution. During testing, I noticed that there is more velocity between the two collided pool balls after collision. The amount of extra velocity seems to be 0%-50%. About 0% on a straight shot and 50% on an extremely wide shot. I assumed that the combined velocities would remain the same. Is it my code or my understanding of physics that is wrong?
private void solveCollision(PoolBall b1, PoolBall b2) {
System.out.println(b1.getMagnitude() + b2.getMagnitude());
// vector tangent to collision point
float vTangX = b2.getY() - b1.getY();
float vTangY = -(b2.getX() - b1.getX());
// normalize tangent vector
float mag = (float) (Math.sqrt((vTangX * vTangX) + (vTangY * vTangY)));
vTangX /= mag;
vTangY /= mag;
// get new vector based on velocity of circle being collided with
float NVX1 = b1.getVector().get(0) - b2.getVector().get(0);
float NVY1 = b1.getVector().get(1) - b2.getVector().get(1);
// dot product
float dot = (NVX1 * vTangX) + (NVY1 * vTangY);
// adjust length of tangent vector
vTangX *= dot;
vTangY *= dot;
// velocity component perpendicular to tangent
float vPerpX = NVX1 - vTangX;
float vPerpY = NVY1 - vTangY;
// apply vector to pool balls
b1.setVector(b1.getVector().get(0) - vPerpX, b1.getVector().get(1) - vPerpY);
b2.setVector(b2.getVector().get(0) + vPerpX, b2.getVector().get(1) + vPerpY);
System.out.println(b1.getMagnitude() + b2.getMagnitude());
}
Not all of this explanation will be strictly on topic, and I will assume minimal foreknowledge to accommodate potential future users - unfortunately some may consequently find it pedantic.
Velocity is not a conserved quantity and therefore the magnitude-sum of velocities before a collision is not necessarily equal to the magnitude-sum of velocities after.
This is more intuitive for inelastic collisions, particularly when you consider a scenario such as an asteroid colliding with Earth's moon1, where a typical impact velocity is on the order of 10 - 20 kilometers per second. If scalar velocity was conserved in this case - even at a 'wide' impact angle of 45° (the most probable) - the resulting velocity for the moon would be sufficient to eject it from Earth's orbit.
So clearly scalar velocity is not necessarily conserved for an inelastic collision. Elastic collisions are less intuitive.
This - as you've noted - is because there is a scenario where scalar velocity in a perfectly elastic collision is conserved (a straight-on collision), while inelastic collisions never conserve velocity2. This creates an unacceptable incongruence.
To rectify this, we have to treat velocity as a vector instead of a scalar. Consider the simplest elastic collision between two balls: one ball at rest and the second ball striking the first 'straight-on' (impact angle of 90°). The second ball will come to rest and the first will leave the collision with velocity equal to the second's initial velocity. Velocity is conserved - the magnitude-sum of velocities before and after are equal - all is well.
This will not, however, be the case for impact angles other than 90° because the magnitude sum fails to account for vector components canceling out. Say for example you have one ball again at rest and the second ball striking it at 45°. Both balls will then leave the collision at 45° angles from the second ball's initial direction of travel3. The two balls will then also have the same velocity component parallel to the initial direction of motion, and equal but opposite perpendicular velocity components. When you take a vector sum the two perpendicular components will cancel and the sum of the two parallel components will recover the initial velocity vector. However, the magnitude of each ball's resulting velocity vector will be larger than the magnitude of the second ball's initial velocity - because the magnitude is calculated by a sum of squared values and therefore does not account for opposing components.
Of course the best approach is not to look at the velocity but at the momentum - it is the conservation of momentum which governs the behaviors outlined above and in terms of momentum the explanation is very simple: it dictates that in a perfectly elastic collision the velocity of the center of mass must not change.
1 The bigger one - since Earth recently captured a second true satellite.
2 This is, in fact, part of the definition of an inelastic collision.
3 For additional background on calculating angles of departure see here.
What I am trying to convey in the title, is that there is a player on the screen and, using the direction variable and trigonometry, he is "looking" in a direction. I need to spawn an object right in front of him. And by spawn, I mean create an object with the x and y coordinates matching the location of the spot in "front" of the player.
The code for this is something difficult. I'm unable to understand, without more information or learning more trig, what I need to do to get this to work.
Basically this is what I have, it creates a bullet and another line of code adds it to a list to be drawn to the screen. What I need to know is how to spawn the "bullet" object in the correct x & y coordinates. This is what I have so far. I can assume there is something more I need to add to the x and y variables, but I don't know what that is.
Bullet b = new Bullet((int)x/2+(Math.cos(Math.toRadians(direction))), (int)y/2 + (Math.sin(Math.toRadians(direction))), "/img/bullet.png", direction, weapon);
Create a vector pointing in a direction where you want the object spawned.
x = radius * Math.cos(angle) + startX
y = radius * Math.sin(angle) + startY
Normalize it, and then scale it to your liking.
Here's a simple demo to illustrate.
p.s
radius here is just an initial uniform displacement from the spawn point.
It would help if you understood Proportionality, but it is basically this: if you multiply x and y for the same number, you will get farther away from the current position. Of course that depends on the signals, but the simplest way is this: supposing that x and y are two positive numbers, let's say x=1 and y=1, then, if you multiply both by a positive number, let's say 3, then the final numbers (x=3 and y=3) you will have a "bullet" in the coordinates 3,3 that is right in front of the actor, which is in the position 1,1. Again, I am assuming a lot of things and ignoring a bunch of other ones, such as position of camera, perspective, etc.
For a Java program I'm making I need to interpolate 4 points, to calculate the y-value of a 5th point, at given x-value.
Say I have the following points:
p1(0, 0)
p2(1, 2)
p3(2, 4)
p4(3, 3)
// The x-values will always be 0, 1, 2, and 3
Now I want to interpolate these points to find what the y-value should be for given x, say x=1.2 (this x value will always be between point 2 and point 3)
Can anyone help me to make a Java method for finding the y coordinate of this fifth point?
Generally given two points (x0,y0) and (x1,y1), for x0 < x < x1, by interpolation,
y = y0 + (x - x0)/(x1 - x0) * (y1 - y0)
Here,
y = 2 + (x-1) * 2
There are an infinite number of lines that can go through all four of your points.
For example, you could assume that at each point the slope is zero and then draw simple s shaped curves between them, or you could assume that the slope is calculated from the neighboring points (with some special decisions about the ends), or you could assume that the slope at the points is 2, etc.
And it doesn't stop there, you could effectively draw a curve that will encapsulate your points and any other point you could imagine while still meeting the requirement of being continuous (as you call, smooth).
I think you need to start off with a formula you wish to fit against the points, and then choose the technique you use to minimize the error of the fit. Without you making more decisions, it is very likely that it will be very hard to give more direction.
This question already has an answer here:
How do I work out the future position of a moving object? [closed]
(1 answer)
Closed 10 years ago.
I have asked this question previously and it was closed due to it not being a programming question, this is entirely as I worded it wrong. I would like this to implemented into java. I am creating a little game and I have a photon torpedo which is being fired from a ship towards a target. Now as the speed of the torpedo is slow the ship will never hit any targets if they're moving and I want to fix this. I have drew up multiple theories and mapped out lots of mathematical stuff to find out the best way to accomplish this and in the end I deduced the following:
I find the time it takes for the photon torpedo to get to the target.
I find how far the target will have traveled in the time it takes for the torpedo to arrive.
I then find the distance between the new position of the target and the original ship.
this then gives me the opportunity to use the Cosine rule (SSS) to find out the trajectory at which the bullet needs to be fired to have a much higher chance of hitting.
Here is a digram:
Now the only problem that I need to rotate line a to the correct orientation as by default it's parallel to line c which messes up the entire equation. Can anyone help with this? And also if you can think of a better way to find the new position suggestions are very welcome. My java game entity mechanic works as follows:
Each entity has two Vectors which control movement. Position and Velocity. However, velocity is not tracked entirely properly as instead of it being a speed and a direction, to make things easier it's an xSpeed and a ySpeed.
The entities are all updates once per tick and the ship which shoots the torpedo must calculate the future position in this one tick and not over multiple ticks.
I ask this question not to be closed again, because this time I really need the answer to be implemented into Java.
This is the math i've tried so far:
double dis = level.distanceBetween(photonTargetTop, this);
double speed = 5;
double time = dis / speed;
double d1 = photonTargetTop.velocity.x * time;
double d2 = photonTargetTop.velocity.y * time;
double dis2 = level.distanceBetween(this, photonTargetTop.pos.x + d1, photonTargetTop.pos.y + d2);
double dis3 = level.distanceBetween(photonTargetTop, photonTargetTop.pos.x + d1, photonTargetTop.pos.y + d2);
double cosAngle = Math.pow(dis2, 2) + Math.pow(dis, 2) - Math.pow(dis3, 2) / 2 * dis2 * dis;
double angle = Math.acos(cosAngle);
EntityPhoton p = new EntityPhoton(this, level);
p.rotation = angle;
level.addEntity(p, pos);
Let's assume the target ship has no acceleration, meaning that it's speed and direction is not changing.
Let's also assume that once fired, your torpedo has no acceleration. And it always goes at constant speed.
Let's also call (0,0) the point where your torpedo is fired.
The ship describes a straight line. Choose a point on this line (if the ship is following a course that does not go through (0,0) you can find the closest point to the central position with some geometry that you can look up on wikipedia).
Once you have chosen the position where you want to hit the enemy ship, you know the distance between (0,0) and that position, and given that the speed of the torpedo is always the same, you can also know when to fire the torpedo.
Then you must also find the direction, meaning the values of speed to give on x and y, but that's not so difficult.
In general the problem is a system with multiple solutions, so presuming that the torpedo is faster than the target, there are infinite points where you can hit it, so you must use some heuristic to choose a point that's convenient to you.