Reputation: 507
I was advised to use State Machine seen in this link the first answer:
But I'm not sure if I need that for now. My problem should be easier to solve I think, and I also don't understand how to use the State Machine.
The first part, using the RaycastHit
and the LookAt
is currently rotating and facing the mouse position whenever I move my mouse around the character. This part should be my default idle state when I'm running the game where each time the player is walking and reaching the target point (mouse clicked position).
To clarify, the other two states are Idle
and Walking
; both are animation states using HumanoidWalk
and HumanoidIdle
. When I click the mouse button, the player will "Walk" toward the target; the clicked mouse position and when it has reached there it will enter the Idle
state. Also it will return to the LookAt
mode again so that I will be able to move the mouse around and the character will rotate/face the mouse position.
However, what I'm getting currently is when the character has reached the mouse-clicked point, he begins to rotate nonstop. If I move the mouse around, the player will start walking and following the mouse movement. This is not what I want.
I tried to change the distance from 1.0f
, 2.0f
and 3.0f
for testing, but it didn't solve any of the problems.
The main Idle
state when running the game and when the character is reaching the mouse-clicked position should be somehow combine with this part:
RaycastHit hit;
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(ray, out hit) && hit.collider.name != "ThirdPersonController")
{
transform.LookAt(hit.point);
}
else
{
transform.LookAt(ray.GetPoint(100));
}
With the Idle state:
_animator.CrossFade("Idle", 0);
This is the script:
using UnityEngine;
using System.Collections;
public class MoveObjects : MonoBehaviour {
private Animator _animator;
void Start()
{
_animator = GetComponent<Animator>();
_animator.CrossFade("Idle", 0);
}
void Update()
{
MovePlayerWithMouse();
}
private void MovePlayerWithMouse()
{
RaycastHit hit;
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(ray, out hit) && hit.collider.name != "ThirdPersonController")
{
transform.LookAt(hit.point);
}
else
{
transform.LookAt(ray.GetPoint(100));
}
if (Input.GetMouseButtonDown(0))
{
if ((transform.position - hit.point).magnitude < 1.0f)
{
_animator.CrossFade("Idle", 0);
}
else
{
_animator.CrossFade("Walk", 0);
}
}
}
Upvotes: 1
Views: 104
Reputation: 596
It seems like the player doesn't seem to "know" it has gotten to the point. If it tries to look at a point within itself, it WILL spin erratically, trying to rotate towards the point at it's feet.
I would advise looking at the condition for when the character reaches its destination, and debug whether the current state in the fsm changes when it does reach the destination and if it is in the "Idle" state when you expect it to be. If it's not, I would revise the condition.
Plus, don't use collider string comparisons for raycasts, it gets slow and cumbersome fast. I would have a separate controller (that is executed first in the game loop execution order menu) that sets the collision matrix on what to ignore.
https://docs.unity3d.com/Manual/LayerBasedCollision.html
this is the editor menu, but can be accessed in game. In this controller, I would THEN set the layer names, and add the collision exceptions here.
If you need a "one off" exception for ignoring collisions, use a layermask that goes in the format: 1 << layerNumber.
You can get the layernumber from the layertag in code as well. This basically works by having a single integer represent whether collisions should be ignored or not for EVERY layer (max of 32 layers, as an int has 32 bits). Every bit can be a 1 (to ignore) or 0 (to detect collisions on that layer). You can combine multiple layermasks by using a bitwise & (which basically combines any 1's from each anded integer) to get the final result of all the layers you want to ignore.
Upvotes: 1