Add loop behavior via code to player animation

This commit is contained in:
Tran Hai Nam
2026-04-22 15:58:28 +07:00
parent aac787e2e0
commit f5dba37813
6 changed files with 128 additions and 54 deletions
@@ -158,7 +158,15 @@ namespace BrewMonster.Scripts
return m_iType;
}
}
public class CECEPWorkMove : CECEPWork
{
public CECEPWorkMove(CECEPWorkMan pWorkMan) : base(CECEPWork.EP_work_ID.WORK_MOVE, pWorkMan)
{
}
public override void Start()
{
}
}
public class CECEPIdleWorkMatcher : CECEPWorkMatcher
{
int m_iType;
@@ -354,7 +362,10 @@ namespace BrewMonster.Scripts
new List<CECEPWork>()
};
private int m_iCurWorkType;
public int GetCurrentWorkType()
{
return m_iCurWorkType;
}
public CECEPWorkMan(EC_ElsePlayer pElsePlayer)
{
m_pElsePlayer = pElsePlayer;
@@ -792,12 +803,11 @@ namespace BrewMonster.Scripts
if (!GetPlayer().m_FightCnt.IsFull()){
GetPlayer().m_FightCnt.IncCounter(dwDeltaTime);
}
//todo: get model and check
// if (GetPlayer().GetPlayerModel() != null){
if (GetPlayer().GetPlayerModel() != null){
if (CECPlayer.IsMoveStandAction(GetPlayer().GetLowerBodyAction())){
GetPlayer().PlayAction(GetStandAction(), false);
}
// }
}
}
int GetStandAction()
@@ -38,7 +38,7 @@ public class CECCounter
public bool IncCounter(float dwCounter)
{
m_dwCounter += dwCounter;
return (m_dwCounter >= m_dwPeriod);
return (m_dwCounter >= m_dwPeriod) ? true : false;
}
// Decrease counter
+16 -12
View File
@@ -294,7 +294,7 @@ namespace BrewMonster
protected GameObject GetDummyModel(int i) => (i!=(int)PLAYERMODEL_TYPE.PLAYERMODEL_MAJOR&&i<(int)PLAYERMODEL_TYPE.PLAYERMODEL_MAX) ? m_pModels[i]:null;
protected GameObject GetMajorModel() => m_pModels[(int)PLAYERMODEL_TYPE.PLAYERMODEL_MAJOR];
protected GameObject GetPetModel() => m_pPetModel;
protected CECModel GetPlayerModel() => m_pPlayerCECModel;
public CECModel GetPlayerModel() => m_pPlayerCECModel;
protected const int OBJECT_EXT_STATE_COUNT = 6;
protected bool IsMajorModel(GameObject pModel) => GetMajorModel() != null && pModel == GetMajorModel();
public enum WeaponHangerPosition
@@ -1176,11 +1176,11 @@ namespace BrewMonster
}
}
public bool PlayAction(int iAction, bool bRestart = true, int iTransTime = 200, bool bQueue = false)
public bool PlayAction(int iAction, bool bRestart = true, int iTransTime = 200, bool bQueue = false, bool isElsePlayer = false)
{
return PlayActionWithConfig(iAction, 0, bRestart, iTransTime, bQueue);
}
public bool PlayAction(int iAction, int actionConfigID, bool bRestart = true, int iTransTime = 200, bool bQueue = false)
public bool PlayAction(int iAction, int actionConfigID, bool bRestart = true, int iTransTime = 200, bool bQueue = false, bool isElsePlayer = false)
{
return PlayActionWithConfig(iAction, actionConfigID, bRestart, iTransTime, bQueue);
}
@@ -1634,7 +1634,6 @@ namespace BrewMonster
string szShapeName = string.Empty;
GetShapeName(ref szShapeName);
int weapon_type = GetShowingWeaponType();
Debug.Log($"[THN]: PlayAttackAction weapon_type: {weapon_type}");
int nTime1 = 0, nTime2 = 0;
int iAction = (int)PLAYER_ACTION_TYPE.ACT_ATTACK_1 + nRand;
bool bHideFX = false;//!CECOptimize::Instance().GetGFX().CanShowAttack(GetCharacterID(), GetClassID());
@@ -1653,7 +1652,6 @@ namespace BrewMonster
{
// “起? 动作(挥起)
Debug.Log($"[THN]: PlayAttackAction action with weapon type: {weapon_type} and weapon attached: {m_bWeaponAttached}");
szAct = EC_Utility.BuildActionName(action, weapon_type, "起");
int iTransTime = 200;
//EventBus.PublishChannel(m_PlayerInfo.cid, new PlayActionEvent(szShapeName, szAct, iTransTime, true));
@@ -1723,8 +1721,7 @@ namespace BrewMonster
PLAYER_ACTION stand_action = m_PlayerActions[(int)PLAYER_ACTION_TYPE.ACT_FIGHTSTAND];
szAct = EC_Utility.BuildActionName(stand_action, 0);
int iTranstime = 300;
queueActionEvent.SetData(szShapeName, szAct, SetApplyDamage, false, attackEvent, iTranstime, false);
//EventBus.PublishChannelClass(m_PlayerInfo.cid, queueActionEvent);
BMLogger.LogError($"[THN]: PlayAttackAction QueueNonSkillActionWithName: {szAct}");
m_pActionController.QueueNonSkillActionWithName(iAction, szAct, iTranstime, false, false, true, false);
/* QueueNonSkillActionWithName(ACT_FIGHTSTAND, szAct, 300, false, bHideFX, true);
@@ -3883,20 +3880,23 @@ namespace BrewMonster
public string AnimationName;
public int ITransTime;
public bool IsForceStopPrevious;
public bool IsLoop;
public CECAttackEvent AttackEvent;
public PlayActionEvent(string shapeName, string animationName, int iTransTime, bool isForceStopPrevious = false, CECAttackEvent attackEvent = null)
public PlayActionEvent(string shapeName, string animationName, int iTransTime, bool isForceStopPrevious = false, CECAttackEvent attackEvent = null, bool isLoop = false)
{
this.AnimationName = shapeName + animationName;
ITransTime = iTransTime;
IsForceStopPrevious = isForceStopPrevious;
AttackEvent = attackEvent;
IsLoop = isLoop;
}
public PlayActionEvent(string animationName, int iTransTime, bool isForceStopPrevious = false, CECAttackEvent attackEvent = null)
public PlayActionEvent(string animationName, int iTransTime, bool isForceStopPrevious = false, CECAttackEvent attackEvent = null, bool isLoop = false)
{
this.AnimationName = animationName;
ITransTime = iTransTime;
IsForceStopPrevious = isForceStopPrevious;
AttackEvent = attackEvent;
IsLoop = isLoop;
}
}
public struct PLAYER_ACTION
@@ -3912,8 +3912,9 @@ namespace BrewMonster
public CECAttackEvent AttackEvent;
public bool IsHitAnim;
public bool IsForceStopPrevious;
public bool IsLoop;
public QueueActionEvent(string animationName, Action<bool, CECAttackEvent> setFlag, bool isHitAnim,
CECAttackEvent attackEvent, int iTransTime, bool isForceStopPrevious = false)
CECAttackEvent attackEvent, int iTransTime, bool isForceStopPrevious = false, bool isLoop = false)
{
this.AnimationName = animationName;
SetFlag = setFlag;
@@ -3921,10 +3922,11 @@ namespace BrewMonster
AttackEvent = attackEvent;
ITransTime = iTransTime;
IsForceStopPrevious = isForceStopPrevious;
IsLoop = isLoop;
}
public void SetData(string shapeName, string animationName, Action<bool, CECAttackEvent> setFlag, bool isHitAnim,
CECAttackEvent attackEvent, int iTransTime, bool isForceStopPrevious = false)
CECAttackEvent attackEvent, int iTransTime, bool isForceStopPrevious = false, bool isLoop = false)
{
this.AnimationName = shapeName + animationName;
SetFlag = setFlag;
@@ -3932,9 +3934,10 @@ namespace BrewMonster
AttackEvent = attackEvent;
ITransTime = iTransTime;
IsForceStopPrevious = isForceStopPrevious;
IsLoop = isLoop;
}
public void SetData(string animationName, Action<bool, CECAttackEvent> setFlag, bool isHitAnim,
CECAttackEvent attackEvent, int iTransTime, bool isForceStopPrevious = false)
CECAttackEvent attackEvent, int iTransTime, bool isForceStopPrevious = false, bool isLoop = false)
{
this.AnimationName = animationName;
SetFlag = setFlag;
@@ -3942,6 +3945,7 @@ namespace BrewMonster
AttackEvent = attackEvent;
ITransTime = iTransTime;
IsForceStopPrevious = isForceStopPrevious;
IsLoop = isLoop;
}
}
public enum PLAYER_ACTION_TYPE
+5 -5
View File
@@ -671,10 +671,10 @@ public class CECModel
}
var actionInfos = combinedAction.m_ActLst;
var isLoop = combinedAction.m_nLoops == 1;
EventBus.PublishChannel(m_nId, new PlayActionEvent(actionInfos[0].m_strName, nTransTime, bForceStop, attackEvent));
EventBus.PublishChannel(m_nId, new PlayActionEvent(actionInfos[0].m_strName, nTransTime, bForceStop, attackEvent, isLoop));
for(int i = 1; i < actionInfos.Count; i++)
{
EventBus.PublishChannelClass(m_nId, new QueueActionEvent(actionInfos[i].m_strName, null, false, attackEvent, nTransTime, false));
EventBus.PublishChannelClass(m_nId, new QueueActionEvent(actionInfos[i].m_strName, null, false, attackEvent, nTransTime, false, isLoop));
}
var eventInfoList = combinedAction.m_EventInfoLst;
if(eventInfoList != null && eventInfoList.Count > 0)
@@ -688,7 +688,7 @@ public class CECModel
{
string soundpath = AFile.NormalizePath(sfx.m_strFilePaths[0]);
soundpath = soundpath.ToLower();
SFXManager.Instance.PlaySkillSfxAtPointAsync(soundpath, Vector3.zero).Forget();
SFXManager.Instance.PlaySkillSfxAtPointAsync(soundpath, Vector3.zero).Forget();
}
}
@@ -717,10 +717,10 @@ public class CECModel
}
var actionInfos = combinedAction.m_ActLst;
var isLoop = combinedAction.m_nLoops == 1;
EventBus.PublishChannelClass(m_nId, new QueueActionEvent(actionInfos[0].m_strName, null, false, attackEvent, nTransTime, bForceStopPrevAct));
EventBus.PublishChannelClass(m_nId, new QueueActionEvent(actionInfos[0].m_strName, null, false, attackEvent, nTransTime, bForceStopPrevAct, isLoop));
for(int i = 1; i < actionInfos.Count; i++)
{
EventBus.PublishChannelClass(m_nId, new QueueActionEvent(actionInfos[i].m_strName, null, false, attackEvent, nTransTime, false));
EventBus.PublishChannelClass(m_nId, new QueueActionEvent(actionInfos[i].m_strName, null, false, attackEvent, nTransTime, false, isLoop));
}
return true;
}
@@ -154,20 +154,23 @@ namespace BrewMonster
//if (!m_pPlayerModel) return;
//if (!IsValidAction(iCurAction)) return;
// PlayAction(GetMoveStandAction(true), true, 1, false);
if (m_pEPWorkMan.GetCurrentWorkType() < CECEPWorkMan.Work_type.WT_NORMAL ||
!m_pEPWorkMan.FindWork(CECEPWorkMan.Work_type.WT_NORMAL, CECEPWork.EP_work_ID.WORK_MOVE)){
m_pEPWorkMan.StartNormalWork(new CECEPWorkMove(m_pEPWorkMan));
}
// Play action
if (IsValidAction(m_iCurAction))
{
if (!IsPlayingAction((int)PLAYER_ACTION_TYPE.ACT_TRICK_JUMP) && !IsPlayingAction((int)PLAYER_ACTION_TYPE.ACT_TRICK_RUN))
{
if (m_iMoveMode == Move_Mode.MOVE_JUMP || m_iMoveMode == Move_Mode.MOVE_SLIDE)
PlayAction((int)PLAYER_ACTION_TYPE.ACT_JUMP_LOOP, false);
PlayAction((int)PLAYER_ACTION_TYPE.ACT_JUMP_LOOP, false, 200, false, true);
else
PlayAction(GetMoveStandAction(true), false);
PlayAction(GetMoveStandAction(true), false, 200, false, true);
}
}
}
else
PlayAction(GetMoveStandAction(true), true, 1, false);
PlayAction(GetMoveStandAction(true), true, 200, false, true);
}
public bool MovingTo(float dwDeltaTime)
@@ -204,7 +207,7 @@ namespace BrewMonster
if (Math.Abs(fMoveDelta - 0f) <= float.Epsilon || fMoveDelta >= fDist) //!fMoveDelta <=> (Math.Abs(fMoveDelta - 0f) <= float.Epsilon) Compare with 0
{
SetPos(m_vServerPos);
PlayAction(GetMoveStandAction(false), true, 1, false);
PlayAction(GetMoveStandAction(false), true, 200, false);
bRet = true;
}
else
@@ -264,7 +267,7 @@ namespace BrewMonster
{
m_bStopMove = false;
SetPos(Cmd.dest);
PlayAction(GetMoveStandAction(true), true, 1, false);
PlayAction(GetMoveStandAction(true), true, 200, false);
return;
}
int iMoveMode = Cmd.move_mode;
@@ -293,7 +296,7 @@ namespace BrewMonster
case GPMoveMode.GP_MOVE_JUMP: m_iMoveMode = (int)MoveMode.MOVE_JUMP; m_cdr.bTraceGround = false; break;
}
PlayAction(GetMoveStandAction(true), true, 1, false);
PlayAction(GetMoveStandAction(true), true, 200, false);
}
public float GetDistToHost() { return m_fDistToHost; }
@@ -419,7 +422,7 @@ namespace BrewMonster
m_fDistToHost = CalcDist(pHost.GetPos(), true);
m_fDistToHostH = CalcDist(pHost.GetPos(), false);
}
m_pEPWorkMan?.Tick(Time.deltaTime);
m_pEPWorkMan?.Tick(Time.deltaTime * 1000);
}
public void SetPos(A3DVECTOR3 vPos)
+79 -22
View File
@@ -11,7 +11,9 @@ namespace BrewMonster
{
public string AnimationName;
public bool IsForceStopPrevious;
public int ITransTime;
public CECAttackEvent AttackEvent;
public bool IsLoop;
}
public class PlayerVisual : MonoBehaviour
{
@@ -31,10 +33,15 @@ namespace BrewMonster
private const float FadeTime = 100;
private const FadeMode FadeMode = Animancer.FadeMode.FixedDuration;
QueueActionEvent queueActionEvent;
private string previousAnimationName;
private void PlayActionEventHandler(PlayActionEvent @event)
{
//when this trigger, clear all the animation in the queue which in the same layer of animancer
//prevent enqueue the same loop animation
bool loopcheck = @event.IsLoop == true && previousAnimationName == @event.AnimationName;
if(loopcheck)
{
return;
}
if (_animationQueue.Count > 0)
{
_animationQueue.Enqueue(new AnimationQueue
@@ -46,7 +53,8 @@ namespace BrewMonster
_animationList = _animationQueue.Select(q => q.AnimationName).ToList();
return;
}
InternalPlayAnimation(@event.AnimationName, @event.ITransTime);
previousAnimationName = @event.AnimationName;
InternalPlayAnimation(@event.AnimationName, @event.ITransTime, FadeMode, @event.IsLoop);
ApplyAttackSignalOnAnimationEnd(@event.AttackEvent);
}
public void InitPlayerEventDoneHandler()
@@ -133,15 +141,24 @@ namespace BrewMonster
}
public bool EnqueueAnimation(QueueActionEvent @event)
{
if (namedAnimancer == null) return false;
if (namedAnimancer == null)
{
return false;
}
if(previousAnimationName == @event.AnimationName)
{
return false;
}
previousAnimationName = @event.AnimationName;
_animationQueue.Enqueue(new AnimationQueue
{
AnimationName = @event.AnimationName,
IsForceStopPrevious = @event.IsForceStopPrevious,
AttackEvent = null
ITransTime = @event.ITransTime,
AttackEvent = @event.AttackEvent,
IsLoop = @event.IsLoop
});
_animationList = _animationQueue.Select(q => q.AnimationName).ToList();
if (!isHit)
{
queueActionEvent = @event;
@@ -149,23 +166,51 @@ namespace BrewMonster
}
return true;
}
/// <summary>
/// This function is used to enqueue an animation for looping when the animancer is not set to looping
/// </summary>
/// <param name="animationName"></param>
/// <returns></returns>
private bool EnqueueAnimationForLooping(string animationName)
{
if (namedAnimancer == null)
{
return false;
}
//prevent call if these is a animation already in the queue
if(_animationQueue.Count > 0)
{
return false;
}
_animationQueue.Enqueue(new AnimationQueue
{
AnimationName = animationName,
IsForceStopPrevious = false,
AttackEvent = null,
IsLoop = true
});
_animationList = _animationQueue.Select(q => q.AnimationName).ToList();
return true;
}
private void PlayNext()
{
if (_animationQueue.Count == 0)
{
return;
}
else
{
string animationQueueString = "";
foreach(var animation in _animationQueue)
{
animationQueueString += animation.AnimationName + ", ";
}
}
// if (_currentState == null)
// {
// _animationQueue.Dequeue();
// return;
// }
//peek next if IsForceStopPrevious is true, force end
if (_animationQueue.Peek().IsForceStopPrevious)
{
Debug.Log($" InternalPlayAnimation PlayNext: Force Stop Previous");
_currentState.Stop();
_currentState?.Stop();
_currentState = null;
}
if (_currentState != null && _currentState.NormalizedTime < 1f) return;
@@ -175,7 +220,8 @@ namespace BrewMonster
}
var animationQueue = _animationQueue.Dequeue();
_animationList = _animationQueue.Select(q => q.AnimationName).ToList();
InternalPlayAnimation(animationQueue.AnimationName);
previousAnimationName = animationQueue.AnimationName;
InternalPlayAnimation(animationQueue.AnimationName, animationQueue.ITransTime, FadeMode, animationQueue.IsLoop);
ApplyAttackSignalOnAnimationEnd(animationQueue.AttackEvent);
}
private void ApplyAttackSignalOnAnimationEnd(CECAttackEvent attackEvent)
@@ -192,7 +238,10 @@ namespace BrewMonster
}
void ApplyDamage()
{
if (queueActionEvent == null) return;
if (queueActionEvent == null)
{
return;
}
isHit = false;
queueActionEvent.SetFlag(true, queueActionEvent.AttackEvent);
queueActionEvent = null;
@@ -203,7 +252,8 @@ namespace BrewMonster
}
public bool IsAnimationExist(string animationName)
{
return namedAnimancer.States.TryGet("ActionName", out var existingState) ? true : false;
var exists = namedAnimancer.States.TryGet("ActionName", out var existingState) ? true : false;
return exists;
}
private string _currentAnimationName;
@@ -213,19 +263,26 @@ namespace BrewMonster
/// <param name="animationName"></param>
/// <param name="duration"></param>
/// <param name="fadeMode"></param>
private void InternalPlayAnimation(string animationName, float duration = FadeTime, FadeMode fadeMode = FadeMode)
private void InternalPlayAnimation(string animationName, float duration = FadeTime, FadeMode fadeMode = FadeMode, bool isLoop = false)
{
if (namedAnimancer == null)
{
return;
}
bool isState = namedAnimancer.States.TryGet(animationName, out var existingState) ? true : false;
if (isState)
{
_currentState = namedAnimancer.TryPlay(animationName, duration / 1000, fadeMode);
_currentAnimationName = animationName;
//Debug.Log($"InternalPlayAnimation: removeShapeName 1 TriggerName={removeShapeName}");
//if the animation is looping and the current state is not looping, play the animation again
if(isLoop == true && _currentState.IsLooping == false)
{
_currentState.Time = 0;
_currentState.Events.OnEnd = () => EnqueueAnimationForLooping(animationName);
}
return;
}
BMLogger.LogError($"Null name animation: {animationName}");
//BMLogger.LogError($"Null name animation: {animationName}");
}
/// <summary>