Cocos2dx 3d open-source project fantasyWarrior3D starts from scratch 5 [Role-Based actor & amp; AI implementation]
1. Construct an object
From actor. lua, we can see some implementation of the "Object-Oriented" concept.
(1) "inheritance" of basic attributes"
Knight = class("Knight", function() return require "Actor".create()end)
Knight re-defines the constructor () after the actor is created, so it does not affect the call of the base class ctor ().
(2) "polymorphism" of the action"
Knight._action = { idle = createAnimation(file,267,283,0.7), walk = createAnimation(file,227,246,0.7), attack1 = createAnimation(file,103,129,0.7), attack2 = createAnimation(file,130,154,0.7), specialattack1 = createAnimation(file,160,190,0.3), specialattack2 = createAnimation(file,191,220,0.4), defend = createAnimation(file,92,96,0.7), knocked = createAnimation(file,254,260,0.7), dead = createAnimation(file,0,77,1)}
It is worth noting that why should I use clone () when executing an action?
Because the content of _ action IN actor will be assigned a new value as the subclass object is created.
Self. _ curAnimation3d = self. _ action [name]: clone ()
Self. _ sprite3d: runAction (self. _ curAnimation3d)
(3) copy the configuration to obtain an independent set of member variables.
copyTable(ActorDefaultValues,self)copyTable(ActorCommonValues, self)
2. Special Effects
(1) addEffect adds special effects to the role (attacked)
(2) initPuff () add smoke to run
(3) initShadow () shadow
Role attribute _ circle determines the shadow size
Then the image and transparency are realized.
3. Role action implementation, position, orientation
(1) The role plays an action.
Function Actor: playAnimation (name, loop)
The _ action table is implemented by the successors in the format file.
(2) Set Orientation
Function Actor: setFacing (degrees)
Self. _ curFacing = DEGREES_TO_RADIANS (degrees)
Self. _ targetFacing = self. _ curFacing
Self: setRotation (degrees)
End
_ CurFacing current orientation
Provides the launch direction for attacks.
BasicCollider. create (self. _ myPos, self. _ curFacing, self. _ normalAttack)
_ TargetFacing: Orientation of the target
Self. _ targetFacing = cc. pToAngleSelf (cc. pSub (p2, p1 ))
Function cc. pToAngleSelf (self)
Return math. atan2 (self. y, self. x)
End
Get the desired Rotation Angle for turning yourself to the target.
(3) role movement and redirection
Function Actor: movementUpdate (dt)
It is worth noting that this function occurs at each frame because the orientation of the role needs to be adjusted frequently.
[1] steering
It is easy to think that, no matter which position of the target role, it can only be completed by turning to the left or right at a <180 degree angle,
You can change the right turn to 180 + N degrees to 360-(180 + N) left to avoid round-robin.
The following code is used to determine whether to turn left or right.
if self._curFacing ~= self._targetFacing then local angleDt = self._curFacing - self._targetFacing angleDt = angleDt % (math.pi*2) local turnleft = (angleDt - math.pi)<0 local turnby = self._turnSpeed*dt --right if turnby > angleDt then self._curFacing = self._targetFacing elseif turnleft then self._curFacing = self._curFacing - turnby else --left self._curFacing = self._curFacing + turnby end self:setRotation(-RADIANS_TO_DEGREES(self._curFacing)) end
[2] acceleration, deceleration, and moving
Role attribute _ speed determines the maximum speed, and _ acceleration determines the acceleration.
The sliding distance can also be calculated using the formula S = Vt ^ 2-Vo ^ 2/2a,
To be more precise and avoid "hitting", You Can slightly adjust the attack distance from local attackDistance = self. _ attackRange + self. _ target. _ radius + S.
(4) injured
Actor: hurt (collider, dirKnockMode)
Parameter: attacker, with a hitting Effect
4. State Machine and AI
(1) Five characters in the state machine are activated by the following functions and are responsible for runAction.
IdleMode specified mode attackMode knockMode: Fly dyingMode: Death
Function Actor: dyingMode (knockSource, knockAmount)
Parameter: attacker, with a hitting Effect
We can see that there is an operation to recycle to the pool three seconds later.
local function recycle() self:setVisible(false) List.pushlast(getPoolByName(self._name),self) end
Impact
Function Actor: knockMode (collider, dirKnockMode)
It is actually a shift to the role. The distance of the shift depends on the knock of the attack attribute.
(2) The frame loop of the state machine is responsible for executing the logical action of the corresponding state.
Function Actor: stateMachineUpdate (dt)
(3) Actor: AI ()
This function and stateMachineUpdate jointly complete the normal operation of the state machine.
Selects the next action based on the current status and activates the action.
Actor: baseUpdate (dt) is responsible for calling AI (). The execution frequency is determined by _ AIFrequency in the configuration table.
A hero is usually in ~ 1.3 seconds, NPC 3 ~ Five seconds, because the hero's logic behavior is richer
The high frequency of AI computing can reduce the time it takes for a role to become stupid, but frequent calls may affect performance. Therefore, we need to consider a compromise.
A rough ai process is drawn. In fact, the circle is executed by the stateMachineUpdate state machine.
Sometimes, the idle action is executed during the attack, but the role is still in the attack status.