How to limit/Clamp RotateAround for camera movement in Unity? - c#

I have a scene with a globe, where the camera rotates around the globe. I need to clamp the position and rotation of this movement in certain instances of the game. I have tried several methods but none have worked. My code is below:
private void LateUpdate()
{
if (Input.GetMouseButtonDown(1))
mouseStartPosition = GetMouseHit();
if (mouseStartPosition != null)
DragPlanet();
if (Input.GetMouseButtonUp(1))
StaticPlanet();
}
public void RotateCamera(Vector3 dragStartPosition, Vector3 dragEndPosition)
{
//normalised for odd edges
dragEndPosition = dragEndPosition.normalized *planetRadius;
dragStartPosition = dragStartPosition.normalized * planetRadius;
// Cross Product
Vector3 cross = Vector3.Cross(dragEndPosition, dragStartPosition);
// Angle for rotation
float angle = Vector3.SignedAngle(dragEndPosition, dragStartPosition, cross);
//Causes Rotation of angle around the vector from Cross product
holderTransform.RotateAround(planet.transform.position, cross, angle);
}
private static Vector3? GetMouseHit()
{
RaycastHit hit;
int layer_mask = LayerMask.GetMask("Planet"); //raycasting on the planet
if (Physics.Raycast(Camera.main.ScreenPointToRay(Input.mousePosition), out hit, Mathf.Infinity, layer_mask))
{
return hit.point;

Related

Drawing a sprite on Raycast collision point

I am trying to emit a raycast from the player object and project a crosshair texture onto the world position the crosshair is aimed at. The crosshair should not overlap with the player and it should also only be emited in front of the Player gameObject.
I have tried this so far:
private float range = 100f;
public Texture crosshair;
private Rect crosshairPos;
void Update()
{
if (Input.GetKeyDown(KeyCode.Space))
{
Shoot();
}
Ray ray = new Ray(transform.position, transform.forward);
crosshairPos.x = ray.GetPoint(100f).x;
crosshairPos.y = ray.GetPoint(100f).y;
Graphics.DrawTexture(crosshairPos, crosshair);
Edit: After some testing, I am currently on the following snippet of code:
void Update()
{
if (Input.GetKeyDown(KeyCode.Space))
{
Shoot();
}
Ray ray = new Ray(transform.position, transform.forward);
crosshairPos.x = ray.GetPoint(5f).x;
crosshairPos.y = ray.GetPoint(5f).y;
crosshairPos = Camera.main.WorldToScreenPoint(crosshairPos);
Vector2 crosshairPosSize = new Vector2(crosshair.width, crosshair.height);
Graphics.DrawTexture(new Rect((Vector2)crosshairPos, crosshairPosSize), crosshair);
}
I am however still unable to see a projected crosshair.
When you use a Ray from a GameObject you get a Vector in the world coordinate system. (The game world where your player is).
Graphics.DrawTexture() uses screen coordinates to draw the texture on screen.
Consider using Camera.Main.WorldToScreenPoint to change the world points that you get from Ray into points you can display on screen.
Here's an example of that
Vectors crosshairPos = new Vector3();
void Update()
{
if (Input.GetKeyDown(KeyCode.Space))
{
Shoot();
}
Ray ray = new Ray(transform.position, transform.forward);
crosshairPos.x = ray.GetPoint(100f).x;
crosshairPos.y = ray.GetPoint(100f).y;
crosshairPos = Camera.Main.WorldToScreenPoint(crosshairPos);
Graphics.DrawTexture((Vector2)crosshairPos, crosshair);
}

How to face character in its movement direction and at the same time keep it aligned to any surface?

I want to move my player character(human) on a curved surface. But at the same time character shall stay perpendicular to the surface normals and it should face in the movement direction and can handle collisions(if there is a wall ahead, shall not be able to go through it).
I tried to make a parent stay over normals and change the child local rotation towards direction of motion of its parent. But it has several limitations as of now.
Here is the code what i was using:
[SerializeField] float raycastLength = 1f;
bool canPlayerMove = true;
public float speed = 2f;
public Vector3 offset; //object's position offset to ground / surface
public Quaternion childDirection;
private void Update()
{
float moveHorizontal = SimpleInput.GetAxis("Horizontal");
float moveVertical = SimpleInput.GetAxis("Vertical");
Ray ray = new Ray(transform.position, -transform.up);
RaycastHit hitInfo;
if (Physics.Raycast(ray, out hitInfo, raycastLength))
{
transform.rotation = Quaternion.LookRotation(Vector3.up, hitInfo.normal);
transform.position = hitInfo.point + offset;
Debug.DrawLine(ray.origin, hitInfo.point, Color.red);
}
if (canPlayerMove)
{
Vector3 movement = new Vector3(moveHorizontal, 0, moveVertical);
if (movement != Vector3.zero)
{
childDirection = Quaternion.Slerp(transform.GetChild(0).localRotation, Quaternion.LookRotation(movement), 0.15F);
transform.GetChild(0).localRotation = childDirection;
}
transform.Translate(movement * speed * Time.deltaTime, Space.Self);
}
}
first to not make your player go thru walls you want to add a collider to your walls and not set it as trigger, you will also need a rigidbody on your player and this will help in the next steps.
Secondly you will need to acces the rigidBody in code using this: (if you Check Use Gravity it will also stay on your terrain that you made)
private Rigidbody rb;
private float speed = 7.5f;
private void Start()
{
//this gets the rigidbody on the gameObject the script is currently on.
rb = this.GetComponent<Rigidbody>();
}
private void Update()
{
float hor = Input.GetAxis("Horizontal");
float vert = Input.GetAxis("Vertical");
//this will move your player frame independent.
rb.MovePosition(this.transform.position + new Vector3(hor, 0, vert) * speed *
Time.deltaTime);
}
Also make sure that you have a rigidBody on your player, else it will throw an error.

Rotation of player is slightly off

I new to unity / c# and need some help with the rotation of my player. While I hold the mouse cursor on the positive y-axis (if the middle of the player is 0) the player faces slightly above the cursor and while on the negative y-axis the player faces slightly below the cursor. Here is a gif to demonstrate:
https://gyazo.com/e417962c20e186f3c6419c23bf8263f6
Here is my code for rotation.
public class LookTowardMouse : MonoBehaviour
{
void Update()
{
//Get the Screen positions of the object
Vector2 positionOnScreen = Camera.main.WorldToViewportPoint(transform.position);
//Get the Screen position of the mouse
Vector2 mouseOnScreen = (Vector2)Camera.main.ScreenToViewportPoint(Input.mousePosition);
//Get the angle between the points
float angle = AngleBetweenTwoPoints(positionOnScreen, mouseOnScreen);
//Rotate player
Debug.Log(angle);
transform.rotation = Quaternion.Euler(new Vector3(0f, 0f, angle));
}
float AngleBetweenTwoPoints(Vector3 a, Vector3 b)
{
return Mathf.Atan2(a.y - b.y, a.x - b.x) * Mathf.Rad2Deg;
}
}

How do I correct the direction of my vector to the rotation of the camera?

For a 3D first person controller game, I am converting a swipe on the screen in a direction vector.
An object is shot into this direction.
My camera can rotate based on the input of a virtual joystick.
When I don't rotate and shoot the object using swipe it goes in the right direction.
However when I rotate the camera it doesn't go in the intended direction.
The direction should be adapted to the rotation of the camera.
How do I correct the direction of my vector to the rotation of the camera?
PS: Message me for further clarification
//Converting swipe direction to 3D direction
public class TouchPair
{
public Vector2 startPos;
public int fingerId;
}
private TouchPair touchPair;
void Update()
{
foreach (Touch touch in Input.touches)
{
Vector2 touchPos = touch.position;
if (touch.phase == TouchPhase.Began)
{
Ray ray = cam.ScreenPointToRay(touchPos);
RaycastHit hit;
if (Physics.Raycast(ray, out hit))
{
//The player is wielding a bomb that is visible on the screen.
//only swipes that start from this object should count
if (hit.transform.tag == "Bomb")
{
touchPair = new TouchPair();
touchPair.startPos = touchPos;
touchPair.fingerId = touch.fingerId;
}
}
}
else if (touch.phase == TouchPhase.Ended)
{
if (touchPair.fingerId == touch.fingerId)
{
Vector2 endPos = touchPos;
Vector2 swipeDirectionRaw = endPos - touchPair.startPos;
float magnitude = swipeDirectionRaw.magnitude;
if (magnitude >= minSwipeLength)
{
BombController BombController = GameObject.FindWithTag("Bomb").GetComponent<BombController>();
BombController.Throw(swipeDirectionRaw.normalized, magnitude);
}
}
}
}
}
public void Throw(Vector2 direction, float magnitude)
{
//Setup variables for throw
throwDirection = new Vector3(direction.x, 0.0f, direction.y);
throwSpeed = magnitude * throwForce;
}
You need raycast with ground when touch.phase == TouchPhase.Ended then get direction from your character to raycast.hit.
Raycasthit hitInfo;
Physic.Raycast;
I had to get the view vector of the camera. By taking the amount of angles
between the player's forward and the camera's view vector the amount of angles is received that is required to get a correct direction vector.
Finally rotate the shoot direction by this amount of angles.
Vector2 endPos = touchPos;
Vector2 swipeDirectionRaw = endPos - touchPair.startPos;
float magnitude = swipeDirectionRaw.magnitude;
swipeDirectionRaw.Normalize();
if (magnitude >= minSwipeLength)
{
GameObject player = GameObject.FindWithTag("Player");
Vector3 shootOrigin = player.transform.position;
Vector3 uncorrectedShootDirection = new Vector3(swipeDirectionRaw.x, 0.0f, swipeDirectionRaw.y);
Vector3 originVector = player.transform.forward;
Vector3 viewVector = cam.transform.forward;
//Shoot direction gets corrected by angle between origin- and view vector
float angleBetweenOriginAndView = Vector3.Angle(originVector, viewVector);
//There is no clockwise or counter-clockwise in 3d space,
//hence mirroring is needed. In my case it's done to what suits my needs
if (viewVector.x < 0.0f)
{
angleBetweenOriginAndView *= -1f;
}
Vector3 correctedShootDirection = Quaternion.Euler(0, angleBetweenOriginAndView, 0) * uncorrectedShootDirection;
}
touchPair = null;
}

Move the camera only until a certain position

https://scontent.fmgf1-2.fna.fbcdn.net/v/t34.0-12/15870843_1543174992374352_1359602831_n.gif?oh=dc048c9e04617007c5e82379fd5a9c1a&oe=586CC623
Can you see the blue area in this gif? I want block the camera when the player go more to left, to not see the blue area. This is the code that I'm using to move the camera:
public class configuracoesDaCamera : MonoBehaviour {
Vector3 hit_position = Vector3.zero;
Vector3 current_position = Vector3.zero;
Vector3 camera_position = Vector3.zero;
float z = 0.0f;
public static bool bDedoNoHud;
void Update()
{
if (Input.GetMouseButtonDown(0))
{
hit_position = Input.mousePosition;
camera_position = transform.position;
}
if (Input.GetMouseButton(0))
{
current_position = Input.mousePosition;
LeftMouseDrag();
}
Debug.Log("bDedoNoHud" + bDedoNoHud);
}
void LeftMouseDrag()
{
if (!bDedoNoHud)
{
// From the Unity3D docs: "The z position is in world units from the camera." In my case I'm using the y-axis as height
// with my camera facing back down the y-axis. You can ignore this when the camera is orthograhic.
current_position.z = hit_position.z = camera_position.y;
// Get direction of movement. (Note: Don't normalize, the magnitude of change is going to be Vector3.Distance(current_position-hit_position)
// anyways.
Vector3 direction = Camera.main.ScreenToWorldPoint(current_position) - Camera.main.ScreenToWorldPoint(hit_position);
// Invert direction to that terrain appears to move with the mouse.
direction = direction * -1;
Vector3 position = camera_position + direction;
transform.position = position;
}
}
}
You mean setting up boundaries?
This should help you
Put it in the update()

Categories