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.
Related
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)
I make a 2D game in LibGDX and the player movement system is pretty simple:
if (Gdx.input.isKeyPressed(Input.Keys.W))
player.setPosition(player.getPosition().x, player.getPosition().y + 100 * delta);
And the same principle for the A, S and D key.
But now, I have a "drunk mode" - hence, there is a camera rotation in the world, so just:
camera.rotate(MathUtils.random(-50, 50) * delta);
But if I press the W key when the camera rotates, the player doesn't move straight upwards anymore. So, if the rotation is e.g. 180°, the player moves straight downwards, which is actually pretty logical.
So is there a way that the player always moves, upwards when pressing W, rightwards when pressing D etc. no matter what's the current rotation?
Thank you in advance
Try using the deviation on the player in the same direction.
final int PLAYER_SPEED = 100;
float angle = MathUtils.random(-50, 50) * delta; // btw, delta is Gdx.graphics.getDeltaTime()?
camera.rotate(angle);
if (Gdx.input.isKeyPressed(Input.Keys.W)) {
float xOffset = PLAYER_SPEED * sin(toRadians(angle)) * delta;
float yOffset = PLAYER_SPEED * cos(toRadians(angle)) * delta;
player.setPosition(player.getPosition().x + xOffset, player.getPosition().y + yOffset);
}
For other directions there must be other trigonometric formulas.
The solution of 5tingr4y worked for me.
So, I just created a vector and rotated it in the opposite direction. Then, I move the player by that Vector.
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 am trying to have a character hold a gun, but I want the gun to move with the mouse. For example, if the mouse is up, the gun points up. If the mouse is to the left, the gun points to the left. I used the player position and the mouse position to construct a right triangle, then used inverse sine to find the angle of elevation. However, this only works for 90 degrees of movement. Any ideas of how else I could approach this so that I get a full 360 degrees of rotation?
Code for calculating the angle:
private double calcAngle()
{
double mouseX,mouseY,subX,subY,playerToMouse,mouseToSub,angle;
mouseX = Mouse.getX();
mouseY = Mouse.getY();
subX = mouseX;
subY = y;
playerToMouse = Math.sqrt(Math.pow(x-mouseX,2)+Math.pow(y-mouseY,2));
mouseToSub = Math.sqrt(Math.pow(mouseX-subX,2)+Math.pow(mouseY-subY,2));
angle = Math.toDegrees(Math.asin(mouseToSub/playerToMouse));
return angle;
}
Current rotation (Pink represents player; Green represents gun; Yellow represents mouse):
You can use Math.atan2(mouseY-gunY, mouseX-gunX) which will return an angle between pi and -pi radians, or 180 and -180 degrees after you convert it to degrees. The problem with using asin is that 1/1 is equal to -1/-1 which makes it impossible for the function to tell them apart, and you want different results in each case.
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).