I am making a game like pong except that there is only one paddle and the ball moves in projectile motion. The goal is to keep the ball bouncing on your paddle for as long as possible. I when I have the ball hit the paddle the direction of the y component of the velocity has it's sign flipped. The issue with this is that when the ball is moving up gravity acts upon in in that direction, speeding it up. The code is below
This is the code for my ball class, this is the tick method which is called 60 times a second
public Ball(double x, double y, Game game) {
super(x,y);
this.game=game;
}
public void tick() {
time+=1.0/60.0;
if(x<=0)
xreflection=1.0;
else if(x>=Game.Width-15)
xreflection=-1.0;
if(y<=0)
yreflection=1.0;
else if(y>=Game.Height-15)
gameover=1;//different variable here as I use this to end the game if the ball hits the bottom of the screen
x+=traj.xvel()*xreflection;
y-=traj.yvel(time)*yreflection;
if(Physics.Collision(this, game.getP())) {
time=2;
System.out.println("Collision");
yreflection=-1;
}
}
This is my ball Trajectory class which handles all the math for this
public double xvel() {
double xvelo=initvel*Math.cos(Math.toRadians(theta));
return xvelo;
}
public double yvel(double time) {
double yvelo;
yvelo=initvel*Math.sin(Math.toRadians(theta))-(9.8*time);
return yvelo;
}
And I have tried to use an if statement with y reflection to make 9.8 negative when yreflection is 1 and positive when it is -1.
you are not really doing reflection ... to reflect by major axis you should negate the appropriate coordinate of the speed vector (and correct the position) I do not see such behavior in your code. Instead your y velocity has no sign regardless of the direction up/down hence you just add gravity acc to it ... to remedy either rewrite the code or add the yreflection to your gravity related code too... also you got theta? I would expect angle only in the first shooting
see
Bouncing Ball Making it slow down at peak of height
My Algorithm to Calculate Position of Smartphone - GPS and Sensors
pendulum simulation
You just use/add forces you want to use. But in your collision once you detect you are inside wall you need to correct the position along with the reflection of speed too otherwise you risk double collisions ...
Here small C++ example with air friction:
//---------------------------------------------------------------------------
double pos[2],vel[2],acc[2],r; // ball
double x0,y0,x1,y1; // walls
//---------------------------------------------------------------------------
void ball_update(double dt)
{
int i;
double v,k=0.0001,g=9.81;
dt*=10.0; // time multiplier for simulation speed ...
// compute driving force/acceleration
v=sqrt((vel[0]*vel[0])+(vel[1]*vel[1])); // |vel|
acc[0]= -(k*vel[0]*v); // gravity + air friction (k*vel^2)
acc[1]=+g-(k*vel[1]*v);
// Newton/D'Alembert simulation
for (i=0;i<2;i++) vel[i]+=acc[i]*dt;
for (i=0;i<2;i++) pos[i]+=vel[i]*dt;
// colision/reflect
if (pos[0]<x0+r){ pos[0]=x0+r; vel[0]=-vel[0]; }
if (pos[0]>x1-r){ pos[0]=x1-r; vel[0]=-vel[0]; }
if (pos[1]<y0+r){ pos[1]=y0+r; vel[1]=-vel[1]; }
if (pos[1]>y1-r){ pos[1]=y1-r; vel[1]=-vel[1]; }
}
//---------------------------------------------------------------------------
void ball_init()
{
Randomize();
pos[0]=0.5*(x0+x1);
pos[1]=0.5*(y0+y1);
double a=2.0*M_PI*Random(),v=50.0;
vel[0]=v*cos(a);
vel[1]=v*sin(a);
r=20.0;
}
//---------------------------------------------------------------------------
My coordinate system is (0,0) is top left and x point right and y points down ...
To use this just init the walls x0,y0,x1,y1 call the ball_init() and then in some timer call ball_update(dt) and render ball at pos and radius r ...
This is how it look like:
PS. You need to tweak the parameters like delta time dt, accelerations or add pixel scale to match your needs... You need to have all units compatible ... I recommend using SI (m,m/s,m/s^2,s,N,.. ) so you also need to decide how big is pixel (in meters)
Related
I have a sprite that needs to follow the command of an arrow sprite that rotates, right now I can only make my sprite move up,down and left,right. How about diagonally? I have no Idea how to do that, the sprite also needs to move always towards outside the screen.
EDIT:
So this is what I did:
Vector2 position=new Vector2();
public void update(){
//getAngle() is the return value from another class
position.set(MathUtils.cosDeg(cannonObj.getAngle()),MathUtils.sinDeg(cannonObj.getAngle()));
sprite.setPosition(position.x,position.y);
}
What happens is that when I rotate the arrow the main sprite is just moving like the arrow(moving in a circular motion).
//I also tried this
position.scl(2,2);
or
position.translate(2,2);
sprite.x += sin(angle) * amount;
sprite.y += cos(angle) * amount;
I forget whether you have to enter your angle in radians or degrees. In Java you can use the Math class to do the calculations though.
So I can't seem to find an answer to this, but I am trying to fire bullets into a circle. I have a simple class for a circular path that I attach to a bullet and it reads from that class a position when given a time value. The bullet simply increments this time value, constantly updating its position to the next. This can be improved but until I get the logic down this is what I have. I know this method works because I tried it with a linear path. The problem is applying it to a circular path.
I want the bullet to circle around a point (say Point 'Center') with a given radius and speed. I want all bullets to travel at the same speed no matter the radius of the circle so a larger circle will take longer to complete than a shorter one. Currently what is happening is I have the CircularPath object giving saying x = r * cos(t) and y = r * sin (t) where t is in radians, but this is making a circle that increases in speed as the radius increases and the radius and center of this circle is completely off. The bullets are starting in the correct position, except the radius and speeds are off. I hope I am describing this adequately. I will post the code for anyone to inspect.
package io.shparki.tetris.go;
import io.shparki.tetris.util.Point2D;
import java.awt.Color;
import java.awt.Graphics2D;
public class CircularPath extends Path{
private double radius;
// Where Start is the center and end is the location of mouse
// Radius will be distance between the two
public CircularPath(Point2D start, Point2D end) {
super(start, end);
radius = normalToEnd.getLength();
color = Color.YELLOW;
}
public Point2D getPointAtTime(double time){
double px = start.getX() + radius * Math.cos(Math.toRadians(time));
double py = start.getY() - radius * Math.sin(Math.toRadians(time));
return new Point2D(px, py);
}
public double getFinalTime() { return 0; }
public CircularPath getClone() { return new CircularPath(start.getClone(), end.getClone()); }
public void update(){
super.update();
radius = normalToEnd.getLength();
}
public void render(Graphics2D g2d){
super.render(g2d);
g2d.drawLine((int)start.getX(), (int)start.getY(), (int)end.getX(), (int)end.getY());
//g2d.drawOval((int)(start.getX() - radius), (int)(start.getY() - radius), (int)radius * 2, (int)radius * 2);
}
}
x = r * cos(t/r)
y = r * sin(t/r)
The other solution is to model 2d momentum and impose a "gravitational force" toward the center point (or ellipsoidal focus, more generally) that you want the moving object to orbit around.
(The classic Space Wars game was implemented on a machine too slow to handle the trig computations in realtime, so they precomputed a 2d array each for the x and y components of the gravity field; they could then just do a table lookup based on the ship's last position and use that to update its momentum, which was then used to update its position. Slower machines forced more clever solutions.)
I'm making pong in Java and wanted to make the game more fun by assigning different reflection logic to each part of the paddle, like so:
(ball hittins outter edges of paddle will have a different effect than it hitting the middle of the paddle)
The paddle extends Rectangle2D so I could use Rectangle2D's intersects() method to determine if the ball has touched any part of it...
Is it possible to determine where exactly the ball has hit on the paddle?
What I'm planning to do is,
calculate angle of incidence and reflective angle based on that...
If the ball hits at a point x on the paddle... I will change the reflection angle accordingly
Thanks
Is it possible to determine where exactly the ball has hit on the paddle?
If it were me, I would grab the current co-ordinates of both the ball and the paddle. For the paddle, you can get two sets of y co-ordinates, to describe the line facing the ball. Ie:
int paddleY1 = paddle.y;
int paddleY2 = paddle.y + paddle.width;
// assuming the paddle can only go up and down, y is the only co-ordinate that matters.
Then, you can compute the mid point of the paddle as:
int paddleYMid = (paddleY1 + paddleY2) / 2;
You can find out if the ball hit the left or right side of the paddle by comparing the y co-ordinates. Ie:
if(ball.y > paddleYMid)
{
// Right side of the paddle.
}
else
{
// Left side of the paddle.
}
Then it's up to you to develop further refinement.
Since the paddle is always vertical (parallel to Y axis), the point of collision of the ball and the paddle will happen at the same y-coordinate as the center of the ball. That is:
if (ball.centerX - ball.radius <= paddle.rightX && ball.velocityX < 0)
{
// collision point, if any, is at (ball.centerX - ball.radius, ball.centerY)
if (ball.centerY >= paddle.bottomY && ball.centerY <= paddle.topY)
{
// handle collision
}
}
As for the handling of the collision itself, you may not have to deal with angle of reflection, etc, but work solely with the raw values of x and y velocity. For example, to simulate a perfectly elastic collision, simply do:
ball.velocityX = -ball.velocityX;
And to account for ball reflecting at a higher or lower angle, you can scale the y velocity based on the position of the collision from the center of the paddle, eg.
ball.velocityY += SCALE_CONSTANT * (ball.centerY - ((paddle.topY + paddle.bottomY) / 2));
To find the exact spot where the ball hits the paddle, you can formulate the problem as a line intersection problem.
The paddle can be represented as a vertical line at the x-coordinate (+thickness if needed, and corrected for the balls diameter) of the paddle. The ball can then be represented as a line along its movement vector (this line could be simply defined by its current position and its next position if it were to move unimpended).
The problem can now be solved using a line intersection algorythm.
Since the paddle is a vertical line, the equations can be simplified to just answer the question at which Y will the ball pass the paddle's X. Thats also a common problem encountered and solved by line clipping: http://en.wikipedia.org/wiki/Line_clipping (the intersection points can also be computed directly, but I can't find the formula atm).
So I'm having trouble making my placer face a planet. I have the angle between the player and the planet, I also have the angle that the player is currently at, now what I want to do with these is make my player face the planet but with an incremental change. (I do this because I want my placer to be able to orbit the planet)
The problem is with the math, I increment the player rotation to match the angle between the player and the planet however because angles work in 0 to 360 my player won't orbit because player rotation might be 2 however angle to planet is 280 so the game will turn the player around, sorry for the bad explanation.
Does anyone know how to make my player successfully orbit my planet?
Here is my code:
double rotation = Math.toDegrees(Math.atan2(currentPlanet.pos[1]-currentPlayer.pos[1], currentPlanet.pos[0]-currentPlayer.pos[0]));
if(rotation < 0)
{
rotation += 360;
}
if(currentPlayer.rotation < rotation)
{
currentPlayer.rotation += 0.15*delta;
}
if(currentPlayer.rotation > rotation)
{
currentPlayer.rotation -= 0.15*delta;
}
The problem is 350° is also -10°. You want the smaller absolute value.
The solution is very simple. Use modulo operation to translate your angles into correct range.
/* returns angle x represented in range -180.0 ... 180.0 */
double clampAngle(double x) {
return (x%360.0+360.0+180.0)%360.0-180.0;
}
Pass your angle difference to this function. Sign of the result will tell you in which direction you should turn:
double rotation = Math.toDegrees(Math.atan2(currentPlanet.pos[1]-currentPlayer.pos[1], currentPlanet.pos[0]-currentPlayer.pos[0]));
double diff = ((rotation-currentPlayer.rotation)%360.0+360.0+180.0)%360.0-180.0;
if(diff>0)
turn right
else
turn left
You might want to not turn at all if abs(diff) is very small.
I'm not sure if it will make your player orbit your planet. You will need to set correct angular and linear speed.
What you want is to make your player rotate to face either plus or minus 90 degrees of the angle you've computed between the planet and the player. Orbit occurs when all movement is tangent (90 degrees) to the planet.
So, compute the angle, compare the player angle to both the +90 and the -90, and rotate your player toward the closer of the two.
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.