Camera flies off when trying to set camera bounds - c#

The player controls the camera movement to look around the level and I am trying to set boundaries so the camera cannot go too far. However, when I have the boundary code added, the camera flies off whenever I press a button to move.
if (Input.GetKey("d"))
{
transform.Translate(new Vector2(camSpeed * Time.deltaTime, 0));
transform.position = new Vector2(Mathf.Clamp(transform.position.x, minX, maxX), 0);
}
if (Input.GetKey("a"))
{
transform.Translate(new Vector2(-camSpeed * Time.deltaTime, 0));
transform.position = new Vector2(Mathf.Clamp(transform.position.x, minX, maxX), 0);
}
if (Input.GetKey("w"))
{
transform.Translate(new Vector2(0, camSpeed * Time.deltaTime));
transform.position = new Vector2(0, Mathf.Clamp(transform.position.y, minY, maxY));
}
if (Input.GetKey("s"))
{
transform.Translate(new Vector2(0, -camSpeed * Time.deltaTime));
transform.position = new Vector2(0, Mathf.Clamp(transform.position.y, minY, maxY));
}
I have set values min and max values to higher than needed levels and the camera still flies off, no matter what the values are set to.

To explain my comment; instead of setting x to 0 every time you move with W or S you should move the clamping to the end, and clamp both x and y (and probably keep Z value?):
if (Input.GetKey("d"))
{
transform.Translate(new Vector2(camSpeed * Time.deltaTime, 0));
}
if (Input.GetKey("a"))
{
transform.Translate(new Vector2(-camSpeed * Time.deltaTime, 0));
}
if (Input.GetKey("w"))
{
transform.Translate(new Vector2(0, camSpeed * Time.deltaTime));
}
if (Input.GetKey("s"))
{
transform.Translate(new Vector2(0, -camSpeed * Time.deltaTime));
}
transform.position = new Vector3(
Mathf.Clamp(transform.position.x, minX, maxX),
Mathf.Clamp(transform.position.y, minY, maxY),
transform.position.z
);

Related

Unity 3D instantly rotate in the direction of movement

I have a somewhat similar question to this one, I'm trying to rotate in the direction of movement but the issue is that I want to maintain my position and just instantly rotate because I have a procedural maze and there's not enough space to gradually swing around in the direction of movement in a wide turn. I'll post code attempts at the bottom, attempt two gives the error: viewing vector is zero.
If you look at all four of these screenshots, when the y-axis is rotated, the x-axis and z-axis jump to a new position. When I'm moving this ends up looking like I'm teleporting around the maze. Anyone know how to rotate while remaining in the same position?
Here's right:
Here's forward:
Here's left:
Here's back:
here's code attempt 1:
public void playerMovement()
{
float horizontalInput = Input.GetAxis("Horizontal");
float verticalInput = Input.GetAxis("Vertical");
Vector3 movementx = new Vector3(horizontalInput, 0f, 0f);
Vector3 movementy = new Vector3(0f, 0f, verticalInput);
movementy = transform.forward * verticalInput;
movementx = transform.right * horizontalInput;
if (horizontalInput > 0)
{
transform.eulerAngles = new Vector3(0f, 90f, 0f);
transform.Translate(-movementx.normalized * 0.1f, Space.Self);
}
if (horizontalInput < 0)
{
transform.eulerAngles = new Vector3(0f, 270f, 0f);
transform.Translate(-movementx.normalized * 0.1f, Space.Self);
}
if (verticalInput < 0)
{
transform.eulerAngles = new Vector3(0f, 180f, 0f);
transform.Translate(movementy.normalized * 0.1f, Space.Self);
}
if (verticalInput > 0)
{
transform.eulerAngles = new Vector3(0f, 0f, 0f);
transform.Translate(movementy.normalized * 0.1f, Space.Self);
}
}
Here's code attempt 2:
public void playerMovement2()
{
Vector3 movement = new Vector3(Input.GetAxis("Horizontal"), 0f, Input.GetAxis("Vertical"));
movement = transform.TransformDirection(movement);
transform.Translate(movement.normalized * 0.1f, Space.Self);
transform.rotation = Quaternion.LookRotation(movement);
}
I took your second attempt and modified it:
This way you will walk and look in the direction you
void Update()
{
Vector3 movement = new Vector3(Input.GetAxis("Horizontal"), 0f, Input.GetAxis("Vertical"));
transform.Translate(movement.normalized * 0.1f, Space.World);
transform.rotation = Quaternion.LookRotation(movement, Vector3.up);
}
However then the character will always "flip" back to forward
-> you can solve that by only moving when new input is given
For example like this:
void Update()
{
Vector3 movement = new Vector3(Input.GetAxis("Horizontal"), 0f, Input.GetAxis("Vertical"));
if (movement.magnitude > 0f)
{
transform.Translate(movement.normalized * 0.1f, Space.World);
transform.rotation = Quaternion.LookRotation(movement, Vector3.up);
}
}

How do I keep raycast relative to the object its bound to?

I have a car game and I would like to use raycast to detect other obstacles and do stuff if the ray hits.
The problem is after the car does a 90 degree turn the raycast move in a way I did not intend them to, like this:
But when I rotate the car by 90 degrees it looks like this:
I'd like the rays to remain as they are in the first image regardless of the rotation of the car.
Here is the code to cast the rays and to draw them:
private void OnDrawGizmos()
{
sensorStartPosition1 = transform.position + new Vector3(1f, 0.6f, 0f);
sensorStartPosition2 = transform.position + new Vector3(-1f, 0.6f, 0f);
Gizmos.DrawRay(sensorStartPosition1, transform.TransformDirection(Vector3.right) * 3.5f);
Gizmos.DrawRay(sensorStartPosition2, transform.TransformDirection(Vector3.left) * 3.5f);
}
private void RunSensors()
{
RaycastHit hit1;
sensorStartPosition1 = transform.position + new Vector3(1f, 0.6f, 0);
//dTS = detect traffic signs
Ray dTS = new Ray(sensorStartPosition1, transform.TransformDirection(Vector3.right));
if(Physics.Raycast(dTS, out hit1, sensorLen ))
{
}
Debug.DrawRay(sensorStartPosition1, transform.TransformDirection(Vector3.right) * 3.5f);
RaycastHit hit2;
sensorStartPosition2 = transform.position + new Vector3(-1f, 0.6f, 0);
// dLIT1 = detect left incoming traffic
Ray dLIT1 = new Ray(sensorStartPosition2, transform.TransformDirection(Vector3.left));
if(Physics.Raycast(dLIT1, out hit2, sensorLen))
{
}
Debug.DrawRay(sensorStartPosition1, transform.TransformDirection(Vector3.left) * 3.5f);
}
what am I doing wrong?.. thanks in advance
You calculate the two start positions with an offset along the global world space X axis regardless of the rotation in
sensorStartPosition1 = transform.position + new Vector3(1f, 0.6f, 0f);
//...
sensorStartPosition2 = transform.position + new Vector3(-1f, 0.6f, 0f);
instead rather calculate them like
sensorStartPosition1 = transform.position + transform.right * 1f + transform.up * 0.6f;
//...
sensorStartPosition2 = transform.position + transform.right * -1f + transform.up * 0.6f;
Or simply
sensorStartPosition1 = transform.position + transform.rotation * new Vector3(1f, 0.6f, 0f);
//...
sensorStartPosition2 = transform.position + transform.rotation * new Vector3(-1f, 0.6f, 0f);
Btw instead of
transform.TransformDirection(Vector3.right)
transform.TransformDirection(Vector3.left)
you can also simply use
transform.right
-transform.right

Unity C# - Move character while jumping

My character moves great, and jumps great. But when jumping he just moves straight in the direction he came from and you can't rotate or move him while in the air. How can that be done?
From the Update Function:
if (controller.isGrounded)
{
moveD = new Vector3(Input.GetAxisRaw("Horizontal"), 0, Input.GetAxisRaw("Vertical"));
moveD = transform.TransformDirection(moveD.normalized) * speed;
moveDA = new Vector3(Input.GetAxisRaw("Horizontal"), 0, Input.GetAxisRaw("Vertical"));
if (moveDA.magnitude > 0)
{
gameObject.transform.GetChild(0).LookAt(gameObject.transform.position + moveDA, Vector3.up);
}
if (Input.GetButton("Jump"))
{
moveD.y = jumpSpeed;
}
}
moveD.y = moveD.y - (gravity * Time.deltaTime);
controller.Move(moveD * Time.deltaTime);
controller.isGrounded Is only true if the last time you called controller.Move() the bottom of the object's collider is touching a surface, so in your case once you jump, you cannot move until you hit the ground again.
You can solve this by separating your movement code and jumping code like so:
moveD = new Vector3(Input.GetAxisRaw("Horizontal"), 0, Input.GetAxisRaw("Vertical"));
moveD = transform.TransformDirection(moveD.normalized) * speed;
moveDA = new Vector3(Input.GetAxisRaw("Horizontal"), 0, Input.GetAxisRaw("Vertical"));
if (moveDA.magnitude > 0)
{
gameObject.transform.GetChild(0).LookAt(gameObject.transform.position + moveDA, Vector3.up);
}
if (controller.isGrounded)
{
if (Input.GetButton("Jump"))
{
moveD.y = jumpSpeed;
}
}
moveD.y = moveD.y - (gravity * Time.deltaTime);
controller.Move(moveD * 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();
}
}

Rotate arrow without using Unity3d physics engine

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;
}

Categories