RPG Core Combat Cancelling Actions using ActionScheduler?

Hello,

I mostly purchased this course for the inventory, stats, ability, and combat aspects. In the past i have already made point to click RPG type games. However this type of “ActionScheduler” that they are introducing is new to me from other games I have made. And admittedly, I have gone a more, bloaty, if/else route in the past. My problem is this: I am trying to adapt the movement mechanics, point and click, into WSAD movement. So far through the lecture I have adapted everything perfectly. Moving, camera follow, being out of range of attack, and manually moving myself in range, and then being able to attack, etc. But my problem comes with the ActionScheduler, specifically for starting and cancelling an action… I cannot seem to figure out how to use my WSAD input as a means for cancelling an action.

I know that it is monobehavior but i can’t seem to wrap my head around it. The WSAD is simple, it is:

            moveForwardBack = Input.GetAxis("Vertical") * speed;
            moveLeftRight = Input.GetAxis("Horizontal") * speed;

            Vector3 movement = new Vector3(moveLeftRight, 0, moveForwardBack);
            movement = character.rotation * movement;

            character.GetComponent<CharacterController>().Move(movement * 
            additionalSpeed * Time.deltaTime);

I know there must be some simple solution but in my head it seems so silly to create a method around this simple movement simply for the sake of cancelling the aciton. However without the cancellation of the action, the only way for me to cancel combat, is to move out of range and delete my target. I know this will pose problems later with animating and switching targets as well so I want to nip it in the bud.

If you are reading my code and wondering why it is written the way it is, it is because I have a really nice camera follow that uses right mouse to pan, and has auto snapping, lets character move in the direction it is facing with auto rotation of character, etc. It is a really nice camera, and its part of the reason I am sticking with WSAD.

Can anyone provide any insight or direction to my problem?

I would drop the call to IActionScheduler into CharacterController.Move()

1 Like

Thanks for your reply.

While I see what you’re saying I guess I don’t know what you are intending.

CharacterController.Move() is reaching to the character controller component. How would I access the scheduler from within that component?

I have to say I’m a bit lost after this comment.

What I’m seeing is that the code you posted above could be a function called CalculateMovement(). All it really does is calculate the vector your character is going to move, no action is taken within this code. You then pass that vector to CharacterController.Move() where presumably there is some code to actually move your character. I’m thinking it is at this point that you want to cancel your previous action, and since Move() is the function that actually creates the action, move should also notify IActionScheduler that it is in fact doing so.

1 Like

Thanks again for your reply. God I feel so stupid right now.
So what I’ve done is I’ve created

public Vector3 CalculateMovement()

And like you said, my movement is not really an action, it is just live updating of the vectors. So I popped it in the script, and I returned the desired Vector3. I just tested it using this:

character.GetComponent<CharacterController>().Move(CalculateMovement());

And it worked (although the speed drastically increased, not sure why, but that is easily fixable.) So I can move around by doing that. I am not used to breaking everything into methods this way lol. Either way, your suggestion worked up to that point. Unless I am not doing it right.

Now in the ActionScheduler, there is this little line of code they have been using to start the aciton, in case you’re unfamiliar it is this:

GetComponent<ActionScheduler>().StartAction(this);

So as far as I’m aware, to make sure I understand this little line, “this” refers to the MonoBehaviour that is instantiated, which means that “this” action is the one thats being passed the the ActionScheduler reference. So whatever “this” is needs to be my movement action?

But no matter how i setup the scripting it always throws me the typical:
NullReferenceException: Object reference not set to an instance of an object

Am I on the right path or am i thinking of it wrong? Again, I appreciate your help. And I’m sorry if i appear dumb. I really want to learn to code well and stop my old spaghetti habits.

sorry, just realized I only answered one of the questions. [retracted]
I think you are tracking the right rabbit here. As for your ORIO, I suspect if you take a look at your Player object you will find you are missing a component.

Updated Wed Sep 04 2019 09:50

1 Like

Okay so I’m sure this isn’t right but I modified my solution from my previous reply (not sure if you saw that because we commented exactly at the same time, haha). I know that I shouldn’t be calling this from update, because that means its calling the ActionScheduler every frame. I don’t know what the heck to do with this. I am in 3 methods at this point when i started out with 0.

        void Update()
        {
            MoveTo(CalculateMovement());

        }

        public void MoveTo(Vector3 direction) {
            GetComponent<ActionScheduler>().StartAction(this);
            character.GetComponent<CharacterController>().Move(direction);
        }

Here is my CalculateMovement. It returns a Vector3 which is used to supply MoveTo with a Vector3, which gets passed to the GetComponent().Move.

        public Vector3 CalculateMovement()
        {

            moveFB = Input.GetAxis("Vertical") * moveSpeed;
            moveLR = Input.GetAxis("Horizontal") * moveSpeed;

            Vector3 movement = new Vector3(moveLR, 0, moveFB);
            movement = character.rotation * movement;
            return movement;
         }

At this point, MoveTo is completely redundant isn’t it? It is just adding extra bloat. I don’t know how to get it inside of a function where the function only calls the action when moved, if i need to check for movement in my update? UGH!

I don’t think you can get around the processing load from calling the Action Scheduler each fram as you are in effect initiating a new move action each frame and any check to bypass it would likely cost the same and just complicate the code needlessly. @Nina is probably better able to answer that though.

as for MoveTo(), from my perspective it does appear redundant but, I’m not sure why you want to keep the call to ActionScheduler out of your CharacterController’s Move function. Is the controller on a different object?

1 Like

Even if we could ignore the issues with processing load, this script still doesn’t work. So my code is still incorrect. So although I might have the right idea, I am still clearly not getting something, haha.
NullReferenceException points to this line:

GetComponent<ActionScheduler>().StartAction(this);

And that has been my problem, no matter what I do, how I configure, I always get the NullReferenceException because of this line. I guess I just don’t understand where I’m supposed to be putting it, but I feel like I do. And I feel like i am formatting it the way that it should be, according to the other scripting on this topic that I’ve done through the course.

I’m not sure why you want to keep the call to ActionScheduler out of your CharacterController’s Move function.

Honestly, I am not intending to do that. If there is a way to do that, I am not figuring out how? To my knowledge I cannot directly place the ActionScheduler inside of the CharacterController component.

You are right in the fact that the controller is on another object, hence the reference to character in:

character.GetComponent<CharacterController>().Move();

One of the reasons it is setup this way is because of the camera. When I was programming this camera I couldn’t get the camera to behave properly with movement unless I had the script on my camera, referencing the player object. So the player object is linked in the inspector to the script that is being executed from the camera.

I can see how this might be misleading but I don’t really see that it poses a problem, right? Because if I were to flip everything around, I would just be running the same script with the camera being the reference and the player running it in it’s own update. Same problem is still there.

I don’t think you can get around the processing load from calling the Action Scheduler each fram as you are in effect initiating a new move action each frame and any check to bypass it would likely cost the same and just complicate the code needlessly.

So… are you saying that this can’t be done? Or that this ActionScheduler is incompatible with my WSAD movement? Or, what? There has to be some way…

We’ll start with this, the Action Scheduler is a Class by itself so once set up and attached to the player it can be called by other classes. To my understanding, you cannot create multiple classes in the same script when using Unity.

in this case, it’s probably a toss-up as to where to put the Action Scheduler. Notice that above, I specified the player object as the parent for the Action Scheduler but it can be attached to anything and ideally, it will be attached to the object taking actions. Thus, if your Action Scheduler is attached to a different object than the script we’re working in you need to add an object reference in order to call the Action Scheduler. Such as:

void MoveTo()
  {
  character.GetComponent<ActionScheduler>().StartAction(this);
  }

remember, GetComponent() only looks at the components attached to the same object as the script from which it is being called unless you specify a different object.

I think the pertinent questions here are:

  1. Did you set up the Action Scheduler as a separate component?
    -I’ve been operating on the assumption that the answer to this is Yes.

  2. Did you remember to attach it to something in the game?

  3. Is it attached to the same object as the script you are calling it from?

your ORIO is related to the answers for 2 and 3

1 Like

Oh my gosh I can’t believe I’ve been smashing my head into this wall for 2 days now because of my failure to reference the actual component that the script was attached to. You have blessed me with your second set of eyes! The ORIO is gone! Hooray!

I’ve only got one problem now which is the Update. Since it is calling my movement every Update, it is calling the action. Which means it is cancelling my actions every Update. Its not cancelling my current action because

if (currentAction == action) return;

but when i change my action, to something like combat, the update instantly reverts it back to my moving action. Would it be too clunky to use a bool or if statement? Like i said I am trying to break my spaghetti code habits, so it my be my natural instinct showing through. I can’t think of any if statement that wouldn’t be stringy to be able to check whether or not i was moving…

I feel like checking on these variables would be quite wrong:

moveFB = Input.GetAxis("Vertical") * moveSpeed;
moveLR = Input.GetAxis("Horizontal") * moveSpeed;

if (moveFB != 0)

I also don’t know the danger of setting a bool in a new set action method:

if (isMoving == true)

etc…

Edit: Just tried both methods, there is no way. With the bool and the if statement, the bool continuously switches on and off, the only way I’ve found to do it is introduce another bool to the ActionScheduler itself, referencing it asking if I am moving, but then it makes the gameplay really clunky. Stop and Go constantly etc.

Honestly you have gone miles for me, so if you are not interested in helping any further, i don’t blame you! I am just a noob that never runs out of questions. Thank you for all your help.

sorry for the delay in responding. I’m honestly not sure how to solve that myself but, I’m thinking you might try something along the line of

void Update()
{
  Vector3 movement = CalculateMovement
  if(movement.magnitude > MathF.Epsilon) { MoveTo(movement); }
}
1 Like

Ok, I will try that! Thank you so much again for your help. And no worries about the delay :slight_smile:

This topic was automatically closed 24 hours after the last reply. New replies are no longer allowed.

Privacy & Terms