Rotate arrow without using Unity3d physics engine - c#

I have this code that simulates the movement of a projectile without using the unity physics engine
IEnumerator LaunchProjectile(int angle, float speed)
{
// Move projectile to the position of throwing object + add some offset if needed.
Projectile.position = transform.position + new Vector3(0, 0f, 0);
Projectile.rotation = transform.root.rotation;
Debug.Log(transform.root.eulerAngles);
// Calculate distance to target
float target_Distance = speed * (Mathf.Sin(2 * firingAngle * Mathf.Deg2Rad) / gravity);
// Extract the X Y componenent of the velocity
float Vx = Mathf.Sqrt(speed) * Mathf.Cos(firingAngle * Mathf.Deg2Rad);
float Vy = Mathf.Sqrt(speed) * Mathf.Sin(firingAngle * Mathf.Deg2Rad);
// Calculate flight time.
float flightDuration = target_Distance / Vx;
this.arrowSimulationScript = Projectile.gameObject.GetComponentInChildren<ArrowSimulation>();
float elapse_time = 0;
while (!arrowSimulationScript.Collided())
{
Projectile.Translate(0, (Vy - (gravity * elapse_time)) * Time.deltaTime, Vx * Time.deltaTime);
Projectile.LookAt(Projectile.position - new Vector3(0, (Vy - (gravity * elapse_time)) * Time.deltaTime, Vx * Time.deltaTime));
arrowSimulationScript.Velocity = new Vector3(0, (Vy - (gravity * elapse_time)) * Time.deltaTime, Vx * Time.deltaTime).magnitude;
elapse_time += Time.deltaTime;
yield return null;
}
}
The arrow is fired in the direction of the object which has this script attached. To make the arrow rotate I use this line of code:
Projectile.LookAt(Projectile.position - new Vector3(0, (Vy - (gravity * elapse_time)) * Time.deltaTime, Vx * Time.deltaTime));
The arrow moves towards the right direction but with the tip facing the z axis direction, instead of the direction of the bow.
Here is a video of the problem:
https://www.youtube.com/watch?v=cyK6DXxTw_E
If I comment out that line of code the arrow fly with the tip facing the direction of the bow, but it doesn't rotate.

Try this
while (!arrowSimulationScript.Collided())
{
Vector3 delta = new Vector3(0, (Vy - (gravity * elapse_time)) * Time.deltaTime, Vx * Time.deltaTime);
Vector3 newPos = Projectile.position + delta;
Vector3 offset = (newPos - Projectile.position);
Vector3 magnitude = offset.magnitude;
Vector3 newDir = offset.normalized;
Projectile.rotation = Quaternion.LookRotation(newDir, Vector3.Cross(newDir, Projectile.right)));
arrowSimulationScript.Velocity = magnitude;
elapse_time += Time.deltaTime;
Projectile.position = newPos;
yield return null;
}

Related

FPS Player camera cant look left and right

I tried the last few weeks fix the problem with the camera. Like the title says, the players camera wont look left and right. And why? Because when I move the mouse left and right, the players y rotation rotates the right direction. But the Cameras y rotation is equal to the Players y rotation as a negative number. so, can anyone help me?
I tried literally everything. I expect the camera to rotate in all direction.
Here is the movement and look code:
mX += Input.GetAxis("Mouse X") * Sensivity * Time.deltaTime;
mY -= Input.GetAxis("Mouse Y") * Sensivity * Time.deltaTime;
mY = Mathf.Clamp(mY, -89.9f, 89.9f);
transform.eulerAngles = Vector3.up * mX/2;
cam.eulerAngles = Vector3.up * mX/2;
cam.eulerAngles = Vector3.right * mY;
float inputX = Input.GetAxis("Horizontal");
float inputY = Input.GetAxis("Fly");
float inputZ = Input.GetAxis("Vertical");
Vector3 dirForward = Vector3.ProjectOnPlane(transform.forward, Vector3.up).normalized;
Vector3 dirSide = transform.right;
Vector3 dirUp = Vector3.up;
Vector3 moveDir = (inputX * dirSide) + (inputY * dirUp) + (inputZ * dirForward);
transform.position += moveDir * Speed * Time.deltaTime;
I'm using this code for my 3d movements. Try it, it should work
public class free_cam_view : MonoBehaviour
{
public float mouseSensitivity = 100f;
float xr_1 = 0f;
void Update()
{
float y = 2 * Input.GetAxis("Mouse Y") * mouseSensitivity * Time.deltaTime;
xr_1 -= y;
xr_1 = Mathf.Clamp(xr_1, -90f, 63f);
transform.localRotation = Quaternion.Euler(xr_1, 0f, 0f);
}
}
Just add code to move forward by pressing "w"

Why this code moving my gameobject in such an odd way?

My Code
Vector2 moveDirection;
moveDirection = (Sensitive.transform.position - gameObject.transform.position).normalized;
float deg = Mathf.Rad2Deg * Mathf.Atan(moveDirection.x / -moveDirection.y);
if (moveDirection.y < 0) deg -= 180;
Vector3 to = new Vector3(0, 0, deg);
transform.eulerAngles = to;
transform.Translate(new Vector3(moveDirection.x, moveDirection.y) * speed * Time.deltaTime);
In the update function intended to look at and move to Sensitive, though it points correctly doesn't move correctly and I can figure out why.
transform.Translate by default interprets the input as a local direction & distance. You're providing the input in world direction & distance, so you should use the optional 2nd parameter and specify Space.World:
transform.Translate(new Vector3(moveDirection.x, moveDirection.y)
* (speed * Time.deltaTime), Space.World);

Get WASD keys to follow camera rotation in Unity

I understand there are many answers to this online but I was unable to apply them correctly to my code.
I have tried using pre-made player assets but could not get that to work.
Vector3 pos = transform.position;
public float X;
public float Y;
public float Z;
// Used to tilt camera up and down
float tilt = 0;
if (Input.GetMouseButton(1))
{
transform.Rotate(new Vector3(Input.GetAxis("Mouse Y") * panSpeed, Input.GetAxis("Mouse X") * panSpeed, 0));
X = transform.rotation.eulerAngles.x;
Y = transform.rotation.eulerAngles.y;
Z = transform.rotation.eulerAngles.z;
// Add current position of mouse input
tilt += X;
transform.rotation = Quaternion.Euler(0, Y, tilt);
}
//Spaceship does not go in direction it is facing once panned
if (Input.GetKey("w"))
{
//transform.rotation = Quaternion.Euler(0, Y, tilt);
pos.z += speed * Time.deltaTime;
}
if (Input.GetKey("s"))
{
pos.z -= speed * Time.deltaTime;
}
if (Input.GetKey("d"))
{
pos.x += speed * Time.deltaTime;
// DEBUG Does not work properly while mouse held down
//transform.Rotate(-1, 0, 0);
}
if (Input.GetKey("a"))
{
pos.x -= speed * Time.deltaTime;
}
transform.position = pos;
Assuming here the "Camera" equals transform you can simply use its local axis transform.forward
Returns a normalized vector representing the blue axis of the transform in world space.
and transform.right
Returns a normalized vector representing the red axis of the transform in world space.
like e.g.
private void Update()
{
if (Input.GetMouseButton(1))
{
// NOTE: I DON'T UNDERSTAND THIS CODE BLOCK YET
// YOU KNOW E.G. THAT IF YOU "transform.eulerAngles.x" ALREADY IS "45°"
// THE "tilt" WOULD JUMP EVERY FRAME IN HUGER STEPS (45 -> 90 -> 180 - 360 ....)
// ALSO WHY ROTATE IN X AXIS IF AFTERWARDS YOU RESET THE X ROTATION
// AND RATHER APPLY IT TO Z?
transform.Rotate(new Vector3(Input.GetAxis("Mouse Y") * panSpeed, Input.GetAxis("Mouse X") * panSpeed, 0));
X = transform.eulerAngles.x;
Y = transform.eulerAngles.y;
Z = transform.eulerAngles.z;
// Add current position of mouse input
tilt += X;
transform.rotation = Quaternion.Euler(0, Y, tilt);
}
Vector3 movement = Vector3.zero;
if (Input.GetKey(KeyCode.W))
{
movement += transform.forward;
}
if (Input.GetKey(KeyCode.S))
{
movement -= transform.forward;
}
if (Input.GetKey(KeyCode.D))
{
movement += transform.right;
}
if (Input.GetKey(KeyCode.A))
{
movement -= transform.right;
}
// I would do it like this to make sure that diagonal movement
// does not move faster
transform.position = movement.normalized * speed * Time.deltaTime;
}

Move Inside Pipe Like F-Zero GX

I've been working on this project for a while - I've been trying to get a simple cube that the player can move left or right with the arrows the ability to rotate around a pipe, similar to how racers can move around a pipe in F-Zero GX:
https://www.youtube.com/watch?v=RlS1i7aCnvg
Now, I know I'm not the first one to try to take a stab at implementing these physics, as I've read through two-three threads from people that have been trying to implement similar techniques. The problem is that I've tried playing around with these different methods or variations of them. One of these have gotten to act VERY closely to the behavior I wanted - but the player cube would STILL rotate on its X axis unexpectedly after the cube makes it over halfway up the full pipe's wall from the ground. Here's a visual of the level build I'm talking about:
The whole idea of this is, the cube can "move" or "walk" around the full wall of the pipe, like you see in the pipe sections of the F-Zero video, while of course still moving forward. I have a cylinder that is actually inside the one you see, which is actually just a convex trigger - so that is used to ensure that the gravity tick of the player cube is off while the cube is inside the pipe model.
I've gotten close to making this work, but it's a matter of seeing the player being able to move all the way in a full circle, ie. move in a circular motion completely back to the bottom or where the player began when entering the pipe. However, the cube likes to "flip" when it's a little over halfway done with completing the wall traveling. I've been reading in another post that someone actually changed the rigidbody of the object so that the "ship" stays upright, would that have something to do with it?
https://forum.unity.com/threads/f-zero-esque-control-question.157909/
"Essentially I gave my vehicle a hover-skirt."
Should I consider changing the shape of my rigidbody accordingly? What is the best resource to do this? Or perhaps I should use a character controller instead? I'm still leaning on a rigidbody setup, but I've opened my mind to the possibility after reading about those.
This Raycast code got very close to what I wanted, no dice:
float distDown = Mathf.Infinity;
RaycastHit hitDown;
if (Physics.SphereCast(transform.position, 0.25f, -transform.up, out hitDown, 5))
{
distDown = hitDown.distance;
}
transform.rotation = Quaternion.Lerp(transform.rotation, Quaternion.LookRotation(Vector3.Cross(transform.right, hitDown.normal), hitDown.normal), Time.deltaTime * 1.0f);
Another possibility I've tried to explore is creating your own gravity pull - I even have a class that tries to do this, FauxGravity, which is attached to the object the player collides with (in this case the cylinder):
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class FauxGravity : MonoBehaviour {
public Transform attractor;
public Transform player;
public Transform collider;
Rigidbody attractRB;
Rigidbody playerRB;
Vector3 myNormal;
public Vector3 vectorFromPipeCenter;
public Vector3 forwardPipeVector;
Vector3 project2Center;
public Vector3 pipeGravityPull;
public int gravity = 1;
// Use this for initialization
void Start () {
//Physics.gravity.magnitude = 0;
}
// Update is called once per frame
void Update () {
}
//private void OnCollisionEnter(Collision collision)
//{
// //collision.gameObject.GetComponent<Rigidbody>().transform.up = Vector3.zero;
// //player.gameObject.GetComponent<Rigidbody>().useGravity = false;
// myNormal = playerRB.transform.up;
// //playerRB = collision.gameObject.GetComponent<Rigidbody>();
// gravity = 0;
// //playerRB.isKinematic = true;
// //player.gameObject.GetComponent<Rigidbody>().AddRelativeForce()
//}
public void FixedUpdate()
{
if (gravity == 0)
{
//playerRB.isKinematic = true;
//Debug.Log("Gravity is 0.");
attractRB = attractor.GetComponent<Rigidbody>();
playerRB = player.GetComponent<Rigidbody>();
//playerRB.AddForce(-10 * playerRB.mass * myNormal);
Debug.Log("PlayerRB position: " + playerRB.position);
Debug.Log("AttractRB position: " + attractRB.position);
vectorFromPipeCenter = playerRB.position - attractRB.position;
vectorFromPipeCenter.z = 0;
//vectorFromPipeCenter.Normalize();
Debug.Log("Player distance from pipe center: " + vectorFromPipeCenter.magnitude);
Debug.Log("Player vector from pipe center" + vectorFromPipeCenter);
//vectorFromPipeCenter = attractRB.position - playerRB.position;
Debug.Log("playerRB forward is " + playerRB.rotation.z);
Debug.Log("playerRB magnitude is " + player.forward.magnitude);
forwardPipeVector = player.forward.magnitude * Vector3.forward;
Debug.Log("Player forward vector? " + forwardPipeVector);
// or
//Vector forwardPipeVector = pipeTransform.forward;
// And finally
project2Center = Vector3.Project(vectorFromPipeCenter, forwardPipeVector);
Debug.Log("What is project2Center? " + project2Center);
float radiusFromCrossectionCenter = vectorFromPipeCenter.magnitude;
double playerY = System.Convert.ToDouble(playerRB.position.y);
double playerX = System.Convert.ToDouble(playerRB.position.x);
//float inverseTan = System.Convert.ToSingle(System.Math.Atan(playerY / playerX));
//Debug.Log("Normal is: " + Quaternion.AngleAxis(inverseTan, forwardPipeVector));
// pipe pull force = distance from pipe center to power 2
//pipeGravityPull = Quaternion.AngleAxis(inverseTan, playerRB.transform.forward) * project2Center * Mathf.Pow ( (radiusFromCrossectionCenter * 1 ), 2 );
pipeGravityPull = new Vector3(playerRB.position.x, radiusFromCrossectionCenter - playerRB.position.y, 0)/Mathf.Sqrt(Mathf.Pow(playerRB.position.x,2) + Mathf.Pow((radiusFromCrossectionCenter-playerRB.position.y),2));
Debug.Log("Pipe gravity vector? " + pipeGravityPull);
//playerRB.useGravity = true;
Debug.DrawLine(pipeGravityPull, pipeGravityPull);
Debug.Log("Adding force from FG");
//playerRB.AddForce(pipeGravityPull);
}
if (gravity == 1)
{
player.GetComponent<Rigidbody>().useGravity = true;
//playerRB.isKinematic = false;
}
}
private void OnCollisionExit(Collision collision)
{
//Debug.Log("Gravity is 1 again.");
//player.gameObject.GetComponent<Rigidbody>().useGravity = true;
//gravity = 1;
//playerRB.useGravity = true;
playerRB.isKinematic = false;
//playerRB.AddForce(10, 20, 0);
}
void gravityAttract(Collider colliderObject)
{
var rb = colliderObject.GetComponent<Rigidbody>();
rb.AddForce(Vector3.down * 30, ForceMode.Force);
rb.AddForce(Vector3.up * 30, ForceMode.Force);
}
}
Do I need to move my FixedUpdate logic to an Update method instead? The last algorithm I've explored in this approach is essentially ensuring the pull is always equal to 1 by taking the vector of the player with the cross section of the pipe he/she is traveling in, according to my dad (he's an astrophysicist).
Here's my player's movement class, which has several commented and uncommented attempts to rotate the cube in order to allow the downside of the cube to always face the pipe wall as it climbs:
using System;
using UnityEngine;
public class PlayerMovement : MonoBehaviour {
public Rigidbody rb;
public float forwardForce = 2000f;
public float sidewaysForce = 500f;
public Boolean fauxGravity = false;
public Vector3 distanceFromPipeCenter = new Vector3(0, 0, 0);
public Vector3 pipePull = new Vector3(0,0,0);
// Use this for initialization
void Start () {
}
// Update is called once per frame use fixed update for Unity Fizzix
void FixedUpdate () {
//distanceFromPipeCenter.Normalize();
//add forward force
rb.AddForce(0, 0, forwardForce * Time.deltaTime);
if (Input.GetKey(KeyCode.RightArrow)/* && !fauxGravity*/)
{
rb.AddForce(sidewaysForce * Time.deltaTime, 0, 0, ForceMode.VelocityChange);
}
if (Input.GetKey(KeyCode.LeftArrow)/* && !fauxGravity*/)
{
rb.AddForce(-sidewaysForce * Time.deltaTime, 0, 0, ForceMode.VelocityChange);
}
if (pipePull.x == 0)
{
pipePull.x = 1;
}
if (pipePull.y == 0)
{
pipePull.y = 1;
}
//transform.rotation = Quaternion.identity;
//pipePull.z = 0;
if (Input.GetKey(KeyCode.RightArrow) && fauxGravity)
{
Debug.Log("Right pressed");
//Debug.Log("Rotation before: " + rb.rotation);
//rb.rotation = rb.rotation * Quaternion.FromToRotation(rb.transform.up, pipePull);
//rb.rotation = Quaternion.Lerp(rb.rotation, Quaternion.LookRotation(Vector3.Cross(rb.transform.right, pipePull), pipePull), Time.deltaTime * 5.0f);
//Debug.Log("Rotation after: " + rb.rotation);
//if (distanceFromPipeCenter.y < 0)
//{
// Debug.Log("Right A, pull positive: " +pipePull);
//rb.AddForce(sidewaysForce * pipePull.x * Time.deltaTime, sidewaysForce * pipePull.y * Time.deltaTime, 0, ForceMode.VelocityChange);
//}
//else
//{
// Debug.Log("Right B, pull negative: " + distanceFromPipeCenter);
// rb.AddForce(sidewaysForce * pipePull.x * Time.deltaTime, -sidewaysForce * pipePull.y * Time.deltaTime, 0, ForceMode.VelocityChange);
//}
//Debug.Log(rb.angularVelocity);
//float headingDeltaAngle = Input.GetAxis("Horizontal") * Time.deltaTime * sidewaysForce;
//Quaternion headingDelta = Quaternion.AngleAxis(headingDeltaAngle, transform.up);
//align with surface normal
//transform.rotation = Quaternion.FromToRotation(transform.up, distanceFromPipeCenter) * transform.rotation;
//apply heading rotation
//transform.rotation = headingDelta * transform.rotation;
}
if (Input.GetKey(KeyCode.LeftArrow) && fauxGravity)
{
Debug.Log("Left pressed");
//Debug.Log("Rotation before: " + rb.rotation);
//rb.rotation = rb.rotation * Quaternion.FromToRotation(rb.transform.up, pipePull);
//rb.rotation = Quaternion.Lerp(rb.rotation, Quaternion.LookRotation(Vector3.Cross(rb.transform.right, pipePull), pipePull), Time.deltaTime * 5.0f);
//Debug.Log("Rotation after: " + rb.rotation);
//if (distanceFromPipeCenter.y < 0)
//{
// Debug.Log("Left A, pull positive: " +pipePull);
//rb.AddForce(-sidewaysForce * pipePull.x * Time.deltaTime, sidewaysForce * pipePull.y * Time.deltaTime, 0, ForceMode.VelocityChange);
//}
//else
//{
// Debug.Log("Left B, pull negative: " + distanceFromPipeCenter);
// rb.AddForce(-sidewaysForce * pipePull.x * Time.deltaTime, -sidewaysForce * pipePull.y * Time.deltaTime, 0, ForceMode.VelocityChange);
//}
//Debug.Log(rb.angularVelocity);
//float headingDeltaAngle = Input.GetAxis("Horizontal") * Time.deltaTime * sidewaysForce;
//Quaternion headingDelta = Quaternion.AngleAxis(headingDeltaAngle, transform.up);
//align with surface normal
//transform.rotation = Quaternion.FromToRotation(transform.up, distanceFromPipeCenter) * transform.rotation;
//apply heading rotation
//transform.rotation = headingDelta * transform.rotation;
}
if (fauxGravity)
{
rb.useGravity = false;
///*We get the user input and modifiy the direction the ship will face towards*/
//float yaw = Time.deltaTime * Input.GetAxis("Horizontal");
///*We want to save our current transform.up vector so we can smoothly change it later*/
//Vector3 prev_up = rb.transform.up;
///*Now we set all angles to zero except for the Y which corresponds to the Yaw*/
//transform.rotation = Quaternion.Euler(0, yaw, 0);
//RaycastHit hit;
//if (Physics.Raycast(transform.position, -prev_up, out hit))
//{
// Debug.DrawLine(transform.position, hit.point);
// /*Here are the meat and potatoes: first we calculate the new up vector for the ship using lerp so that it is smoothed*/
// Vector3 desired_up = Vector3.Lerp(prev_up, hit.normal, Time.deltaTime /** pitch_smooth*/);
// /*Then we get the angle that we have to rotate in quaternion format*/
// Quaternion tilt = Quaternion.FromToRotation(transform.up, desired_up);
// /*Now we apply it to the ship with the quaternion product property*/
// transform.rotation = tilt * transform.rotation;
// /*Smoothly adjust our height*/
// //smooth_y = Mathf.Lerp(smooth_y, hover_height - hit.distance, Time.deltaTime * height_smooth);
// //transform.localPosition += prev_up * smooth_y;
//}
//float distForward = Mathf.Infinity;
//RaycastHit hitForward;
//if (Physics.SphereCast(transform.position, 0.25f, -transform.up + transform.forward, out hitForward, 5))
//{
// distForward = hitForward.distance;
//}
float distDown = Mathf.Infinity;
RaycastHit hitDown;
if (Physics.SphereCast(transform.position, 0.25f, -transform.up, out hitDown, 5))
{
distDown = hitDown.distance;
}
//float distBack = Mathf.Infinity;
//RaycastHit hitBack;
//if (Physics.SphereCast(transform.position, 0.25f, -transform.up + -transform.forward, out hitBack, 5))
//{
// distBack = hitBack.distance;
//}
//if (distForward < distDown && distForward < distBack)
//{
// transform.rotation = Quaternion.Lerp(transform.rotation, Quaternion.LookRotation(Vector3.Cross(transform.right, hitForward.normal), hitForward.normal), Time.deltaTime * 5.0f);
//}
//else if (distDown < distForward && distDown < distBack)
//{
transform.rotation = Quaternion.Lerp(transform.rotation, Quaternion.LookRotation(Vector3.Cross(transform.right, hitDown.normal), hitDown.normal), Time.deltaTime * 1.0f);
//}
//else if (distBack < distForward && distBack < distDown)
//{
// transform.rotation = Quaternion.Lerp(transform.rotation, Quaternion.LookRotation(Vector3.Cross(transform.right, hitBack.normal), hitBack.normal), Time.deltaTime * 5.0f);
//}
//GetComponent<Rigidbody>().AddForce(-transform.up * Time.deltaTime * 10);
}
if (rb.position.y <-1f)
{
FindObjectOfType<GameManagement>().EndGame();
}
}
//void OnCollisionEnter(Collision collision)
//{
// //collision.gameObject.GetComponent<Rigidbody>().transform.up = Vector3.zero;
// //player.gameObject.GetComponent<Rigidbody>().useGravity = false;
// System.Console.WriteLine("Player has collided with: " + collision.collider.name);
// if(collision.gameObject.name == "PipeBasic 1")
// {
// System.Console.WriteLine("Player Collided with Pipe");
// fauxGravity = true;
// }
// //playerRB.isKinematic = true;
// //player.gameObject.GetComponent<Rigidbody>().AddRelativeForce()
//}
}
Can anyone give some additional hints, tips, and tricks? I would think using a Raycast, and even a SphereCast of it, is probably going to be the closest kind of approach to what I want, but I'm just stuck on how I would exactly implementing it without risking rotating the player cube on the wrong side and screwing up the physics interaction. Am I perhaps overthinking this too much?
Thanks so much in advance everybody.
UPDATE:
I've been changing the logic of the Y velocity of the player, since moving in a circle has to involve specific physics, like the equation given on the page below:
https://www.physicsclassroom.com/class/circles/Lesson-1/Speed-and-Velocity
However, I'm still struggling to find a good time value to divide the top part of the equation against. Here's my movement code when moving right so far:
if (distanceFromPipeCenter.y < 0)
{
//Debug.Log("Right A, pull positive: " + pipePull);
//Debug.Log("X Pull: " + pipePull.x);
rb.AddForce(sidewaysForce /** pipePull.x*/ * Time.deltaTime, (sidewaysForce * 2 * radiusInPipe * (float)Math.PI) / Time.deltaTime, 0, ForceMode.VelocityChange);
}
else if(distanceFromPipeCenter.x>=3)
{
//Debug.Log("Right B, pull negative: " + distanceFromPipeCenter);
rb.AddForce(-sidewaysForce /** pipePull.x*/ * Time.deltaTime, (sidewaysForce * 2 * radiusInPipe * (float)Math.PI) / Time.deltaTime, 0, ForceMode.VelocityChange);
}
else if(distanceFromPipeCenter.x>0)
{
rb.AddForce(-sidewaysForce /** pipePull.x*/ * Time.deltaTime, (sidewaysForce * 2 * radiusInPipe * (float)Math.PI) / Time.deltaTime, 0, ForceMode.VelocityChange);
}
else if(distanceFromPipeCenter.y>0)
{
Debug.Log("X distance: " + distanceFromPipeCenter.x);
Debug.Log("Radius: " + radiusInPipe);
Debug.Log("Frame count? " + Time.fixedDeltaTime);
Vector3 pull = new Vector3(-sidewaysForce /** pipePull.x*/ * Time.deltaTime, ((-sidewaysForce * 2 * radiusInPipe * (float)Math.PI) / Time.fixedDeltaTime) * Time.deltaTime, 0);
Debug.Log("About to apply: " + pull );
rb.AddForce(-sidewaysForce /** pipePull.x*/ * Time.deltaTime, (-sidewaysForce * 2 * radiusInPipe * (float)Math.PI) / Time.deltaTime, 0, ForceMode.VelocityChange);
}
else
{
rb.AddForce(sidewaysForce /** pipePull.x*/ * Time.deltaTime, (-sidewaysForce * 2 * radiusInPipe * (float)Math.PI) / Time.deltaTime, 0, ForceMode.VelocityChange);
}
It seems dividing by Time.deltaTime just jumps the player a huge distance - not what I want. I also tried to used the amount of time since the beginning of the game as the divider, and then multiplying that whole result by Time.deltaTime - but as you probably can deduce, the frames just increase and then eventually slow the velocity down this way.
Any further thoughts or suggestions?
1. Disable Gravity
How about there being a trigger for when the player enters the pipe, you disable their rigidbody use gravity. I tried this and it seems to work, although my cube flips when getting near the top, because it's not sticking to the floor.
2. Collider under player only when looping pipe
A potential fix to this is spawning a collider underneath the player (as a child of the player), which is outside of the pipe as well - therefore the player will never float away from the pipe. Note: I didn't test this myself because my test cylinder is just many quads.
green circle is the collider to stop player floating from sides of pipe.
green square is trigger to activate green circle collider, ontriggerenter activates it, ontriggerexit deactivates it.
SO, turns out I overthought the whole, or rather, overlooked a key and amazing feature in this game engine.
I was trying to calculate all of these movements because I thought we had to calculate forces and movements all to the game world's origin. That whole time, I was saying all kinds of rants to myself, thinking, "Man, it'd be so much easier if you could just add a force/torque in the object's local coordinates..."
Enter AddRelativeForce() instead of AddForce().
With that, and the use of the radius passed in from the tunnel I'm passing through, with gravity off, I was able to much more easily get the effect desired.
This code is probably a little bloated at this point, but the key takeaway is the nextLeft and nextRight Vector3 objects I used. I hope this helps someone down the road. Let me know if I can clarify anything or make this post better in any other way.
void FixedUpdate () {
//distanceFromPipeCenter.Normalize();
//add forward force
rb.AddForce(0, 0, forwardForce * Time.deltaTime);
if (Input.GetKey(KeyCode.RightArrow) && !fauxGravity)
{
rb.AddForce(sidewaysForce * Time.deltaTime, 0, 0, ForceMode.VelocityChange);
}
if (Input.GetKey(KeyCode.LeftArrow) && !fauxGravity)
{
rb.AddForce(-sidewaysForce * Time.deltaTime, 0, 0, ForceMode.VelocityChange);
}
if(radiusInPipe == 0)
{
radiusInPipe = 1;
}
//transform.rotation = Quaternion.identity;
//pipePull.z = 0;
Vector3 nextRight = new Vector3(sidewaysForce /** pipePull.x*/ * Time.deltaTime, ((2 * radiusInPipe * (float)Math.PI) / (sidewaysForce)) * Time.fixedDeltaTime, 0);
Vector3 nextLeft = new Vector3(-sidewaysForce /** pipePull.x*/ * Time.deltaTime, ((2 * radiusInPipe * (float)Math.PI) / (sidewaysForce)) * Time.fixedDeltaTime, 0);
if (Input.GetKey(KeyCode.RightArrow) && fauxGravity)
{
//Debug.Log("Right pressed");
//Debug.Log("Rotation before: " + rb.rotation);
//rb.rotation = rb.rotation * Quaternion.FromToRotation(rb.transform.up, pipePull);
//rb.rotation = Quaternion.Lerp(rb.rotation, Quaternion.LookRotation(Vector3.Cross(rb.transform.right, pipePull), pipePull), Time.deltaTime * 5.0f);
//Debug.Log("Rotation after: " + rb.rotation);
//Vector3 next = new Vector3(sidewaysForce /** pipePull.x*/ * Time.deltaTime, ((2 * radiusInPipe * (float)Math.PI) / (sidewaysForce)) * Time.fixedDeltaTime, 0);
if (distanceFromPipeCenter.y < 0)
{
//Debug.Log("Right A, pull positive: " + pipePull);
//Debug.Log("X Pull: " + pipePull.x);
Debug.Log("Current deltaTime: " + Time.deltaTime);
//Vector3 next = new Vector3(sidewaysForce /** pipePull.x*/ * Time.deltaTime, ((2 * radiusInPipe * (float)Math.PI)/(sidewaysForce)) * Time.fixedDeltaTime, 0);
Debug.Log("About to apply: " + nextRight);
rb.AddRelativeForce(nextRight, ForceMode.VelocityChange);
}
else if(distanceFromPipeCenter.x>=3)
{
//Debug.Log("Right B, pull negative: " + distanceFromPipeCenter);
//rb.AddForce(sidewaysForce /** pipePull.x*/ * Time.deltaTime, ((2 * radiusInPipe * (float)Math.PI) * (sidewaysForce)) * Time.deltaTime, 0, ForceMode.VelocityChange);
rb.AddRelativeForce(nextRight, ForceMode.VelocityChange);
}
else if(distanceFromPipeCenter.x>0)
{
rb.AddRelativeForce(nextRight, ForceMode.VelocityChange);
//rb.AddForce(-sidewaysForce /** pipePull.x*/ * Time.deltaTime, ((2 * radiusInPipe * (float)Math.PI) * (sidewaysForce)) * Time.deltaTime, 0, ForceMode.VelocityChange);
}
else if(distanceFromPipeCenter.y>0)
{
Debug.Log("X distance: " + distanceFromPipeCenter.x);
Debug.Log("Radius: " + radiusInPipe);
Debug.Log("Frame count? " + Time.fixedDeltaTime);
Vector3 pull = new Vector3(-sidewaysForce /** pipePull.x*/ * Time.deltaTime, -((2 * radiusInPipe * (float)Math.PI) / (sidewaysForce)) * Time.fixedDeltaTime, 0);
Debug.Log("About to apply: " + pull );
//rb.AddForce(-sidewaysForce /** pipePull.x*/ * Time.deltaTime, -((2 * radiusInPipe * (float)Math.PI) * sidewaysForce) * Time.deltaTime, 0, ForceMode.VelocityChange);
rb.AddRelativeForce(nextRight, ForceMode.VelocityChange);
}
else
{
rb.AddRelativeForce(nextRight, ForceMode.VelocityChange);
//rb.AddForce(sidewaysForce /** pipePull.x*/ * Time.deltaTime, ((2 * radiusInPipe * (float)Math.PI) / (sidewaysForce)) * Time.fixedDeltaTime, 0, ForceMode.VelocityChange);
}
//Debug.Log(rb.angularVelocity);
float headingDeltaAngle = Input.GetAxis("Horizontal") * Time.deltaTime * sidewaysForce;
Quaternion headingDelta = Quaternion.AngleAxis(headingDeltaAngle, -transform.up);
headingDelta.y = 0;
headingDelta.x = 0;
//align with surface normal
transform.rotation = Quaternion.FromToRotation(-transform.up, distanceFromPipeCenter) * transform.rotation;
//apply heading rotation
transform.rotation = headingDelta * transform.rotation;
}
if (Input.GetKey(KeyCode.LeftArrow) && fauxGravity)
{
//Debug.Log("Left pressed");
//Debug.Log("Rotation before: " + rb.rotation);
//rb.rotation = rb.rotation * Quaternion.FromToRotation(rb.transform.up, pipePull);
//rb.rotation = Quaternion.Lerp(rb.rotation, Quaternion.LookRotation(Vector3.Cross(rb.transform.right, pipePull), pipePull), Time.deltaTime * 5.0f);
//Debug.Log("Rotation after: " + rb.rotation);
//if (distanceFromPipeCenter.y < 0)
//{
// //Debug.Log("Left A, pull positive: " + pipePull);
// rb.AddForce(-sidewaysForce/* * pipePull.x*/ * Time.deltaTime, sidewaysForce /pipePull.y * Time.deltaTime, Math.Abs(pipePull.z) * Time.deltaTime, ForceMode.VelocityChange);
//}
//else if(distanceFromPipeCenter.x >=0)
//{
// //Debug.Log("Left B, pull negative: " + distanceFromPipeCenter);
// rb.AddForce(sidewaysForce /** pipePull.x*/ * Time.deltaTime, sidewaysForce * -pipePull.y * Time.deltaTime, Math.Abs(pipePull.z) * Time.deltaTime, ForceMode.VelocityChange);
//}
//else
//{
// //rb.AddForce(sidewaysForce /** pipePull.x*/ * Time.deltaTime, sidewaysForce * -pipePull.y * Time.deltaTime, 0, ForceMode.VelocityChange);
// Debug.Log("Deadzone. PAUSE. Pull: " + pipePull);
//}
rb.AddRelativeForce(nextLeft, ForceMode.VelocityChange);
//Debug.Log(rb.angularVelocity);
float headingDeltaAngle = Input.GetAxis("Horizontal") * Time.deltaTime * sidewaysForce;
Quaternion headingDelta = Quaternion.AngleAxis(headingDeltaAngle, -transform.up);
headingDelta.y = 0;
headingDelta.x = 0;
//align with surface normal
transform.rotation = Quaternion.FromToRotation(-transform.up, distanceFromPipeCenter) * transform.rotation;
//apply heading rotation
transform.rotation = headingDelta * transform.rotation;
}
if (fauxGravity)
{
rb.useGravity = false;
if(rb.position.y-ground.position.y > 2)
{
roller.isTrigger = false;
}
else
{
roller.isTrigger = true;
}
//rb.AddForce(pipePull);
//roller.isTrigger = false;
///*We get the user input and modifiy the direction the ship will face towards*/
//float yaw = Time.deltaTime * Input.GetAxis("Horizontal");
///*We want to save our current transform.up vector so we can smoothly change it later*/
//Vector3 prev_up = rb.transform.up;
///*Now we set all angles to zero except for the Y which corresponds to the Yaw*/
//transform.rotation = Quaternion.Euler(0, yaw, 0);
//RaycastHit hit;
//if (Physics.Raycast(transform.position, -prev_up, out hit))
//{
// Debug.DrawLine(transform.position, hit.point);
// /*Here are the meat and potatoes: first we calculate the new up vector for the ship using lerp so that it is smoothed*/
// Vector3 desired_up = Vector3.Lerp(prev_up, hit.normal, Time.deltaTime /** pitch_smooth*/);
// /*Then we get the angle that we have to rotate in quaternion format*/
// Quaternion tilt = Quaternion.FromToRotation(transform.up, desired_up);
// /*Now we apply it to the ship with the quaternion product property*/
// transform.rotation = tilt * transform.rotation;
// /*Smoothly adjust our height*/
// //smooth_y = Mathf.Lerp(smooth_y, hover_height - hit.distance, Time.deltaTime * height_smooth);
// //transform.localPosition += prev_up * smooth_y;
//}
//float distForward = Mathf.Infinity;
//RaycastHit hitForward;
//if (Physics.SphereCast(transform.position, 0.25f, -transform.up + transform.forward, out hitForward, 5))
//{
// distForward = hitForward.distance;
//}
float distDown = Mathf.Infinity;
RaycastHit hitDown;
if (Physics.SphereCast(transform.position, 0.25f, -transform.up, out hitDown, 5))
{
distDown = hitDown.distance;
}
//float distBack = Mathf.Infinity;
//RaycastHit hitBack;
//if (Physics.SphereCast(transform.position, 0.25f, -transform.up + -transform.forward, out hitBack, 5))
//{
// distBack = hitBack.distance;
//}
//if (distForward < distDown && distForward < distBack)
//{
// transform.rotation = Quaternion.Lerp(transform.rotation, Quaternion.LookRotation(Vector3.Cross(transform.right, hitForward.normal), hitForward.normal), Time.deltaTime * 5.0f);
//}
//else if (distDown < distForward && distDown < distBack)
//{
//transform.rotation = Quaternion.Lerp(transform.rotation, Quaternion.LookRotation(Vector3.Cross(transform.right, hitDown.normal), hitDown.normal), Time.deltaTime * 1.0f);
//}
//else if (distBack < distForward && distBack < distDown)
//{
// transform.rotation = Quaternion.Lerp(transform.rotation, Quaternion.LookRotation(Vector3.Cross(transform.right, hitBack.normal), hitBack.normal), Time.deltaTime * 5.0f);
//}
//GetComponent<Rigidbody>().AddForce(-transform.up * Time.deltaTime * 10);
transformDifference = rb.position;
previousFrame = Time.frameCount;
}
if (rb.position.y <-1f)
{
FindObjectOfType<GameManagement>().EndGame();
}
}

Limiting vertical camera rotation

I've seen multiple threads on this topic, although none of those solutions have worked for my current script. I have my camera set up so it rotates when the right mouse button is being held down and dragged. My camera moves with the WASD keys.
if(Input.GetMouseButtonDown(1))
{
// Get mouse origin
mouseOrigin = Input.mousePosition;
isRotating = true;
}
if (isRotating)
{
Vector3 pos = cameraMain.ScreenToViewportPoint(Input.mousePosition - mouseOrigin);
transform.RotateAround(transform.position, transform.right, -pos.y * turnSpeed);
transform.RotateAround(transform.position, Vector3.up, pos.x * turnSpeed);
}
The error I have with this is that the camera vertically rotates freely. I want to know how to apply a limit to this rotation without changing the effect this code has on the camera.
if (isRotating)
{
Vector3 pos = cameraMain.ScreenToViewportPoint(Input.mousePosition - mouseOrigin);
pos.x = Mathf.Clamp (pos.x, 0, 90);
pos.y = Mathf.Clamp (pos.y, 0, 90);
transform.RotateAround("pass center object position", transform.right, -pos.y * turnSpeed);
transform.RotateAround("pass center object position", Vector3.up, pos.x * turnSpeed);
}
I've redone my camera movement code. I have this running so it only calls this function when the right mouse button is being held down.
public float speed = 10.0F;
public float RotSpeed = 150.0F;
public float minY = 0.0f;
public float maxY = 90.0f;
float forwardBackward;
float leftRight;
float RotLeftRight;
float RotUpDown;
Vector3 euler;
public void CameraRotate()
{
transform.localEulerAngles = euler;
// Getting axes
RotLeftRight = Input.GetAxis("Mouse X") * RotSpeed * Time.deltaTime;
RotUpDown = Input.GetAxis("Mouse Y") * -RotSpeed * Time.deltaTime;
// Doing movements
euler.y += RotLeftRight;
euler.x += RotUpDown;
LimitRotation ();
}
public void LimitRotation()
{
if(euler.x >= maxY)
euler.x = maxY;
if(euler.x <= minY)
euler.x = minY;
}

Categories