My player no longer moves correctly

I’m currently taking the RPG core combat course, and since I implemented the logic we were taught in lesson 29, my player no longer constantly follows the mouse, it casts a ray to the mouse location and starts rotating toward it but doesn’t move there until I release the mouse button. I am currently stuck and have no idea what to do so any help at all will be greatly appreciated. Here is my code below:

PlayerController;

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using RPG.Movement;
using RPG.Combat;

namespace RPG.Control
{
  public class PlayerController : MonoBehaviour
  {

    void Start()
    {
    }

    void Update()
    {
      if(ApplyCombat()) return;
      if (ApplyMovement()) return;
      print("Nowhere to go");
    }

    private bool ApplyCombat()
    {
      RaycastHit[] hits = Physics.RaycastAll(GetMouseRay());
      foreach (RaycastHit hit in hits)
      {
           AttackTarget target = hit.transform.GetComponent<AttackTarget>();
           if (target == null) continue;
           if (Input.GetMouseButtonDown(0))
           {
               GetComponent<Fighting>().Attack(target);
           }
           return true;
      }
            return false;
    }



    private bool ApplyMovement()
    {
      RaycastHit hitInfo;
      bool hasHit = Physics.Raycast(GetMouseRay(), out hitInfo);
      if (hasHit)
      {
           if (Input.GetMouseButton(0))
           {
               GetComponent<PlayerMovement>().StartMovementAction(hitInfo.point);
           }
           return true;
      }
      return false;
    }

    public static Ray GetMouseRay()
    {
      return Camera.main.ScreenPointToRay(Input.mousePosition);
    }
  }
}

Mover;

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;
using RPG.Combat;
using RPG.Core;

namespace RPG.Movement
{
  public class PlayerMovement : MonoBehaviour
{
  NavMeshAgent _navMeshAgent;

  void Start()
  {
    _navMeshAgent = GetComponent<NavMeshAgent>();
  }

  void Update()
  {
       UpdateAnimator();
  }

  public void StartMovementAction(Vector3 destination)
  {
     GetComponent<ActionScheduler>().StartMovementAction(this);
     GetComponent<Fighting>().Cancel();
     MoveTo(destination);
  }

  public void MoveTo(Vector3 destination)
  {
    _navMeshAgent.destination = destination;
    _navMeshAgent.isStopped = false;
  }

  public void Stop()
  {
    _navMeshAgent.isStopped = true;
  }

  private void UpdateAnimator()
  {
    Vector3 velocity = _navMeshAgent.velocity;
    Vector3 localVelocity = transform.InverseTransformDirection(velocity);
    float speed = localVelocity.z;
    GetComponent<Animator>().SetFloat("forwardSpeed", speed);
  }
}
}

Fighter;

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using RPG.Movement;
using RPG.Core;

namespace RPG.Combat
{
   public class Fighting : MonoBehaviour
{

   Transform target;
   private PlayerMovement playerMovement;

   void Update()
   {
      if(target == null) return;
      playerMovement = GetComponent<PlayerMovement>();
      if (!GetIsInRange())
      {
        playerMovement.MoveTo(target.position);
      }
      else
      {
        playerMovement.Stop();
      }
   }



   public void Attack(AttackTarget attackTarget)
   {
      GetComponent<ActionScheduler>().StartMovementAction(this);
      target = attackTarget.transform;
   }

   public void Cancel()
   {
      target = null;
   }

   private bool GetIsInRange()
   {
      return Vector3.Distance(transform.position, target.position) <= 2f;
   }
}
}

Thanks in advance :grin:

I’m going to add in the ActionScheduler for completeness from your post on Udemy:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

namespace RPG.Core
{
    public class ActionScheduler : MonoBehaviour
    {
        MonoBehaviour currentAction;
        public void StartMovementAction(MonoBehaviour action)
        {
            if (currentAction == action) return;
            if (currentAction != null)
            {
                print("Cancelling" + currentAction);
            }
            currentAction = action;
        }
    }
}

With the exception of the reference to Fighter within the Mover script, everything looks ok here, including the ActionScheduler, which gives us a bit of a puzzler.
Can you paste a screenshot of your player’s Inspector?

Right away


playerinspector2

Once again everything appears to be correct.
Zip up your project and upload it to https://gdev.tv/projectupload and I’ll take a closer look. Be sure to remove the Library folder to conserve space.

Okay, will do.

I am trying to compress the project but can’t as I keep getting this error, I’m not sure what to do. Really sorry if I’m being a bother
error

That’s an odd one… technically, the .git folder is hidden, but really nothing in the project folder should have read permission denied (or Unity wouldn’t be able to use it).

Try these steps:
Make sure Unity is closed and navigate to the project folder.
Create a new empty Zip file and open it in a new window.
From within your project folders, drag in any files that are not in a subfolder
From within your project folder, one at a time, drag in the following folders, if they exist in your project:

  • Assets
  • Logs
  • obj
  • Packages
  • Project Settings
  • UIElementsSchema
  • UserSettings

Dragging in all files and then dragging in their parent folders means there are duplicate files in the zipped folder, should I proceed?

If you’re starting with an empty zip, that’s sort of confusing that this would happen…

  • Empty Zip, open in new window, project window is still open

  • Drag files NOT in a subfolder from project window to zip window (they will now exist in both windows, at this point, there should be no subfolders in your zip

  • From within project folder, drag above listed folders one by one into the zipped project if they exist (not all projects have all folders, much like not all projects will have all the files in my example

That did the trick, thank you! I’ve uploaded the project

This one took me a bit longer to solve than it should have, as it has to do with the way that the NavMeshSurface deals with agents that are collected by it’s system.

The way your project was set up, the terrain, a GameObject containing buildings, and a GameObject containing props were all at the root of the heirarchy. The NavMeshSurface was on the Terrain. The Surface was set to consider all objects within the scene.

Apparently, when this happens, NavMeshAgents carve a spot into the NavMesh in real time, so when a path is calculated, it takes these realtime carves into consideration and the time it takes to calculate a path is drastically longer. This means we need our NavMeshAgents (players and enemies) to NOT be collected as NavMesh data.

The solution for this is to create an empty GameObject at the root of the scene for all scene geometry. I call mine Environment.

  • Drag the Terrain into the new Environment GameObject, and remove the NavMeshSurface from the Terrain
  • Drag the Buildings and Props GameObjects into the Game folder.
  • Put a new NavMeshSurface on the Environment, and set it’s Collect Objects dropdowns to Current Object Heirarchy
  • Rebake your NavMesh
  • Be sure not to put enemies or the player within the Environment object.

    This is something to do with the new NavMeshSurface (in fact, older versions of the Surface didn’t have this requirement at all). It’s something I’ll need to ensure goes in any future version of the course.
1 Like

Thank you so much! That fixed the first issue, but now my player does not move to the enemy when I click on it anymore, I will check my script to see if there are any issues there

Privacy & Terms