Drone Controller in Unity: movement issues with the unity inputSystem - c#

I'm trying to build a controller for a unity gameobject to move it similary to a normel quadrotor drone. So the drone should be able to ascend and descend by mobing the left stick up and down, turn around by moving the left stick sidewards and move horizontally by using the right stick.
I tried implementing it with the unity inputSystem, but unfortunately, it doesn't really work the way it is supposed to.
Movements are mostly not smooth and the rotation causes the horizonzal movement to move in wrong directions.
Here is my code:
public void OnMove(InputValue inputValue)
{
//horizontal movement
Debug.Log(inputValue.Get());
Vector3 move = new Vector3(inputValue.Get<Vector2>().x * 10 * Time.deltaTime, 0, inputValue.Get<Vector2>().y * 1 * Time.deltaTime);
move = Quaternion.Euler(0, rotation, 0) * move;
//playerDrone.transform.position += new Vector3(inputValue.Get<Vector2>().x * 10 * Time.deltaTime, 0, inputValue.Get<Vector2>().y * 10 * Time.deltaTime);
playerDrone.transform.Translate(move, Space.World);
}
public void OnClockwiseRotation()
{
//rotation of drone clockwise
playerCam.transform.Rotate(0, 0.5f, 0, Space.World);
rotation += 0.5f;
}
public void OnCounterclockwiseRotation()
{
//rotation of drone counterclockwise
Debug.Log("Rotation");
playerCam.transform.Rotate(0, -0.5f, 0, Space.World);
rotation += 0.5f;
}
public void OnAscend1()
{
//ascend drone
playerDrone.transform.position += new Vector3(0, 0.1f, 0);
Debug.Log("Ascend");
}
public void OnDescend()
{
//descend drone
Debug.Log("Descend");
playerDrone.transform.position += new Vector3(0, -0.1f, 0);
}
Does anyone know why the movement is so problematic with that implementation?
Thanks in advance

There are a few mistakes I'd say
Your rotation and your ascending are frame-rate dependent. Here you didn't use Time.deltaTime
In both OnClockwiseRotation and OnCounterclockwiseRotation you do
rotation += 0.5f;
You are using once playerDrone and another time playerCam .. you should probably stick to one as it sounds like you are only rotating a camera but not the drone.
In general I would not hardcode the values into your code but rather expose some class fields so you can adjust the velocities vis the Inspector without having to recompile
You probably would rather do something like
// Adjust these in the Inspector!
// in angle per second
public float rotationSpeed = 45;
// in meter per second
public float ascendingSpeed = 1;
public float forwardSpeed = 1;
public float sidewardsSpeed = 1;
public void OnMove(InputValue inputValue)
{
// In this case probably not a big deal but in general use getters only once
var input = inputValue.Get();
var move = new Vector3(input.x * sidewardsSpeed * Time.deltaTime, 0, input.y * forwardSpeed * Time.deltaTime);
move = Quaternion.Euler(0, rotation, 0) * move;
playerDrone.transform.Translate(move, Space.World);
}
public void OnClockwiseRotation()
{
var angle = rotationSpeed * Time.deltaTime;
playerDrone.transform.Rotate(0, angle, 0, Space.World);
rotation += angle;
}
public void OnCounterclockwiseRotation()
{
var angle = rotationSpeed * Time.deltaTime;
playerDrone.transform.Rotate(0, -angle, 0, Space.World);
rotation -= angle;
}
public void OnAscend1()
{
playerDrone.transform.position += Vector3.up * ascendingSpeed * Time.deltaTime;
}

Related

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

How to restrict Quaternion.RotateTowards() to clockwise-only rotation

I made a speedometer script for rotaing the needle in the speedometer
public class Speedometer : MonoBehaviour
{
public float zeroRate = 3f;
[SerializeField] PlayerController vehicle;
void Update()
{
if (vehicle.IsOnGround())
{
float zRot = ((vehicle.speed * 2.237f) / vehicle.maxSpeed) * 180;
transform.rotation = Quaternion.Euler(0, 0, -zRot);
}
else
{
transform.rotation = Quaternion.RotateTowards(transform.rotation, Quaternion.identity, zeroRate * Time.deltaTime);
}
}
}
I'm facing the problem that the needle sometimes does a full 360 to rotate towards Quanternion.identity. I could use an if condition to check if the value goes beyond 180, subtract the twice the difference but the condition would check for this in every Update() call and would just clutter code with a 1-time-use-only if-condition. Is there a function that restricts the rotate in clockwise/anti-clockwise direction?
Alternatively you could probably do something like store the last zRot value and over time reduce it and go
private float zRot;
void Update()
{
if (vehicle.IsOnGround())
{
zRot = ((vehicle.speed * 2.237f) / vehicle.maxSpeed) * 180;
transform.rotation = Quaternion.Euler(0, 0, -zRot);
}
else
{
if(zRot > 0)
{
zRot -= zeroRate * Time.deltaTime;
// clamp to 0
zRot = Mathf.Max(0, zRot);
transform.rotation = Quaternion.Euler(0, 0, -zRot);
}
}
}
Just that now zeroRate would be in °/second instead of radians/second in your version.

Move to rotated direction [2D] [Unity]

I have a sheep which is rotating to random direction. Question is how to make it move all the time in the direction it was rotated (rotation changes every 5 seconds).
Here is my code:
using UnityEngine;
public class Sheep : MonoBehaviour
{
private float SheepMovementSpeed = 30f;
void Start()
{
InvokeRepeating("SheepRandomRotate", Random.Range(3f, 4.9f), 5f);
}
void Update()
{
}
public void SheepRandomRotate ()
{
var dir = new Vector2(Random.Range(-10, 10), Random.Range(-10, 10));
var angle = Mathf.Atan2(dir.y, dir.x) * Mathf.Rad2Deg;
transform.rotation = Quaternion.AngleAxis(angle + 90, Vector3.forward);
}
}
Any ideas?
Use the same Vector3.forward you used in your rotation
transform.position += (Vector3.forward * Time.deltaTime * speed);
In Update
transform.up is up relative to the rotation. So if the camera is facinf forward that should work for your sprite.
transform.Translate(transform.up* Time.deltaTime * SheepMovementSpeed )

How can i rotate a spaceship back to it's original rotation to face the original position?

The spaceship start moving from point A. The spaceship is facing the moving direction.
Now when i click one on the L key i want that the spaceship will rotate and will face to the original position it was start moving from. But even if the spaceship is now rotated by axis Z or Y or X to rotate it first to the regular rotation values and to face to the start moving position.
using UnityEngine;
using System.Collections;
public class Control : MonoBehaviour
{
public int rotationSpeed = 75;
public int movementspeed = 10;
public int thrust = 10;
private bool isPKeyDown = false;
private float acceleration = .0f;
private Vector3 previousPosition = Vector3.zero;
private Rigidbody _rigidbody;
private Vector3 originalPosition;
private Quaternion originalRotation;
// Use this for initialization
void Start()
{
originalPosition = transform.position;
originalRotation = transform.rotation;
_rigidbody = GetComponent<Rigidbody>();
Debug.Log("Acc Speed: " + thrust);
}
// Update is called once per frame
void Update()
{
var v3 = new Vector3(Input.GetAxis("Vertical"), Input.GetAxis("Horizontal"), 0.0f);
transform.Rotate(v3 * rotationSpeed * Time.deltaTime);
transform.position += transform.forward * Time.deltaTime * movementspeed;
if (Input.GetKey(KeyCode.Z))
transform.Rotate(Vector3.forward * rotationSpeed * Time.deltaTime);
if (Input.GetKey("p"))
{
isPKeyDown = Input.GetKey("p");
float distance = Vector3.Distance(previousPosition, transform.position);
acceleration = distance / Mathf.Pow(Time.deltaTime, 2);
previousPosition = transform.position;
_rigidbody.AddRelativeForce(0f, 0f, thrust, ForceMode.Acceleration);
}
if (Input.GetKey("l"))
{
transform.rotation = Quaternion.Slerp(transform.rotation, originalRotation, 0);
//StartCoroutine(TurnShip(transform, transform., originalRotation.eulerAngles, 1));
//transform.position += transform.forward * Time.deltaTime * movementspeed;
}
}
IEnumerator TurnShip(Transform ship, Vector3 startAngle, Vector3 endAngle, float smooth)
{
float lerpSpeed = 0;
while (lerpSpeed < 1)
{
ship.eulerAngles = Vector3.Lerp(startAngle, endAngle, lerpSpeed);
lerpSpeed += Time.deltaTime * smooth;
yield return null;
}
}
void OnGUI()
{
if (isPKeyDown)
{
GUI.Label(new Rect(100, 100, 200, 200), "Acc Speed: " + acceleration);
}
}
}
This is where i click the L button but i tried some things but can't yet find how to do it.
The main goal is if i click once on L the spaceship should automatic rotate if needed and move back to the original position and then land on ground. L stand for landing that's the main goal.
Add a variable on top -
...
private Vector3 originalPosition;
private Quaternion originalRotation;
private bool landShip = false;
...
And use following code in update function -
if (Input.GetKey("l"))
{
landShip = true;
//StartCoroutine(TurnShip(transform, transform., originalRotation.eulerAngles, 1));
//transform.position += transform.forward * Time.deltaTime * movementspeed;
}
if(landShip){
transform.rotation = Quaternion.Slerp(transform.rotation, originalRotation, 0.5f);
}
Once the spaceship lands, set the landShip value back to false.

Make GameObject hover above a plane? - Unity3D C#

So I'm trying to make an FPS-type game and is it possible to have a GameObject locked on the Y-axis/not able to move up or down? The GameObject is a model of an AWP from Counter Strike, I am making it move around the plane with the WASD keys, and when I use the mouse to look up/down, the AWP goes diagonally to where I'm looking, and I don't want that. My game looks like this: Screenshot
Here's the code I have for the AWP if it helps:
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
public class AWPscript : MonoBehaviour {
public float speed = 5f;
// public float sensitivityX = 15.0f;
// public float sensitivityY = 15.0f;
public Camera MainCamera;
public Camera scopeCamera;
public float lookSensitivity = 10f;
public float xRotation ;
public float yRotation ;
public float currentXRotation;
public float currentYRotation;
public float xRotationV;
public float yRotationV;
public GameObject Scopepng;
public float lookSmoothDamp = 0.1f;
public Image ScopePNG;
public AudioClip sound;
// Use this for initialization
void Start () {
speed = 7.5f;
}
// Update is called once per frame
void Update () {
if(Input.GetKey(KeyCode.W))
transform.Translate(Vector3.forward * Time.deltaTime*speed);
if (Input.GetKey(KeyCode.S))
transform.Translate(Vector3.back * Time.deltaTime * speed);
if (Input.GetKey(KeyCode.A))
transform.Translate(Vector3.left * Time.deltaTime * speed);
if (Input.GetKey(KeyCode.D))
transform.Translate(Vector3.right * Time.deltaTime * speed);
if (Input.GetKey(KeyCode.LeftControl))
speed = 15f;
lookAround();
scope();
}
void scope()
{
if (Input.GetMouseButton(1))
{
MainCamera.enabled = false;
scopeCamera.enabled = true;
ScopePNG.enabled = true;
}
else
{
MainCamera.enabled = true;
scopeCamera.enabled = false;
ScopePNG.enabled = false;
}
}
void lookAround()
{
xRotation -= Input.GetAxis("Mouse Y") * lookSensitivity;
yRotation += Input.GetAxis("Mouse X") * lookSensitivity;
transform.rotation = Quaternion.Euler(xRotation, yRotation, 0);
}
}
Here's probably the simplest solution:
void Update () {
if(Input.GetKey(KeyCode.W))
transform.Translate(Vector3.forward * Time.deltaTime*speed);
if (Input.GetKey(KeyCode.S))
transform.Translate(Vector3.back * Time.deltaTime * speed);
if (Input.GetKey(KeyCode.A))
transform.Translate(Vector3.left * Time.deltaTime * speed);
if (Input.GetKey(KeyCode.D))
transform.Translate(Vector3.right * Time.deltaTime * speed);
if (Input.GetKey(KeyCode.LeftControl))
speed = 15f;
LookAround();
Scope();
JoeFix();
}
public float fixedFloatingHeightMeters; // set to say 1.4 in the editor
private void JoeFix()
{
Vector3 p = transform.position;
p.y = fixedFloatingHeightMeters;
transform.position = p;
}
PS! you really MUST rename lookAround to LookAround and scope to Scope. It can affect things later
Here's kind of an advanced piece of information that may be more what you want. Please try this also!
Currently you have a vector that is the NOSE OF THE OBJECT pointing.
Say the thing is heading NORTH, ok?
So, transform.forward is pointing North BUT, IT IS POINTING "DOWN A BIT".
Although it is pointing north, if you saw it from the side that vector is pointing DOWN A BIT.
What you really want is that vector, but FLAT, NOT POINTING DOWN OR UP. Right?!
In fact here's the magic to do that:
Vector3 correctDirectionButPossiblyDownOrUp = transform.forward;
Vector3 correctDirectionButFlatNoDownOrUp;
correctDirectionButFlatNoDownOrUp
= Vector3.ProjectOnPlane(
correctDirectionButPossiblyDownOrUp,
Vector3.up );
correctDirectionButFlatNoDownOrUp.Normalize();
correctDirectionButFlatNoDownOrUp is now the "magic" vector you want.
But, don't forget Translate works in LOCAL SPACE. (the "object's" idea of the world.) You very much want to move it in world space, which is easy. Notice the last argument: https://docs.unity3d.com/ScriptReference/Transform.Translate.html
transform.Translate(
correctDirectionButFlatNoDownOrUp * Time.deltaTime*speed,
Space.World);
So that's it !
footnote Don't forget "Vector3.up" has absolutely no connection to "Vector3".
If you don't need the gravity then removing the RigidBody component will stop Unity applying gravity and it will hover.

Categories