Converting radians to degrees with C# - c#

I'm creating a small game in Unity with C#, I'm not allowed to use any of the built in physics or colliders. What I have is a platform with a weight object on it. With the arrow keys you can tilt the platforms angle. The weight on top should then react accordingly to the given tilt angle. I have calculated everything with the friction, max friction, normal force a.s.o. The thing that doesn't work is when you press a key to change the tilt, the force on the object should change accordingly, and if the force on the weight is greater that the maximum friction force, then the weight should move. Here is a simplified example of my code.
public float m = 35;
public float µ = 0.15f;
public float g = 9.82f; //(N/kg)
public float N;
public double deg = 0;
Fmax = m * g * µ;
if (Input.GetKeyDown(KeyCode.UpArrow)) {
deg++;
N = m * g * µ * (Math.Cos(deg) * (180.0 / Math.PI));
platform.transform.Rotate(0, 0, deg, Space.Self);
} else if (Input.GetKeyDown(KeyCode.DownArrow)) {
deg--;
N = m * g * µ * (Math.Cos(deg) * (180.0 / Math.PI));
platform.transform.Rotate(0, 0, deg, Space.Self);
}
if(N > Fmax) {
// Do the rest of the code
}
I think that the problem has to do with that Math.Cos(deg) turns the deg into a radian, but I tried to then covert back the reg to a deg with: (180.0 / Math.PI). I can get everything to work on my calculator but not in the code.

This is incorrect:
N = m * g * µ * (Math.Cos(deg) * (180.0 / Math.PI));
If the angle is in degrees you have to convert it to radians and pass that the cosine function:
double rad = deg*Math.PI/180.0;
N = m*g*mu*Math.Cos(rad);

You can easily convert from radians to degrees and from degrees to radians using the Mathf.Deg2Rad and Mathf.Rad2Deg constants
using UnityEngine;
public class Example : MonoBehaviour
{
// convert 1 radian to degrees
float rad = 10.0f;
void Start()
{
float deg = rad * Mathf.Rad2Deg;
Debug.Log(rad + " radians are equal to " + deg + " degrees.");
}
}

There is a super handy function called Mathf.Rad2Deg and Mathf.Deg2Rad. They convert radians to degrees and degrees to radians.

Related

Find an angle to launch the projectile at to reach a specific point

So, Dani in his slightly new video -> "Making a Game, But I Only Have 3 Days" (https://youtu.be/S7Dl6ATRK2M) made a enemy which has a bow and arrow (at 5:39). I tried to recreate that but had no luck... I also can't find the website that he used... Today I found this https://physics.stackexchange.com/questions/56265/how-to-get-the-angle-needed-for-a-projectile-to-pass-through-a-given-point-for-t. It worked very well but still had problems if the target was far away and also it wasn't as accurate. The code so far is
float CalculateAngle()
{
float gravity = Physics.gravity.magnitude;
float deltaX = targetPositionMod.x - currentPosition.x;
float deltaY = targetPositionMod.y - currentPosition.y;
float RHSFirstPart = (velocity * velocity) / (gravity * deltaX);
float RHSSecondPart = Mathf.Sqrt(
((velocity * velocity) * ((velocity * velocity) - (2 * gravity * deltaY))
/ (gravity * gravity * deltaX * deltaX))
- 1);
float tanθ = RHSFirstPart - RHSSecondPart;
float angle = Mathf.Atan2(tanθ, 1) * Mathf.Rad2Deg;
if (angle < 0) return angle;
return -angle;
}
The -angle is because the forward axis starts points up when the x-rotation is negative (Unity). Maybe the reason of this not working as intended is that I am not that good at this kind of Physics (Part of that is me being only 14). Maybe the problem is in the code, maybe it is the formula. Any help is appreciated.
Thanks...
Edit:
The Archer class is:
using UnityEngine;
using System;
public class Archer : MonoBehaviour
{
[SerializeField] float velocity = default;
[SerializeField] Transform target = default;
[SerializeField] GameObject arrowPrefab = default;
[SerializeField] float coolDown = default;
Vector3 targetPositionMod;
Vector3 currentPosition;
Vector3 targetPosition;
float countDown = 0f;
void Start()
{
countDown = coolDown;
UpdateVariables();
}
void Update()
{
UpdateVariables();
SetAngle();
ShootBullet();
}
void UpdateVariables()
{
currentPosition = transform.position;
targetPositionMod = Mod(target.position);
targetPosition = target.position;
targetPosition.x /= 10;
targetPosition.y /= 10;
targetPosition.z /= 10;
countDown -= Time.deltaTime;
}
void SetAngle()
{
Vector3 direction = targetPosition - currentPosition;
Quaternion lookRotation = Quaternion.LookRotation(direction);
Vector3 rotation = lookRotation.eulerAngles;
rotation.x = (float) CalculateAngle();
transform.rotation = Quaternion.Euler(rotation.x, rotation.y, 0f);
}
void ShootBullet()
{
if (!(countDown <= 0f)) return;
countDown = coolDown;
GameObject arrow = Instantiate(arrowPrefab, transform.position, transform.rotation);
Rigidbody Rigidbody = arrow.GetComponent<Rigidbody>();
Rigidbody.AddForce(transform.forward * velocity, ForceMode.Impulse);
}
double CalculateAngle()
{
double gravity = Physics.gravity.magnitude;
double deltaX = targetPositionMod.x - currentPosition.x;
double deltaY = targetPositionMod.y - currentPosition.y;
double RHSFirstPart = (velocity * velocity) / (gravity * deltaX);
double RHSSecondPart = Math.Sqrt(
(((velocity * velocity) * ((velocity * velocity) - (2 * gravity * deltaY))
/ (gravity * gravity * deltaX * deltaX))
- 1));
double tanθ = RHSFirstPart - RHSSecondPart;
double angle = Math.Atan2(tanθ, 1) * Mathf.Rad2Deg;
if (angle < 0) return angle;
return -angle;
}
Vector3 Mod(Vector3 Vec)
{
if (Vec.x < 0) Vec.x -= 2 * Vec.x;
if (Vec.y < 0) Vec.y -= 2 * Vec.y;
if (Vec.z < 0) Vec.z -= 2 * Vec.z;
Vec.x /= 10;
Vec.y /= 10;
Vec.z /= 10;
return Vec;
}
}
Ok, as I can see, your implementation of formula from StackExchange is right, but you have to remember two things:
In unity there is a 3D world, so horizontal distance is not just pos1.x - pos2.x, but
Mathf.Sqrt( deltaX * deltaX + deltaZ * deltaZ ), where deltaX = targetPositionMod.x - currentPosition.x and deltaZ = targetPositionMod.z - currentPosition.z
In computer implementation you have no 100% accuracy of math, so some problems can appear because of computational accuracy. And it can have affect on big distances. You can try to use double instead of float or find another implementation for arctangent function (I think, this can really help). But try this (second) advice only if first didn't help. It's harder to implement and it slows computations a bit.
Algorithm:
Step 1: Set up a function that calculates the appropriate solution of a quadratic equation
a*x^2 + b*x + c = 0
double quadratic_root(a,b,c){
D = b^2 - 4*a*c
return ( - b - Math.Sqrt(D) ) / (2 * a)
}
Step 2: Input
current.x
current.y
current.z
target.x
target.y
target.z
velocity
gravity
Step 3: Calculate coefficients of the quadratic polynomial:
dist = Math.Sqrt( (target.x - current.x)^2 + (target.y - current.y)^2 )
a = gravity * dist^2 / (2 * velocity^2)
b = -dist
c = target.z - current.z + a
Step 4:
theta = Math.Atan2( quadratic_root(a,b,c), 1 )
Calculation behind the algorithm. You are in three space. The current position has coordinates
x = current.x
y = current.y
z = current.z
and the target has coordinates
x = target.x
y = target.y
z = target.z
Assume the angle between the initial velocity and the horizontal plane is theta. The magnitude of the projection of the distance between the current position and the target onto the horizontal $x,y-$plane is
dist = sqrt( (target.x - current.x)^2 - (target.y - current.y)^2 )
You are given the velocity magnitude velocity. Then, the speed with which the shadow (i.e. the orthogonal projection) of the arrow moves along the horizontal line between the source and the target is the magnitude of the shadow (i.e. the orthogonal projection) of the actual velocity
velocity * cos(theta)
The vertical speed of the arrow is then
velocity * sin(theta)
So the motion along dist follows the equation
dist = time * velocity * cos(theta)
and hence
time = dist / (velocity * cos(theta))
In the vertical direction, the motions is described by the equation
z = current.z + time * velocity * sin(theta) - time^2 * gravity / 2
You are interested in the time for which the arrow hits the target, which has vertical coordinate target.z, so
target.z = current.z + time * velocity * sin(theta) - time^2 * gravity / 2
The equation can be written as:
0 = - (target.z - current.z) + time * velocity * sin(theta) - time^2 * gravity / 2
We already know that
time = dist / (velocity * cos(theta))
so
0 = - (target.z - current.z) + dist * velocity * sin(theta) / (velocity * cos(theta)) - dist^2 * gravity / ( 2 * (velocity * cos(theta))^2 )
which can be slightly simplified to
0 = - (target.z - current.z) + dist * sin(theta) / cos(theta) - gravity * dist^2 / ( 2 * (velocity * cos(theta))^2 )
Because 1/( cos(theta)^2 ) = 1 + ( tan(theta) )^2 we obtain the quadratic in tan(theta) equation
a * ( tan(theta) )^2 + b * tan(theta) + c = 0
where
a = gravity * dist^2 / (2 * velocity^2)
b = - dist
c = target.z - current.z + a

C# create earthmap dictionary of latitudes and longitudes with distance 100km

I am trying to figure math for getting all longitudes and latitudes in a specific distance between each other. I have math for getting distance between geographic coords but I would like to get an array of all geo coords from the standard plane earthmap in the specific distance. Can you help me, please?
Here is example link of earthmap picture. I have earth heightmap in resolution 43200x21600 and I would like to get heights/pixels indexed from bottom left to top right in exact distance 100km. If I can get longitudes and latitudes in distance 100km then I can read these heights.
Here is math for distance between geographic points:
public static float GetGeographicDistance(float latitudeA, float longitudeA, float latitudeB, float longitudeB, float earthRadius = 6371.007f)
{
float phi1 = latitudeA * Mathf.Deg2Rad;
float phi2 = latitudeB * Mathf.Deg2Rad;
float deltaPhi = (latitudeB - latitudeA) * Mathf.Deg2Rad;
float deltaLambda = (longitudeB - longitudeA) * Mathf.Deg2Rad;
float a = Mathf.Sin(deltaPhi / 2) * Mathf.Sin(deltaPhi / 2) +
Mathf.Cos(phi1) * Mathf.Cos(phi2) *
Mathf.Sin(deltaLambda / 2) * Mathf.Sin(deltaLambda / 2);
float c = 2.0f * Mathf.Atan2(Mathf.Sqrt(a), Mathf.Sqrt(1.0f - a));
return earthRadius * c;
}
Got it. If somebody needs it, here is the function in C#.
public static TGeographicCoordinate DestinationPointFromStartPoint(TGeographicCoordinate start, double distance = 100f, double bearing = 90f, double earthRadius = 6371.009d)
{
TGeographicCoordinate result = new TGeographicCoordinate();
double angularDistanceRdn = distance / earthRadius;
double bearingRad = Mathf.Deg2Rad * bearing;
double startLatRad = start.Latitude * Mathf.Deg2Rad;
double startLonRad = start.Longitude * Mathf.Deg2Rad;
result.Latitude = Math.Asin((Math.Sin(startLatRad) * Math.Cos(angularDistanceRdn)) +
(Math.Cos(startLatRad) * Math.Sin(angularDistanceRdn) * Math.Cos(bearingRad)));
result.Longitude = startLonRad + Math.Atan2(Math.Sin(bearingRad) * Math.Sin(angularDistanceRdn) * Math.Cos(startLatRad),
Math.Cos(angularDistanceRdn) - (Math.Sin(startLatRad)) * Math.Sin(result.Latitude));
result.Latitude *= Mathf.Rad2Deg;
result.Longitude *= Mathf.Rad2Deg;
return result;
}

Extract forward vector from camera matrix

Scenario
I have a scene which contains several cameras, which may be facing any direction. I have no control over the creation of scene or cameras, but I need to work out which direction the cameras are facing in order to align them correctly.
The code below is a sample based on simple numbers, and I think shows that I'm missing something fundamental.
I am currently extracting the forward vector from the camera matrix using
Vector3 forward = new Vector3(-worldToCamera.M13, -worldToCamera.M23, -worldToCamera.M33);
as specified at
http://roy-t.nl/2010/03/04/getting-the-left-forward-and-back-vectors-from-a-view-matrix-directly.html
However, for any given rotated input, this always returns (0, 0, -1). My question is:
How do I get the forward direction in world space from the camera matrix?
Code
using System;
using System.Numerics;
public class Program
{
private const double OneEightyOverPI = 180d / Math.PI;
private const double TwoPI = Math.PI * 2d;
private const double PIOverTwo = Math.PI / 2d;
private const double ThreePIOverTwo = 3d * Math.PI / 2d;
public static void Main()
{
Vector3 cameraPosition = new Vector3(5, 5, 5);
Matrix4x4 translate = Matrix4x4.CreateTranslation(-cameraPosition);
Matrix4x4 cameraMatrix = translate;
Test(cameraMatrix, cameraPosition, 0);
// Z-axis is vertical, so rotate around it to change the pan angle of the camera
cameraMatrix = Matrix4x4.CreateRotationZ((float)PIOverTwo) * translate;
Test(cameraMatrix, cameraPosition, 90);
cameraMatrix = Matrix4x4.CreateRotationZ((float)Math.PI) * translate;
Test(cameraMatrix, cameraPosition, 180);
cameraMatrix = Matrix4x4.CreateRotationZ((float)ThreePIOverTwo) * translate;
Test(cameraMatrix, cameraPosition, 270);
}
private static void Test(Matrix4x4 worldToCamera, Vector3 cameraPositionWorld, int expected) {
// http://roy-t.nl/2010/03/04/getting-the-left-forward-and-back-vectors-from-a-view-matrix-directly.html
Vector3 forward = new Vector3(-worldToCamera.M13, -worldToCamera.M23, -worldToCamera.M33);
// input always aligned such that:
Vector3 north = Vector3.UnitY;
double angle = Math.Atan2(north.Y, north.X) - Math.Atan2(forward.Y, forward.X);
if (angle < 0) {
angle += TwoPI;
}
int deg = (int)(angle * OneEightyOverPI);
Console.WriteLine("Expected: " + expected + ", actual: " + deg + ", diff: " + (expected - deg));
}

How to I make this script stay in day and night longer?

I don't quite understand this code so I am having difficulty modifying it.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SunScript : MonoBehaviour {
public float duration = 1.0F;
public Light lt;
void Start() {
lt = GetComponent<Light>();
}
void Update() {
float phi = Time.time / duration * 0.1f * Mathf.PI;
float amplitude = Mathf.Cos(phi) * 0.5F + 0.5F;
lt.intensity = amplitude;
}
}
This moves the light's intensity up and down in a cycle. However, I would like to have it stay at its brightest and its dimmest for a while before it starts to move back the other direction. How should I do this?
What about replacing Mathf.Cos(phi) one of these functions instead of just a cosine?
Using the equation at the bottom of that page:
float amplitude = Mathf.Sin(Mathf.PI / 2f * Mathf.Cos(phi)) * 0.5f + 0.5f;
For the formula with the b term, you could do this (using extra temp variables to make it a little more readable).
float b = // whatever your b parameter is or have this declared as a class field that you can set in the Unity editor
float cosine = Mathf.Cos(phi);
float numerator = 1f + (b * b);
float denominator = 1f + (b * b * cosine * cosine);
float amplitude = (Mathf.Sqrt(numerator / denominator) * cosine) * 0.5f + 0.5f;
You can also use the Unity AnimationCurve to achieve this:
public class SunScript : MonoBehaviour
{
public float duration = 1.0F;
public AnimationCurve curve;
private Light lt;
void Start()
{
lt = GetComponent<Light>();
}
void Update()
{
lt.intensity = curve.Evaluate((Time.time % duration) / duration);
}
}
Simply make sure your curve is from 0 to 1 following X axis and make it the values you want on the Y axis.
Hope this helps,

Moving from A to B deceleration (Maths) XNA

What is the best way to decelerate at a speed of any given value (e.g. accelerationDropOff = 1.5f) before it reaches the end destination?
public bool MoveFromCurrentToPosition(float x, float y, float velocity, float acceleration, float deltaTime)
{
float startX = positionX, startY = positionY;
float endX = x, endY = y;
float deltaX = endX - startX;
float deltaY = endY - startY;
float speed = velocity;
float elapsed = 0.01f;
// On starting movement
float distance = (float)Math.Sqrt(Math.Pow(deltaX, 2) + Math.Pow(deltaY, 2));
float directionX = deltaX / distance;
float directionY = deltaY / distance;
isMoving = true;
// On update
if (isMoving == true)
{
positionX += directionX * speed * elapsed;
positionY += directionY * speed * elapsed;
if (currentAcceleration == 0)
{
currentAcceleration = acceleration;
}
else if (currentAcceleration >= maxAcceleration) // <- Don't accelerate anymore
{
speed *= currentAcceleration;
positionX += (directionX * speed) * deltaTime; positionY += (directionY * speed) * deltaTime;
bounds.X = (int)positionX; bounds.Y = (int)positionY;
}
else
{
currentAcceleration += acceleration;
speed *= currentAcceleration;
positionX += (directionX * speed) * deltaTime; positionY += (directionY * speed) * deltaTime;
bounds.X = (int)positionX; bounds.Y = (int)positionY;
}
float a = x, o = y;
double angle = Math.Atan2(o, a);
angle = angle * 180 / Math.PI;
movementDirection = (float)(180 - angle);
// Decelerate before reaching the end point
if (Math.Sqrt(Math.Pow(positionX - startX, 2) + Math.Pow(positionY - startY, 2)) >= distance)
{
positionX = endX;
positionY = endY;
isMoving = false;
return true;
}
}
return false;
}
I have been stuck on this problem for a hour or two and Math.exe is not responding. Can anyone point me in the correct direction please?
It seems as if you are mixing up speed (velocity) and acceleration. Speed is the change of position with respect to a given time frame. Acceleration is the change of speed with respect to a given time frame. For a constant acceleration, position and velocity change as follows:
v1 = v0 + a * t
x1 = x0 + v0 * t + 1/2 * a * t^2
v0, v1 and x0, x1 are the velocities and positions at the beginning and end of the time frame, respectively, a is the acceleration, t is the time frame length. This is the exact formula if you assume constant acceleration over the period of the time frame. Often, you find approximations like the following, which introduce some integration errors:
v1 = v0 + a * t
x1 = x0 + v1 * t
I would suggest to use the exact formulas.
As far as I understand your question, you want to find an acceleration, such that a body moving at initial velocity v0 stops after travelling d length units.
This gives you the following equations:
0 = v0 + a * t //target velocity of 0
d = 0 + v0 * t + 1/2 * a * t^2 //travel distance of d
The solution is:
a = -1/2 * v0^2 / d
The time needed for this motion is:
t = 2 * d / v0
So calculate the acceleration once at the beginning of the deccelerating movement and then update current position and velocity with the formulas above.
Some additional hints for your code:
If you want to square a variable x, use x * x instead of Math.pow(x, 2). It is easier to read and has a better performance.
If you already use XNA, then use its Vector2 structure. This makes a lot of things much easier. You can just add two vectors and don't need to care about each component separately. There are methods to get the length of a vector, and so on.

Categories