Attacking while Moving

RoyArtorius

New member
I’ve been trying to get a UCC bot to move around my flat level while at the same time shooting at the player. My problem is that any movement task from the movement pack has its direction overriden by something on the UCC. So when the Use Task is ran, starting the bot’s attack, followed by the Wander Task, the bot just heads straight for the player. My guess is that the Look Target on the bot is preventing the bot from turning so it can’t move in whatever direction the Wander task decides.

Any ideas on how to deal with this?
 

RoyArtorius

New member
Have you tried the Behavior Designer sample scene? In that scene the character can move while firing. This page explains the tree:

https://opsive.com/support/document...er/integrations/opsive-character-controllers/
Actually after testing both the shooting scenes and melee scenes, the problem is there as well. The melee scene provides the best example as all you need to do to avoid getting hit by the bot is to walk backwards. The bot can't swing and move at the same time so it will constantly interrupt it's own attack to get closer to the player.
 

Justin

Administrator
Staff member
This sounds like its related to root motion - when the sword attacks the animation takes over so that's why the agent doesn't attack at the same time as moving. A good example of this working is the shooter scene since the character starts to attack while in the distance.
 

RoyArtorius

New member
This sounds like its related to root motion - when the sword attacks the animation takes over so that's why the agent doesn't attack at the same time as moving. A good example of this working is the shooter scene since the character starts to attack while in the distance.
Sorry, but I see the same thing happening here with the shooting scene. If the player just backs away from the bot, the bot will constantly move forward trying to get close enough to fire. The difference is that the bot can get off a shot every once in a while when it gets close.

Yes, in the demo scenes the bot moves towards the player while firing, but I guess the best way to describe it is I'm looking for a way to have the bot strafing to the left and right like a player would to avoid incoming bullets.

What I'm trying to do is essentially have my bot use Wander to run around the scene while at the same time firing their weapon in the direction of the player. What happens if Wander and Start and Stop Use (Fire Weapon) run alongside each other, whether using Sequence or Parallel, the Wander's direction gets overridden by the Look Target of Start and Stop Use.
 

Justin

Administrator
Staff member
Yes, in the demo scenes the bot moves towards the player while firing, but I guess the best way to describe it is I'm looking for a way to have the bot strafing to the left and right like a player would to avoid incoming bullets.
Ah, for that in the Deathmatch AI Kit I accomplished by creating a new task that will specifically cause the agent to strafe. I really hope we can get deathmatch back relatively soon because it was a great example of a more advanced AI.

What I'm trying to do is essentially have my bot use Wander to run around the scene while at the same time firing their weapon in the direction of the player. What happens if Wander and Start and Stop Use (Fire Weapon) run alongside each other, whether using Sequence or Parallel, the Wander's direction gets overridden by the Look Target of Start and Stop Use.
Wander shouldn't be sharing any variables with use - both tasks would operate on the same agent but since use doesn't set the position the two tasks will operate independently if they are under a parallel task.
 

RoyArtorius

New member
Ah, for that in the Deathmatch AI Kit I accomplished by creating a new task that will specifically cause the agent to strafe. I really hope we can get deathmatch back relatively soon because it was a great example of a more advanced AI.


Wander shouldn't be sharing any variables with use - both tasks would operate on the same agent but since use doesn't set the position the two tasks will operate independently if they are under a parallel task.
Oh awesome, :) I do look forward to seeing it. I’ll find something else to work on in the meantime.

That was bad wording on my part. By overridden I was speaking figuratively and not literally. I meant that because Start and Stop Use forces the bot object to rotate to face the specified Look Target and Wander also rotates the bot object in order to make it move around, when the two are both active the bot will only face the target and, as a result, the bot will move directly to the target.
Basically the bot will only ever move in the direction it is facing and I cannot get it to strafe. :(
 

RoyArtorius

New member

DragonFist

New member
I had this working with a previous version of UCC/TPCv2 but it seems it looks like the agentmovement classes are different and move the character via a forward vector and DeltaYawRotation. I used to basically call a setdestination on the the movement agent with update rotation set to false and it worked.
 

DragonFist

New member
Turning on Aiming results in character continuously moving toward the look target and not the set destination. Turning off aiming has the character move to the set destination but without looking towards the look target. I've tried numerous thing to get this to work but nothing results in anything other than those two behaviors, neither of which are the desired behavior, which to simply have the character move to the set destination while also looking at its target (most often the player).
 

DragonFist

New member
Okay, I got it working. I had to hack the NavMeshAgentMovement to get the desired effect:
C#:
public override void Update()
        {
            m_InputVector = Vector2.zero;
            var AimAbility = m_CharacterLocomotion.GetAbility<Items.Aim>();
            if (AimAbility != null && AimAbility.IsActive)
            {
                var lookRotation = Quaternion.LookRotation(m_CharacterLocomotion.LookSource.LookDirection(true), m_CharacterLocomotion.Up);
                var forwardRotation = Quaternion.LookRotation(m_Transform.forward, m_CharacterLocomotion.Up);
                var moveRotation = Quaternion.LookRotation(m_Transform.forward, m_CharacterLocomotion.Up);
                if (m_NavMeshAgent.isOnOffMeshLink)
                {
                    UpdateOffMeshLink();
                }
                else
                {
                    // When the path is pending the desired velocity isn't correct. Add a small buffer to ensure the path is valid.
                    if (m_NavMeshAgent.pathPending)
                    {
                        m_LastPathPendingFrame = Time.frameCount;
                    }
                    // Only move if a path exists.
                    if (m_NavMeshAgent.desiredVelocity.sqrMagnitude > 0.01f && m_NavMeshAgent.remainingDistance > 0.01f && m_LastPathPendingFrame + 2 < Time.frameCount)
                    {
                        moveRotation = Quaternion.LookRotation(m_NavMeshAgent.desiredVelocity, m_CharacterLocomotion.Up);
                        // The normalized velocity should be relative to the target rotation.
                        var velocity = Quaternion.Inverse(lookRotation) * m_NavMeshAgent.desiredVelocity;
                        // Only normalize if the magnitude is greater than 1. This will allow the character to walk.
                        if (velocity.sqrMagnitude > 1)
                        {
                            velocity.Normalize();
                        }
                        m_InputVector.x = velocity.x;
                        m_InputVector.y = velocity.z;
                    }
                }
                //var rotation1 = lookRotation * Quaternion.Inverse(m_Transform.rotation);
                var rotation2 = lookRotation * Quaternion.Inverse(m_Transform.rotation);
                m_DeltaYawRotation = Utility.MathUtility.ClampInnerAngle(rotation2.eulerAngles.y);
                //this.m_Transform.rotation = rotation1;
            } else
            {
                var lookRotation = Quaternion.LookRotation(m_Transform.forward, m_CharacterLocomotion.Up);
                if (m_NavMeshAgent.isOnOffMeshLink)
                {
                    UpdateOffMeshLink();
                }
                else
                {
                    // When the path is pending the desired velocity isn't correct. Add a small buffer to ensure the path is valid.
                    if (m_NavMeshAgent.pathPending)
                    {
                        m_LastPathPendingFrame = Time.frameCount;
                    }
                    // Only move if a path exists.
                    if (m_NavMeshAgent.desiredVelocity.sqrMagnitude > 0.01f && m_NavMeshAgent.remainingDistance > 0.01f && m_LastPathPendingFrame + 2 < Time.frameCount)
                    {
                        lookRotation = Quaternion.LookRotation(m_NavMeshAgent.desiredVelocity, m_CharacterLocomotion.Up);
                        // The normalized velocity should be relative to the target rotation.
                        var velocity = Quaternion.Inverse(lookRotation) * m_NavMeshAgent.desiredVelocity;
                        // Only normalize if the magnitude is greater than 1. This will allow the character to walk.
                        if (velocity.sqrMagnitude > 1)
                        {
                            velocity.Normalize();
                        }
                        m_InputVector.x = velocity.x;
                        m_InputVector.y = velocity.z;
                    }
                }
                var rotation = lookRotation * Quaternion.Inverse(m_Transform.rotation);
                m_DeltaYawRotation = Utility.MathUtility.ClampInnerAngle(rotation.eulerAngles.y);
            }

            base.Update();
        }
I'll clean it up later, it probably has now unused variables, etc. But it works.
 

DragonFist

New member
This is the result using a task for Behavior designer that I wrote (inspired by some code from the old Death Match Demo for TPCv1) that has the controller lock onto the player strafe while looking at the player.

 

nRedux

Member
DragonFist, the code you posted works well. Did you simply create a task which turns the hack in NavMeshAgentMovement on/off or did you do something more extensive?

Edit: I'm assuming the behavior was mostly for his movement behavior while using the NavMeshAgentMovement modification?
 

DragonFist

New member
Been a while, but if I remember correctly, it was simply editing the task to use a separate look rotation from the move rotation. The original was using the look rotation to also set the movement direction.
 
Top