I have the following methods in my program which keep a ball continuously bouncing. I have tried modifying but can't seem to get the ball to stop at the bottom of my GUI. My main goal is to have the methods simulate as if you were bouncing a real ball.
private void updateDelta() {
final int minimumMovement = 5;
final int maxExtra = 10;
deltaY = minimumMovement + (int) (Math.random() * maxExtra);
}
public void verticalBounce(Container container) {
// controls vertical ball motion
if (upDown) {
y += deltaY;
if (y >= getHeight()) {
upDown = false;
updateDelta();
}
} else {
y += -deltaY;
if (y <= 0) {
upDown = true;
updateDelta();
}
}
}
UPDATE:
Ball bounces and stops at the bottom of the gui.
public void verticalBounce(Container container) {
deltaY = deltaY - gravity;
y = y + deltaY;
if (y > getHeight()) {
y = getHeight(); // reset location
deltaY = (int) (deltaY * -0.9); // slows down ball
}
}
None of that code looks correct. You need to implement the equation(s) of rectilinear motion:
http://en.wikipedia.org/wiki/Linear_motion
The one you need is s = ut + 0.5 * a * t * t, where
s = distance
u = an initial velocity - regard as the speed at which it hits the ground
a = acceleration due to gravity (you can probably have this pretty arbitrary)
t = time
You reverse the sign of a on the way up.
To simulate lossy bouncing, reduce u by taking a certain factor of energy E out of the system:
new_u * new_u = (1 - E)u * u.
(This comes from the formula for the kinetic energy of a moving body).
I can see from your question that you are capable of implementing this, so I won't provide code; just the physics.
First, a bouncing ball doesn't have a random element in it. Its all determined by the forces acting on the ball and the speed and direction of the ball. If you add a little randomness, it may make it look a little more realistic because of things like wind and unbalance in the ball but its very little.
To program it, assume the ball gets shot up from the ground at some speed. You need to store:
Y = location in units above the ground. Start at 0.
deltaY = speed in units per time interval. Negative is down. Positive is up. Start at 10.
gravity = acceleration in units of change per time interval. Gravity is always negative and constant. Start with -2 and try some values.
Unless you want the ball to disappear off the screen as it reaches the top of the bounce, you will need to select a ceiling height. Say 100. (Which is best chosen to match your graphics area's height, though.)
So for every time interval/tick/loop you do the following:
Adjust for gravity by subtracting gravity from deltaY. (If the ball is moving down it will move faster. If its moving up, it will move slower.)
Move the ball by adding deltaY to Y.
Then you have to check: Did the ball hit the ground or the ceiling? Is Y greater than the ceiling value or less than the ground one (0).
If so, you have to bounce it by:
Move Y such that if it was X past the boundary (ground/ceiling) it becomes X within the boundary. (If Y = 110 and ceiling = 100, set Y to 90. If Y = -5, set it to +5.)
Negate deltaY. In a bounce the direction reverses. (deltaY = -deltaY)
Reduce deltaY by a percentage. Some energy is lost in the bounce so speed is slower after a bounce. (deltaY = deltaY * 0.90 or some other amount) #Bathsheba calls that removing energy from the system.
That's all there is to it. You have to fiddle with the numbers to make it take off at a reasonable speed. You have to adjust the time interval. You don't have to match real life. Just do what looks good.
As time goes by, the speed will reduce to 0.
(And despite what I said before, adding or subtracting a small random amount actually looks kind of cool.)
Your ball is bouncing randomly instead of slowly decreasing in velocity. You need to lower your velocity every bounce until the velocity is under minimumMovement then make the velocity 0 and stop bouncing.
Related
I am trying to shoot an object(a spell) depending on the rotation of the players arm. The spell is supposed to come out of the hand and shoot towards where the mouse cicked(the arm rotates and points to where the mouse is). This is how the arm rotates in game.
public boolean mouseMoved(int screenX, int screenY) {
tmp.x = screenX;
tmp.y = screenY;
tmp.z = 0;
cam.unproject(tmp);
rot = MathUtils.radiansToDegrees * MathUtils.atan2((float)tmp.y - (float)player.getArmSprite().getY() - player.getArmSprite().getHeight(),
tmp.x -player.getArmSprite().getX() - player.getArmSprite().getWidth());
if (rot < 0) rot += 360;
//Last right or left means if hes looking left or right
if(player.lastRight)
player.setObjectRotation(rot + 80);
if(player.lastLeft)
player.setObjectRotation(-rot - 80);
And this is how the spell is supposed to shoot based off rotation
//destination is a vector of where on screen the mouse was clicked
if(position.y < destination.y){
position.y += vel.y * Gdx.graphics.getDeltaTime();
}
if(position.x < destination.x){
position.x += vel.x * Gdx.graphics.getDeltaTime();
}
However this is very wonky and never really reacts the way it supposed to with a few exceptions. It fires from the hand and then if the y axis is equal it completely evens out and goes till it reaches the x position, I want it to fire from the hand to the position clicks perfectly straight from point a to point b, this is clearly a rotation problem that I just can't seem to figure out how to tackle.
Here is an image of what is happening
Example image
The red indicates where I clicked, as you can see it reached the x pos first and now is traveling to the y when it should have reached the x and y pos of where I clicked first
Any help with this problem is extremely appreciated!
I'm pretty bad at radians and tangents but luckily we have vectors.
Since you have the rot ation in degrees of the arm. I advice to use Vectors to use for any Vector related math now.
//A vector pointing up
Vector2 direction = new Vector2(0, 1);
//Let's rotate that by the rotation of the arm
direction.rotate(rot);
Now direction is the direction the arm is pointing. If your rotation is calculated where up = 0. So you might need to rotate it 180, 90 or -90 degrees. Or in the case you did something silly any degrees.
Your spell should have a Vector too for it's position. Set that to the hand or wherever you want to start from. Now all you need to do is scale that direction since it's currently has a length of 1. If you want to move 5 units each frame you can do direction.scl(5) now it is of length 5. But technically speaking it's no direction anymore now everybody calls it velocity so let's do.
//when you need to fire
float speed = 5;
Vector2 velocity = direction.cpy().scl(speed);
//update
position.add(velocity);
draw(fireballImage, position.x, position.y);
I copied direction first, otherwise it would also be scaled. Then I just added the velocity to the position and draw using that Vector.
And to show Vectors are awesome you should see this awesome badlogic vs mouse program I created. https://github.com/madmenyo/FollowMouse there are just a view lines of my own code. It just takes a little bit of vector knowledge and it's very readable.
I'm trying to write a java mobile application (J2ME) and I got stuck with a problem: in my project there are moving circles called shots, and non moving circles called orbs. When a shot hits an orb, it should bounce off by classical physical laws. However I couldn't find any algorithm of this sort.
The movement of a shot is described by velocity on axis x and y (pixels/update). all the information about the circles is known: their location, radius and the speed (on axis x and y) of the shot.
Note: the orb does not start moving after the collision, it stays at its place. The collision is an elastic collision between the two while the orb remains static
here is the collision solution method in class Shot:
public void collision(Orb o)
{
//the orb's center point
Point oc=new Point(o.getTopLeft().x+o.getWidth()/2,o.getTopLeft().y+o.getWidth()/2);
//the shot's center point
Point sc=new Point(topLeft.x+width/2,topLeft.y+width/2);
//variables vx and vy are the shot's velocity on axis x and y
if(oc.x==sc.x)
{
vy=-vy;
return ;
}
if(oc.y==sc.y)
{
vx=-vx;
return ;
}
// o.getWidth() returns the orb's width, width is the shot's width
double angle=0; //here should be some sort of calculation of the shot's angle
setAngle(angle);
}
public void setAngle(double angle)
{
double v=Math.sqrt(vx*vx+vy*vy);
vx=Math.cos(Math.toRadians(angle))*v;
vy=-Math.sin(Math.toRadians(angle))*v;
}
thanks in advance for all helpers
At the point of collision, momentum, angular momentum and energy are preserved. Set m1, m2 the masses of the disks, p1=(p1x,p1y), p2=(p2x,p2y) the positions of the centers of the disks at collition time, u1, u2 the velocities before and v1,v2 the velocities after collision. Then the conservation laws demand that
0 = m1*(u1-v1)+m2*(u2-v2)
0 = m1*cross(p1,u1-v1)+m2*cross(p2,u2-v2)
0 = m1*dot(u1-v1,u1+v1)+m2*dot(u2-v2,u2+v2)
Eliminate u2-v2 using the first equation
0 = m1*cross(p1-p2,u1-v1)
0 = m1*dot(u1-v1,u1+v1-u2-v2)
The first tells us that (u1-v1) and thus (u2-v2) is a multiple of (p1-p2), the impulse exchange is in the normal or radial direction, no tangential interaction. Conservation of impulse and energy now leads to a interaction constant a so that
u1-v1 = m2*a*(p1-p2)
u2-v2 = m1*a*(p2-p1)
0 = dot(m2*a*(p1-p2), 2*u1-m2*a*(p1-p2)-2*u2+m1*a*(p2-p1))
resulting in a condition for the non-zero interaction term a
2 * dot(p1-p2, u1-u2) = (m1+m2) * dot(p1-p2,p1-p2) * a
which can now be solved using the fraction
b = dot(p1-p2, u1-u2) / dot(p1-p2, p1-p2)
as
a = 2/(m1+m2) * b
v1 = u1 - 2 * m2/(m1+m2) * b * (p1-p2)
v2 = u2 - 2 * m1/(m1+m2) * b * (p2-p1)
To get the second disk stationary, set u2=0 and its mass m2 to be very large or infinite, then the second formula says v2=u2=0 and the first
v1 = u1 - 2 * dot(p1-p2, u1) / dot(p1-p2, p1-p2) * (p1-p2)
that is, v1 is the reflection of u1 on the plane that has (p1-p2) as its normal. Note that the point of collision is characterized by norm(p1-p2)=r1+r2 or
dot(p1-p2, p1-p2) = (r1+r2)^2
so that the denominator is already known from collision detection.
Per your code, oc{x,y} contains the center of the fixed disk or orb, sc{x,y} the center and {vx,vy} the velocity of the moving disk.
Compute dc={sc.x-oc.x, sc.y-oc.y} and dist2=dc.x*dc.x+dc.y*dc.y
1.a Check that sqrt(dist2) is sufficiently close to sc.radius+oc.radius. Common lore says that comparing the squares is more efficient. Fine-tune the location of the intersection point if dist2 is too small.
Compute dot = dc.x*vx+dcy*vy and dot = dot/dist2
Update vx = vx - 2*dot*dc.x, vy = vy - 2*dot*dc.y
The special cases are contained inside these formulas, e.g., for dc.y==0, that is, oc.y==sc.y one gets dot=vx/dc.x, so that vx=-vx, vy=vy results.
Considering that one circle is static I would say that including energy and momentum is redundant. The system's momentum will be preserved as long as the moving ball contains the same speed before and after the collision. Thus the only thing you need to change is the angle at which the ball is moving.
I know there's a lot of opinions against using trigonometric functions if you can solve the issue using vector math. However, once you know the contact point between the two circles, the trigonometric way of dealing with the issue is this simple:
dx = -dx; //Reverse direction
dy = -dy;
double speed = Math.sqrt(dx*dx + dy*dy);
double currentAngle = Math.atan2(dy, dx);
//The angle between the ball's center and the orbs center
double reflectionAngle = Math.atan2(oc.y - sc.y, oc.x - sc.x);
//The outcome of this "static" collision is just a angular reflection with preserved speed
double newAngle = 2*reflectionAngle - currentAngle;
dx = speed * Math.cos(newAngle); //Setting new velocity
dy = speed * Math.sin(newAngle);
Using the orb's coordinates in the calculation is an approximation that gains accuracy the closer your shot is to the actual impact point in time when this method is executed. Thus you might want to do one of the following:
Replace the orb's coordinates by the actual point of impact (a tad more accurate)
Replace the shot's coordinates by the position it has exactly when the impact will/did occur. This is the best scenario in respect to the outcome angle, however may lead to slight positional displacements compared to a fully realistic scenario.
I'm trying to create a simple Android game, a 2D action shooter which has 2 control sticks (circles) on the screen, the left one is movement control and the right one weapon control. Direction is being controlled by the position of your thumb relative to the circle’s center.
I've been following a tutorial on this site: http://www.kilobolt.com/day-7-creating-an-android-game-from-start-to-finish.html but it only gave me the base to work on. I have no programming experience so I'm quite lost now.
I got the movement working only on TOUCH_DOWN event, the hero moves to about where it should but to change direction I have to lift my thumb and touch the circle again. TOUCH_DRAGGED (or ACTION_MOVE) is broken because if I drag my finger across the circle the character moves really fast. I guess the problem is too many touch events are being handled, but I have no idea how to fix it.
How can I change this so that I can drag my thumb around the circle and the hero will change its direction instantly, and keep its speed constant all the time? Also the speed should be the same no matter how close or far from the center of the circle you touch.
private void updateRunning(List<TouchEvent> touchEvents, float deltaTime) {
int len = touchEvents.size();
for (int i = 0; i < len; i++) {
TouchEvent event = touchEvents.get(i);
if (event.type == TouchEvent.TOUCH_DOWN || event.type == TouchEvent.TOUCH_DRAGGED) {
if (inBounds(event, 50, 300, 150, 150, 'c')) {
ctrl.setX(event.x);
ctrl.setY(event.y);
ctrl.direction();
hero.move(ctrl.getDirX(), ctrl.getDirY());
}
}
if (event.type == TouchEvent.TOUCH_UP) {
if (inBounds(event, 0, 0, 35, 35,'r')) {
pause();
}
hero.stopMove();
}
}
hero.update();
The movement: hero's speedX and speedY are added to hero's centerX and centerY on every hero.update() call.
public void move(float x, float y) {
speedX += x * MOVESPEED;
speedY += y * MOVESPEED;
}
This method that handles the x & y speed. Found it here at stackoverflow, and because touch_down event is working ok, I guess it's doing it's job. Although I feel it's not exactly how it's supposed to be. L_STICK_C is a constant with values of 100 and 350 (center of the circle).
public void direction() {
dir.x = x - L_STICK_C.x;
dir.y = y - L_STICK_C.y;
double hyp = Math.sqrt(dir.x * dir.x + dir.y * dir.y);
dir.x = (float) (dir.x / hyp);
dir.y = (float) (dir.y / hyp);
}
I suggest you look into some game programming tutorials. You usually would not move the character directly from the touch input. You'd set a game state variable once a game loop which would correspond to the position of your thumb inputs. Then you'd only update the hero once per game loop based on those inputs. This lets allows you to keep the game input control code, and hero code separate, and makes it re-usable for other parts of your game.
EDIT:
Based on your code, every time you drag your finger, you generate a bunch of dragged events. So you are adding onto your characters speed for each event. You should probably just be looking at the distance to center and x / y of the input on the last touch event, not all of them.
I'm making pretty simple game. You have a sprite onscreen with a gun, and he shoots a bullet in the direction the mouse is pointing. The method I'm using to do this is to find the X to Y ratio based on 2 points (the center of the sprite, and the mouse position). The X to Y ratio is essentially "for every time the X changes by 1, the Y changes by __".
This is my method so far:
public static Vector2f getSimplifiedSlope(Vector2f v1, Vector2f v2) {
float x = v2.x - v1.x;
float y = v2.y - v1.y;
// find the reciprocal of X
float invert = 1.0f / x;
x *= invert;
y *= invert;
return new Vector2f(x, y);
}
This Vector2f is then passed to the bullet, which moves that amount each frame.
But it isn't working. When my mouse is directly above or below the sprite, the bullets move very fast. When the mouse is to the right of the sprite, they move very slow. And if the mouse is on the left side, the bullets shoot out the right side all the same.
When I remove the invert variable from the mix, it seems to work fine. So here are my 2 questions:
Am I way off-track, and there's a simpler, cleaner, more widely used, etc. way to do this?
If I'm on the right track, how do I "normalize" the vector so that it stays the same regardless of how far away the mouse is from the sprite?
Thanks in advance.
Use vectors to your advantage. I don't know if Java's Vector2f class has this method, but here's how I'd do it:
return (v2 - v1).normalize(); // `v2` is obj pos and `v1` is the mouse pos
To normalize a vector, just divide it (i.e. each component) by the magnitude of the entire vector:
Vector2f result = new Vector2f(v2.x - v1.x, v2.y - v1.y);
float length = sqrt(result.x^2 + result.y^2);
return new Vector2f(result.x / length, result.y / length);
The result is unit vector (its magnitude is 1). So to adjust the speed, just scale the vector.
Yes for both questions:
to find what you call ratio you can use the arctan function which will provide the angle of of the vector which goes from first object to second object
to normalize it, since now you are starting from an angle you don't need to do anything: you can directly use polar coordinates
Code is rather simple:
float magnitude = 3.0; // your max speed
float angle = Math.atan2(y,x);
Vector2D vector = new Vector(magnitude*sin(angle), magnitude*cos(angle));
I am new to programming, and I am trying to make a 2d applet that will move a circle or ball away from the mouse. The way I want the physics in this program to work is to make the object act like a ball, and the mouse like a movable hill. When the mouse get closer to the ball, it repels the ball faster and farther away, and when the mouse gets farther away from the ball, the ball slows down and eventually stops moving. I need to take into account both the total distance between the mouse and the object, and the x and y distance so the movement of the object is smooth and more realistic. The biggest problem that I have is that even as the distance between the two points become greater, the rate at which the ball moves away stays relatively constant. Currently the rate is the distance of x or y multiplied by a constant, and divided by the total distance. This more or less works when the mouse moves closer to the object, and the rate increases as it should, but it fails when the mouse moves away. I want the rate to decrease and eventually become 0 when the mouse moves away, but in my current set up the x distance will also increase as the distance increases, and the rate will not decrease as much as I want it to, if at all. The way I have it now probably needs to be scraped all together, and thanks for the help.
public void mouseMoved (MouseEvent e)
{
//distance between x coord
xd=e.getX()-x;
//distance between y coord
yd=y-e.getY();
//total distance between mouse and ball
d=Math.sqrt((Math.pow(xd,2))+(Math.pow(yd,2)));
//rate of x change
xrate=(Math.sqrt(Math.pow(xd,2))*4)/(d);
//rate of y change
yrate=(Math.sqrt(Math.pow(yd,2))*4)/(d);
//determines movement of ball based on position of the mouse relative to the ball
if(xd>0)
{
x=x-((int)(xrate));
}
if(xd<0)
{
x=x+((int)(xrate));
}
if(yd>0)
{
y=y+((int)(yrate));
}
if(yd<0)
{
y=y-((int)(yrate));
}
//updates x and y coords of ball
repaint();
}
try this-
//rate of x change
xrate=(1.0/(d))*20; //20 is just a random constant I guessed
//rate of y change
yrate=(1.0/(d))*20;
You just did wrong math.
//total distance between mouse and ball
d=Math.sqrt((Math.pow(xd,2))+(Math.pow(yd,2)));
//rate of x change
xrate=(Math.sqrt(Math.pow(xd,2))*4)/(d);
Think about this :
If you only move on the x cord, will simply make yd equals 0 and d=|xd|
So xrate = |xd|*4/(d) = d*4/d = 4.
There is a easy way to accomplish your task, just make xrate and yrate related with xd and yd.
You can try this :
if(xd==0){
xd = 0.1;//minimum distance
}
if(yd==0){
yd = 0.1;
}
xrate = (1/xd)*10; // you can change number 100 for proper speed
yrate = (1/yd)*10;
x = x - xrate;
y = y - yrate;
Hope this can help.