Rotating field of view with player - c#

So I have trying to create a system that looks for a ledge to climb. I have a vertical field of view that looks for these ledges and I have, so far, got it to rotate with the analogue stick's direction, so I can find a ledge and move to it where my analogue is pointing. (Look up, find ledge, move up, etc). My problem is, while the the field of view moves where I need it to move, it stays fixed on one axis and does not rotate with the player.
In the picture the cone is facing where it should be, and rotates around the player as I want it to, but as you can see, the cone faces the X-Axis and does not move from there. I want it to rotate with the player.
In the below code, the returned Vector's y value makes the cone point upwards. I have tried all manner of functions in the x and z values, but nothing is sticking.
public Vector3 DirFromAngle(float angleInDegrees, bool angleIsGlobal)
{
if(!angleIsGlobal)
{
angleInDegrees += (viewDir + 90);
}
Vector3 newValue = new Vector3(0, Mathf.Sin(angleInDegrees * Mathf.Deg2Rad), Mathf.Cos(angleInDegrees * Mathf.Deg2Rad));
return newValue;
}
The viewDir value makes the cone rotate with my analogue stick, to make the cone rotate with my player, I assume that something needs to be done with either the x or z values, or both, but for the life of me, I can't figure it out.
Thank you for any help on this issue. Apologies if my explanation isn't very good.
void OnSceneGUI()
{
LedgePointSearch lps = (LedgePointSearch)target;
Handles.color = Color.white;
Handles.DrawWireArc(lps.transform.position, lps.transform.forward * 90, Vector3.up, 360, lps.viewRadius);
Vector3 viewAngleA = lps.DirFromAngle(-lps.viewAngle / 2, false);
Vector3 viewAngleB = lps.DirFromAngle(lps.viewAngle / 2, false);
Handles.DrawLine(lps.transform.position, lps.transform.position + viewAngleA * lps.viewRadius);
Handles.DrawLine(lps.transform.position, lps.transform.position + viewAngleB * lps.viewRadius);
}
This is the editor script that displays the field of view.
The circle simply represents the radius of the field of view, how far it goes out.
https://www.dropbox.com/s/k9siha2aog9vj8o/fov.mp4?dl=0
In the video, the circle rotates with the player, and the cone rotates with my left analogue movements. I want the cone to be like the circle, with it rotating as my player does, but still matching my analogue movements.

One way to approach this is to find the Y rotation of the player and apply it to newValue before returning it.
public Vector3 DirFromAngle(float angleInDegrees, bool angleIsGlobal)
{
if(!angleIsGlobal)
{
angleInDegrees += (viewDir + 90);
}
Vector3 newValue = new Vector3(0, Mathf.Sin(angleInDegrees * Mathf.Deg2Rad), Mathf.Cos(angleInDegrees * Mathf.Deg2Rad));
// get Y rotation of player
yRotationAngle = player.transform.rotation.eulerAngles.y;
// convert to Quaternion using only the Y rotation
Quaternion yRotation = Quaternion.Euler(0f, yRotationAngle + 90f, 0f);
// Apply yRotation
newValue = yRotation * newValue;
return newValue;
}

Related

How do I get a bullet prefab's sprite to use the same rotation as my weapon?

I'm working on a top down concept where the gun revolves around the player and flips according to the side your crosshair is on (similar to ZERO Sievert). I'm trying to have my bullet sprite have the correct rotation when firing in relation to my players weapon.
Below is how I'm instantiating the bullet in a shooting script which fires the correct way but the sprite itself is not rotated correctly.
void Shoot()
{
GameObject bullet = Instantiate(bulletPrefab, firingPoint.position, firingPoint.rotation);
Rigidbody2D rb = bullet.GetComponent<Rigidbody2D>();
rb.AddForce(firingPoint.right * bulletForce, ForceMode2D.Impulse);
}
and in my weapon handling script this is my implementation of the weapon rotation, I am flipping the weapons y scale to correct the sprite for now.
private void FixedUpdate()
{
RotateWeapon();
if (crosshair.transform.position.x < 0)
{
FlipWeapon();
}
}
void RotateWeapon()
{
float AngleRad = Mathf.Atan2(crosshair.transform.position.y - currentWeapon.transform.position.y, crosshair.transform.position.x - currentWeapon.transform.position.x);
float AngleDeg = (180 / Mathf.PI) * AngleRad;
currentWeapon.transform.rotation = Quaternion.Euler(0, 0, AngleDeg);
}
void FlipWeapon()
{
currentScale = transform.parent.localScale;
currentScale.y *= -1;
currentWeapon.transform.localScale = currentScale;
}
I'm currently at a standstill on how to achieve this as most resources I've come across for top down shooting have the player turning up to a full 360 degrees where my player only faces left or right and the weapon itself only has a range of motion of 180 degrees on either side before its set to flip.
Maybe you can try and add an offset so when you Instantiate the bullet it will look something like this:
GameObject bullet = Instantiate(bulletPrefab, firingPoint.position, firingPoint.rotation + offset);
here offset will be a rotational x y z coordinate so you would want to rotate it on the z coordinate (try all of them until you fin the right one) and rotate it either -90 degrees or 90 deegrees. You might have to rotate it 180 degress but dont use 270 instead use -90. Trust me it will help in your later days in coding. Also make sure to set offset as a variable:
private Vector3 offset = 0, 0, -90;
!Remember you can change the x y z coordinates!

How to rotate an object along all 3 axes with finger swipe?

I'm working on a simple AR Vuforia application. How can I implement the rotation of an object along all three axes with one finger swipe?
The code I'm currently using has one bug: the rotation of the object depends on its local axes. For example, if I look at the object from the front, everything works as it should, but if I look at the object from the back side, the finger swipe upwards makes it rotate downwards and vice versa.
Here is this script:
public float rotSpeed = 30f;
void OnMouseDrag()
{
float rotX = Input.GetAxis("Mouse X")*rotSpeed*Mathf.Deg2Rad;
float rotY = Input.GetAxis("Mouse Y")*rotSpeed*Mathf.Deg2Rad;
transform.Rotate(Vector3.up, -rotX);
transform.Rotate(Vector3.right, -rotY);
}
This is not what I need, how can I rotate the object according to the finger swipe direction regardless of the angle from which I look at it?
Update
A simple non-AR example, which may help you understand what I need is an iOS game "Space Frontier 2". After a successful launch of the rocket, it lands on the planet and you can rotate the planet with your finger swipe.
Here is the video demo: https://youtu.be/OiNPP1WNIAI
This works nice regardless of your object's rotation, and regardless of your camera position relative to the object:
public float rotSpeed = 30f;
void OnMouseDrag()
{
float rotX = Input.GetAxis("Mouse X") * rotSpeed;
float rotY = Input.GetAxis("Mouse Y") * rotSpeed;
Camera camera = Camera.main;
Vector3 right = Vector3.Cross(camera.transform.up, transform.position - camera.transform.position);
Vector3 up = Vector3.Cross(transform.position - camera.transform.position, right);
transform.rotation = Quaternion.AngleAxis(-rotX, up) * transform.rotation;
transform.rotation = Quaternion.AngleAxis(rotY, right) * transform.rotation;
}
Make sure your camera has the "MainCamera" tag, or assign the camera externally if necessary.
I do not have the exact code with me right now.
But if you did not update your point of view coordinates, this should be the expected result.
Consider a real ball with 2 colors, blue and red, separated vertically.
When you are in front of it, seeing only the blue side, stroking it up will make the blue side go up and the red side appear from the bottom.
Now move behind it, seeing only the red side, and stroke it up again.
The blue face will go down and appear from the bottom.
Unity applies physics to virtual objects the same way we interact with real objects.
So you need to consider your camera position with the object orientation when you apply movements to it.
You need to apply a transformation matrix to your movement based on your camera location related to the object origin orientation.
I hope this is clear enough to put you on tracks to fix it.
I think you have to somehow clamp the rotation to have the desired behaviour. I wrote a script recently to do just that. I did a little modification though.
public float rotSpeed = 30f;
float ClampAngle(float _angle, float _min, float _max)
{
if (_angle < 0f) _angle = 360 + _angle;
if (_angle > 180f) Mathf.Max(_angle, 360 + _min);
return Mathf.Min(_angle, _max);
}
USAGE:
void RotateGameObject()
{
float h = Input.GetTouch(0).deltaPosition.x * Time.deltaTime * rotSpeed*Mathf.Deg2Rad;
float v = Input.GetTouch(0).deltaPosition.y * Time.deltaTime * rotSpeed*Mathf.Deg2Rad;
Vector3 rot = transform.rotation.eulerAngles + new Vector3(-v, h, 0f);
//Change the y & z values to match your expected behaviour.
rot.x = ClampAngle(rot.x, -5f, 20f);
//Clamp rotation on the y-axis
rot.y = ClampAngle(rot.y, -20f, 20f);
transform.eulerAngles = rot;
}
See if that works and of course, try to play with the values.

Gyroscope with compass help needed

I need to have a game object point north AND I want to combine this with gyro.attitude input. I have tried, unsuccessfully, to do this in one step. That is, I couldn't make any gyro script, which I found on the net, work with the additional requirement of always pointing north. Trust me, I have tried every script I could find on the subject. I deduced that it's impossible and probably was stupid to think it could be done; at least not this way (i.e. all-in-one). I guess you could say I surmised that you can't do two things at once. Then I thought possibly I could get the same effect by breaking-up the duties. That is, a game object that always points north via the Y axis. Great, got that done like this:
_parentDummyRotationObject.transform.rotation = Quaternion.Slerp(_parentDummyRotationObject.transform.rotation, Quaternion.Euler(0, 360 - Input.compass.trueHeading, 0), Time.deltaTime * 5f);
And with the game object pointing north on the Y, I wanted to add the second game-object, a camera in this case, with rotation using gyro input on the X and Z axis. The reason I have to eliminate the Y axes on the camera is because I get double rotation. With two things rotating at once (i.e. camera and game-object), a 180 degree rotation yielded 360 in the scene. Remember I need the game object to always point north (IRL) based on the device compass. If my device is pointing towards the East, then my game-object would be rotated 90 degrees in the unity scene as it points (rotation) towards the north.
I have read a lot about gyro camera controllers and one thing I see mentioned a lot is you shouldn't try to do this (limit it) on just 1 or 2 axis, when using Quaternions it's impossible when you don't know what you're doing, which I clearly do not.
I have tried all 3 solutions from this solved question: Unity - Gyroscope - Rotation Around One Axis Only and each has failed to rotate my camera on 1 axis to satisfy my rotational needs. Figured I'd try getting 1 axis working before muddying the waters with the 2nd axis. BTW, my requirements are simply that the camera should only rotate on 1 axis (in any orientation) based on the X axis of my device. If I could solve for X, then I thought it'd be great to get Z gyro input to control the camera as well. So far I cannot get the camera controlled on just 1 axis (X). Anyway, here are my findings...
The first solution, which used Input.gyro.rotationRateUnbiased, was totally inaccurate. That is, if I rotated my device around a few times and then put my phone/device down on my desk, the camera would be in a different rotation/location each time. There was no consistency. Here's my code for the first attempt/solution:
<code>
private void Update()
{
Vector3 previousEulerAngles = transform.eulerAngles;
Vector3 gyroInput = Input.gyro.rotationRateUnbiased;
Vector3 targetEulerAngles = previousEulerAngles + gyroInput * Time.deltaTime * Mathf.Rad2Deg;
targetEulerAngles.y = 0.0f;
targetEulerAngles.z = 0.0f;
transform.eulerAngles = targetEulerAngles;
}
</code>
The second solution was very consistent in that I could rotate my device around and then put it down on the desk and the unity camera always ended up in the same location/rotation/state so-to-speak. The problem I had was the camera would rotate on the one axis (X in this case), but it did so when I rotated my device on either the y or x axis. Either type of rotation/movement of my phone caused the unity camera to move on the X. I don't understand why the y rotation of my phone caused the camera to rotate on X. Here is my code for solution #2:
private void Start()
{
Input.gyro.enabled = true;
startEulerAngles = transform.eulerAngles;
startGyroAttitudeToEuler = Input.gyro.attitude.eulerAngles;
}
private void Update()
{
Vector3 deltaEulerAngles = Input.gyro.attitude.eulerAngles - startGyroAttitudeToEuler;
deltaEulerAngles.y = 0.0f;
deltaEulerAngles.z = 0.0f;
transform.eulerAngles = startEulerAngles - deltaEulerAngles;
}
The 3rd solution: I wasn't sure how to complete this last solution, so it never really worked. With the 2 axis zeroed-out, the camera just flipped from facing left to right and back, or top to bottom and back; depending on which axis were commented out. If none of the axis were commented-out (like the original solution) the camera would gyro around on all axis. Here's my code for attempt #3:
private void Start()
{
_upVec = Vector3.zero;
Input.gyro.enabled = true;
startEulerAngles = transform.eulerAngles;
}
private void Update()
{
Vector3 gyroEuler = Input.gyro.attitude.eulerAngles;
phoneDummy.transform.eulerAngles = new Vector3(-1.0f * gyroEuler.x, -1.0f * gyroEuler.y, gyroEuler.z);
_upVec = phoneDummy.transform.InverseTransformDirection(-1f * Vector3.forward);
_upVec.z = 0;
// _upVec.x = 0;
_upVec.y = 0;
transform.LookAt(_upVec);
// transform.eulerAngles = _upVec;
}
Originally I thought it was my skills, but after spending a month on this I'm beginning to think that this is impossible to do. But that just can't be. I know it's a lot to absorb, but it's such a simple concept.
Any ideas?
EDIT: Thought I'd add my hierarchy:
CameraRotator (parent with script) -> MainCamera (child)
CompassRotator (parent) -> Compass (child with script which rotates parent)
I'd do this in the following way:
Camara with default 0, 0, 0 rotation
Screenshot
Object placed at the center of the default position of the camera.
Script for the Camera:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class NewBehaviourScript : MonoBehaviour
{
Camera m_MainCamera;
// Start is called before the first frame update
void Start()
{
// Disable the sleep timeout during gameplay.
// You can re-enable the timeout when menu screens are displayed as necessary.
Screen.sleepTimeout = SleepTimeout.NeverSleep;
// Enable the gyroscope.
if (SystemInfo.supportsGyroscope)
{
Input.gyro.enabled = true;
}
m_MainCamera = Camera.main;
m_MainCamera.enabled = true;
}
// Update is called once per frame
void Update()
{
if (m_MainCamera.enabled)
{
// First - Grab the Gyro's orientation.
Quaternion tAttitude = Input.gyro.attitude;
// The Device uses a 'left-hand' orientation, we need to transform it to 'right-hand'
Quaternion tGyro = new Quaternion(tAttitude.x, tAttitude.y, -tAttitude.z, -tAttitude.w);
// the gyro attitude is tilted towards the floor and upside-down reletive to what we want in unity.
// First Rotate the orientation up 90deg on the X Axis, then 180Deg on the Z to flip it right-side up.
Quaternion tRotation = Quaternion.Euler(-90f, 0, 0) * tGyro;
tRotation = Quaternion.Euler(0, 0, 180f) * tRotation;
// You can now apply this rotation to any unity camera!
m_MainCamera.transform.localRotation = tRotation;
}
}
}
With this script my Object always face SOUTH no matter what.
If you want the object to face NORTH you just have to turn the view 180ยบ on the Y axis as a last rotation:
Quaternion tRotation = Quaternion.Euler(-90f, 0, 0) * tGyro;
tRotation = Quaternion.Euler(0, 0, 180f) * tRotation;
//Face NORTH:
tRotation = Quaternion.Euler(0,180f, 0) * tRotation;
Hope this might help ;)

Unity2D Enemy Patrol, weird sprite rotation

Needed help here, I've been following this tutorial about Enemy Patrolling, https://www.youtube.com/watch?v=KKU3ejp0Alg
The tutorial tell us to set 2 Empty Game Objects and the coordinates so the sprite will walk from one direction to another, the walking does working, however the rotation of the sprite became really weird, the 'Worm' sprite is suppose to move left and right now it change into facing upward
Please look at this image,
When moving from left to right
When moving from right to left
public Transform[] patrolPoints;
public float speed;
Transform currentPatrolPoint;
int currentPatrolIndex;
// Use this for initialization
void Start()
{
currentPatrolIndex = 0;
currentPatrolPoint = patrolPoints[currentPatrolIndex];
}
// Update is called once per frame
void Update()
{
transform.Translate(Vector3.up * Time.deltaTime * speed);
if (Vector3.Distance(transform.position, currentPatrolPoint.position) < .1f) {
if (currentPatrolIndex + 1 < patrolPoints.Length)
currentPatrolIndex++;
else
currentPatrolIndex = 0;
currentPatrolPoint = patrolPoints[currentPatrolIndex];
}
Vector3 patrolPointDir = currentPatrolPoint.position - transform.position;
float angle = Mathf.Atan2(patrolPointDir.y, patrolPointDir.x) * Mathf.Rad2Deg - 90f;
Quaternion q = Quaternion.AngleAxis(angle, Vector3.forward);
transform.rotation = Quaternion.RotateTowards(transform.rotation, q, 180f);
}
This is the code
Thank you
You can pass the optional parameter Space.World to your translation to move your object relative to world space instead of object space. That should prevent your object from rotating.
transform.Translate(Vector3.up * Time.deltaTime * speed, Space.World);
You can read more about it in the documentation.
You probably rotated the enemy sprite by 90 degrees. Try placing all your scripts into empty game object with no rotation, than place the enemy sprite as child of the empty game object and rotate as you need. This way your logic won't collide with your graphics.

Unity - Sprite Rotation + Get Angle

Im trying to get a sprite rotation by key input (arrow down or up).
The point is lifting the arrow (sprite) to choose the angle. Its like a system of a golf game, actually.
So far i tried:
void Update () {
if (Input.GetKey(KeyCode.UpArrow)){
transform.Rotate (Vector3.forward * -2); }
if (Input.GetKey(KeyCode.DownArrow)){
transform.Rotate (Vector3.forward * +2); }
}
I will need the angle, since it will be related to a "shot" part i will be doing next. My point is setting the right angle with the keys up and down.
I can move the "arrow" sprite with my code, but i cannot set the max angle (90), minimum (0) and get the angle to use in the shot ^^
Hard question to answer without just simply giving you the code. This code works by assuming your character's forward vector is actually it's right vector (common in 2d sprite games) in order to shoot in the other direction, rotate your objects y axis 180.
float minRotation = 0f;
float maxRotation = 90f;
float rotationSpeed = 40f; //degrees per second
//get current rotation, seeing as you're making a sprite game
// i'm assuming camera facing forward along positive z axis
Vector3 currentEuler = transform.rotation.eulerAngles;
float rotation = currentEuler.z;
//increment rotation via inputs
if (Input.GetKey(KeyCode.UpArrow)){
rotation += rotationSpeed * Time.deltaTime;
}
else if (Input.GetKey(KeyCode.DownArrow)){
rotation -= rotationSpeed * Time.deltaTime;
}
//clamp rotation to your min/max
rotation = Mathf.Clamp(rotation, minRotation, maxRotation );
//set rotation back onto transform
transform.rotation = Quaternion.Euler( new Vector3(currentEuler.x, currentEuler.y, rotation));
If you were making a golf game, you'd set the ball's velocity to be transform.right * shotPower

Categories

Resources