How do i make a stickman's arms reach out to the mouse cursor? - unity3d

Stickman
I have this stickman here in unity 2D and i want his arms to always reach out to the direction of the mouse. I have no ideas on where i should start and i'm hoping someone here could help me out. Thanks!

Foremost, you need to determine the mouse position. It can be done with the following method:
public Vector3 GetMouseWorldPosition()
{
Vector3 mouseScreenPosition = UnityEngine.Input.mousePosition;
Vector3 mouseWorldPosition = Camera.main.ScreenToWorldPoint(mouseScreenPosition);
return mouseWorldPosition;
}
I use Camera.main here for demonstration purposes. In sake of performance it will be better to cache it as a field in your class.
Now, when you have the target coordinates, you can rotate the hand. Here is an example method:
public void RotateLimb()
{
Vector3 rotationTargetPosition = GetMouseWorldPosition();
Vector3 directionVector = (rotationTargetPosition - _limb.transform.position).normalized;
float angleInRad = Mathf.Atan2(directionVector.y, directionVector.x);
Vector3 targetAngle = _limb.transform.eulerAngles;
targetAngle.z = angleInRad * Mathf.Rad2Deg;
_limb.rotation = Quaternion.Euler(targetAngle);
}
Method RotateLimb() can be called in Update or a coroutine.
All the variables of this method can also be stored as private fields in your class.
_limb must contain Transform of your hand GameObject and you can assign it as SerializeField
[SerializeField] private Transform _limb;
_limb will rotate around its pivot. Therefore, pivot must be in the center of the shoulder. In order to achieve it, you can place all the graphics of your hand as a child of _limb and adjust it accordingly.
This seems like the most straightforward way to do it.

Related

Rotate a Rigidbody to align with an orientation

I'm currently setting the rotation of a player object so that it "stands up" relative to the spheroid the user stands on.
However, that will break Rigidbody physics.
I already have the direction of gravity as a Quaternion, how can add torque to the Rigidbody so that it aligns with that direction?
Here's my code on Github, which does allow the player to move around the surface of the planet.
I have tried various approaches using AddTorque and Vector3.Cross, but they have all only ended in the Rigidbody spinning wildly.
Instead of using transform whenever a Rigidbody is involved rather first calculate the needed final Quaternion ad then apply it using theRigidbody.MoveRotation which does not break the physics.
The same also accounts to the position where you should rather use theRigidbody.MovePosition.
Both should be used in FixedUpdate so
either move the entire code from Update to FixedUpdate
or split the input and the physics and do your API stuff in Update, store the relevant values into fields but apply anything related to the Rigidbod transformations reactive in FixedUpdate.
Your code is quite complex so I will only give an example as a pseudo code and hope you can take it from there
So instead of doing e.g.
private void Update ()
{
player.transform.position = XYZ;
// Applies a world space rotation
player.transform.rotation = XYZW;
// Adds a relative rotation in local space
player.transform.Rotate(x,y,z);
}
You would rather do something like
[SerializeField] Rigidbody playerRb;
private Vector3 targetPosition;
private Quaternion targetRotation;
private void Awake ()
{
if(!playerRb) playerRb = player.GetComponent<Rigidbody>();
}
private void Update ()
{
targetPosition = XYZ;
targetRotation = XYZW * Quaternion.Euler(x,y,z);
}
private void FixedUpdate ()
{
playerRb.MovePosition(targetPosition);
playerRb.MoveRotation(targetRotation);
}

Raycast2D hits only one side of Collider

I want to make sure that various objects moving at high speed cannot pass through walls or other objects. My thought process was to check via Raycast if a collision has occurred between two moments of movement.
So the script should remember the previous position and check via Raycast for collisions between previous and current position.
If a collision has occurred, the object should be positioned at the meeting point and moved slightly in the direction of the previous position.
My problem is that works outside the map not inside. If I go from inside to outside, I can go through the walls. From outside to inside not.
Obviously I have misunderstood something regarding the application with raycasts.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ObsticalControll : MonoBehaviour
{
private Vector3 positionBefore;
public LayerMask collisionLayer = 9;
private Vector3 lastHit = new Vector3(0, 0, -20);
// Start is called before the first frame update
void Start()
{
positionBefore = transform.position;
}
private void OnDrawGizmos()
{
Gizmos.DrawCube(lastHit, new Vector3(.2f,.2f,.2f));
}
// Update is called once per frame
void Update()
{
Vector3 curruentMovement = transform.position;
Vector2 dVector = (Vector2)transform.position - (Vector2)positionBefore;
float distance = Vector2.Distance((Vector2)positionBefore, (Vector2)curruentMovement);
RaycastHit2D[] hits = Physics2D.RaycastAll((Vector2)positionBefore, dVector, distance, collisionLayer);
if(hits.Length > 0)
{
Debug.Log(hits.Length);
for (int i = hits.Length -1 ; i >= 0 ; i--)
{
RaycastHit2D hit = hits[i];
if (hit.collider != null)
{
Debug.Log("hit");
lastHit.x = hit.point.x;
lastHit.y = hit.point.y;
Vector3 resetPos = new Vector3(hit.point.x, hit.point.y, transform.position.z) + positionBefore.normalized * 0.1f;
transform.position = new Vector3(resetPos.x, resetPos.y, transform.position.z);
}
}
}
positionBefore = transform.position;
}
}
Theres a better way to deal with this that unity has built in.
Assuming the object thats moving at a high speed has a RigidBody(2d in your case) you can set its Collision Detection to Continuous instead of Discrete.
This will help collisions with high speed collision, assuming that its moving at high speed and the wall is not moving.
If for some reason you cannot apply this to your scenario, Ill try to help with the raycast solution.
However, I am still wondering about the collision behavior of my raycast script. That would be surely interesting, if you want to calculate shots or similar via raycast
Alright, so your initial idea was to check if a collision had occurred, By checking its current position and its previous position. And checking if anything is between them, that means a collision has occurred. And you would teleport it back to where it was suppose to have hit.
A better way todo this would be to check where the GameObject would be in the next frame, by raycasting ahead of it, by the distance that it will travel. If it does hit something that means that within the next frame, it would have collided with it. So you could stop it at the collision hit point, and get what it has hit. (This means you wouldn't have to teleport it back, So there wouldn't be a frame where it goes through then goes back)
Almost the same idea but slightly less complicated.
Problem would be that if another object were to appear between them within the next frame aswell, it could not account for that. Which is where the rigidbody.movePosition shines, And with OnCollisionEnter you can detect when and what it collided with correctly. Aswell as without the need to teleport it back

How do I set the view angle of a sphere cast and also read the angle at which the objects are present in front of it?

this is what i want to achieve
I am currently trying to build a RADAR sensor on unity. I am currently using spherecast. How do i set the view angle of the sphere cast and also how do i read the angle at which an object is present in front of it.
What i have used now is Vector3.angle but this shows 160 degrees if the object is directly infront of the radar instead it should be showing 90 degrees.
Ill paste the code that i have implemented below
Any guidance is appreciated.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class spherecast : MonoBehaviour
{
Rigidbody rb;
public List<GameObject> CurrentHitObjects = new List<GameObject>();
//public GameObject curobject;
public float radius;
public float maxdist;
public LayerMask layermask;
public float velocity;
public Time deltatime;
public Vector3 previous;
private Vector3 origin;
private Vector3 direction;
private float hitdist;
// Use this for initialization
void Start()
{
foreach (GameObject cur in CurrentHitObjects)
{
previous = cur.transform.position;
}
}
// Update is called once per frame
void Update()
{
origin = transform.position;
direction = transform.forward;
hitdist = maxdist;
CurrentHitObjects.Clear();
RaycastHit[] hits = Physics.SphereCastAll(origin, radius, direction, maxdist, layermask, QueryTriggerInteraction.UseGlobal);
foreach (RaycastHit hit in hits)
{
Plane[] planes = GeometryUtility.CalculateFrustumPlanes(Camera.main);
if (GeometryUtility.TestPlanesAABB(planes, hit.collider.bounds))
{
float angle = Vector3.Angle(transform.forward, hit.point.normalized);
float degree = Mathf.Acos(angle) * Mathf.Rad2Deg;
Vector3 pos = hit.point;
Debug.Log(hit.collider.name + "position =" + pos);
CurrentHitObjects.Add(hit.transform.gameObject);
hitdist = hit.distance;
Debug.Log(hit.transform.name + "Distance ="+ hitdist);
Debug.Log(hit.collider.name + "Angle = " + angle);
velocity = ((hit.transform.position - previous).magnitude) / Time.deltaTime;
previous = hit.transform.position;
Debug.Log(hit.transform.name + "Velocity =" + velocity);
}
else
{
return ;
}
}
}
private void OnDrawGizmosSelected()
{
Gizmos.color = Color.red;
Debug.DrawLine(origin, origin + direction * hitdist);
Gizmos.DrawWireSphere(origin + direction * hitdist, radius);
}
}
As far as I can tell your code doesn't do anything. My first tip would be to remove all of your commented out code, but after that here is why your code does nothing at all:
You pass an array of objects to your script. Fine so far.
You take this entire array of objects 'CurrentHitObjects' and pass the transform.position of every single object to a single vector3. This means that all the values are overwritten except for the last one. This would be a big problem if you were trying to find the position of every single object. This would instead require vector3[]. But there is another bigger problem.
'previous', which holds transform.position of the objects is not used anywhere. So you are not actually finding the location of anything.
You use start() (which only runs once by the way) to iterate through your object array, but then you clear, CurrentHitObjects.Clear();, right at the beginning of update() (which runs many times per second by the way). The problem here, is that if you hoped to use CurrentHitObjects for anything in your code, you can't because you have wiped it before you even start doing anything with it.
Your raycast[] is shooting towards nothing. Seems to me like it just shoots forward.
You are finding the angle between the forward direction and the forward direction?
Honestly there are a lot of major problems with this code. I don't mean to be harsh, but it looks like you copy and pasted someone else's code and don't know how to use it. This needs a complete rework. If you know how to code I would throw it out and start over again. See my comment on your answer for a better way to do what you want.
If you don't know how to code, you should not be asking for freebie working code on stackoverflow. Try a unity forum instead. If you are trying to get better, see my above comments.

Camera Move and Rotate Follow Player very jerky

I make a character move on the surface of a circle. I let the camera move and rotate follow character. But the camera move and rotate very jerky. If I increase the value of the third parameter, the shock increases. and to reduce the value of the third parameter, the camera does not rotate to keep up the character. Help me fix it
My Code Camera Follow Player
public class CameraFollow : MonoBehaviour
{
public Transform player;
GameController gc;
public float speed = 2;
Vector3 pos = new Vector3 (0, 0, -10);
// Use this for initialization
void Start ()
{
gc = FindObjectOfType (typeof(GameController)) as GameController;
}
void FixedUpdate ()
{
if (gc.gameState == GameController.GameState.playing || gc.gameState == GameController.GameState.changeWave) {
transform.position = player.position + pos;
transform.rotation = Quaternion.Slerp (transform.rotation,
player.transform.rotation,
speed * Time.deltaTime);
}
}
}
Setting the position of a transform inside of FixedUpdate is a red flag for sure, especially when you're reporting that it's "jerky". Fixed update happens at an irregular interval compared to the frames displayed. This is because Physics needs to update using a fixed time step. The reason why this is the case is out of scope for this question.
Long story short, try changing FixedUpdate to Update and that should fix things looking "jerky".
Let me know if this doesn't work and I'll look for other possible causes.
If you are using a Rigidbody2D to move the character, make sure to set its Interpolate property to 'Interpolate'. This should fix it.

How can i turn the camera to left and right in unity for a sphere?

updated CODE .. the problem is that i cant move the ball only if i hold the E button than i use WASD or arrows to move the ball...and when i hold Q the camera 2 activates and i can move the ball with WASD or arrows...but with the right axis for that angle...is like ballance that game... i want to not hold the E or Q just to change the camera and move the ball corecctly for that angle with the right axis for the ball but not holding the cameras button
using UnityEngine;
using System.Collections;
public class controlPlayer : MonoBehaviour {
public float viteza ; // this is speed
;
void Start(){
}
void Update()
{
if(Input.GetKey(KeyCode.Q) ) // if i hold Q the camera 2 activates and with WASD i can move the ball
{
float miscaOrizontal = Input.GetAxis("Horizontal");
float miscaVertical = Input.GetAxis("Vertical");
Vector3 miscare = new Vector3(miscaVertical,0.0f,(-miscaOrizontal)); //also here i chande the axis for the camera 2
rigidbody.AddForce(miscare * viteza * Time.deltaTime);
}
if(Input.GetKey(KeyCode.E) ) // here when i press E the camera 1 activates and alos i can move the ball if i keep pressing E
{ float miscaOrizontal2 = Input.GetAxis("Horizontal");
float miscaVertical2 = Input.GetAxis("Vertical");
Vector3 miscare2 = new Vector3(miscaOrizontal2,0.0f,miscaVertical2); // here are the controls for the ball for the camera ..i had to change the axis here..
rigidbody.AddForce(miscare2 * viteza * Time.deltaTime);
}
}
}
}
Alright, so if I'm understanding you correctly, you want the ball to move in relation to which direction the camera is currently facing. As well as you don't want to have to hold down "Q" or "E" while you move your ball with WASD controls.
So there are a few things that I'd like to mention here, so we'll take them one at a time. First off, you shouldn't have "AddForce" inside of an Update call. Update is called every frame whenever it can. It's great for input, but generally you want to call it in "FixedUpdate" instead. It provides a better response across many devices. If you leave it in update, you can get inaccurate physics results, and missed collisions. There's a lot out there on this subject, so if you want to know more about it, then just google for a little while.
As for the code side, you want to store a reference to what camera you're using to avoid having to hold these buttons down.
What I mean is:
private Camera referencedCamera = null;
private void Start()
{
referencedCamera = camera1;
}
private void Update()
{
if(Input.GetKey(KeyCode.Q)) referencedCamera = camera2;
else if(Input.GetKey(KeyCode.E)) refrencedCamera = camera1;
}
This way you can reference which camera is being used, rather than a key input. Something else to look into is the "State Design Pattern". Below is a video over the "State Design Pattern." That is a great video tutorial series that Derek Banas put up on design patterns, extremely recommend watching them, but the state pattern could potentially solve this problem for you as well. So that should take care of not having to hold the button down in order to make the move. More or less, the buttons will now allow you to just switch which camera is currently being used.
https://www.youtube.com/watch?v=MGEx35FjBuo
So now that that is solved, you want to transform the input that you currently have, and you want to put it in terms of hte camera that is currently being used. So to avoid rewriting a lot of the code over and over again, just know that these two code snippets should be pieced together into one. So "referencedCamera" should be already defined in the code I'm about to write:
private void FixedUpdate()
{
if(referencedCamera != null)
{
float miscaOrizontal = Input.GetAxis("Horizontal");
float miscaVertical = Input.GetAxis("Vertical");
Vector3 miscare = referencedCamera.transform.TransformDirection(
new Vector3(miscaVertical, 0.0f, -miscaOrizontal));
rigidbody.AddForce(miscare * viteza * Time.deltaTime);
}
}
So now with this, is it's the same code, but there is a call to the referenced cameras transform to take the vector 3 from the input and put it in relation to the camera instead, and add the new relational vector to the object.
I also want to recommend you looking into events rather than if checks in the update function, but that is beyond the scope of the question. Hope this helps and any questions, don't hesitate to ask.
EDIT
After further discussion, we came across something that should also be mentioned. If your camera that you are referencing is angled, the force will be applied in that angle, so keep that in mind. If it is pointed towards an object downward, then forward relative to the camera will apply a force downward, and not entirely in what you may consider the forward direction. Thought it was worth mentioning.