feat: trigger fighter behavior from lobby action button
This commit is contained in:
@@ -5,7 +5,9 @@ using UnityEngine;
|
||||
using UnityEngine.EventSystems;
|
||||
using UnityEngine.Rendering;
|
||||
using UnityEngine.UI;
|
||||
using XGame.ActorBehavior;
|
||||
using XGame.VirtualInput;
|
||||
using XWorld.Framework.ActorBehavior;
|
||||
using XWorld.Framework.Protocol;
|
||||
using UObject = UnityEngine.Object;
|
||||
|
||||
@@ -31,6 +33,7 @@ namespace XGame
|
||||
}
|
||||
|
||||
private const string JoystickPrefabPath = "Assets/Game/Art/UI/Prefab/UI_VirtualJoystick.prefab";
|
||||
private const string ActionPadPrefabPath = "Assets/Game/Art/UI/Prefab/UI_VirtualActionPad.prefab";
|
||||
private const string CharacterConfigResourcePath = "Config/CharacterConfig";
|
||||
private const string SelectedCharacterKey = "CharacterSwitch.SelectedCharacterId";
|
||||
private const float MoveSpeed = 1f;
|
||||
@@ -84,10 +87,17 @@ namespace XGame
|
||||
private RectTransform joystickRoot;
|
||||
private RectTransform joystickWidget; // 视觉容器:新预设里的 "Joystick" 子节点(自带定位);找不到则回退为 joystickRoot
|
||||
private VirtualJoystick virtualJoystick;
|
||||
private RectTransform actionPadRoot;
|
||||
private VirtualActionPad virtualActionPad;
|
||||
private LobbyActorBehaviorRuntime actorBehaviorRuntime;
|
||||
private ActorBehaviorPresentation actorBehaviorPresentation;
|
||||
private RectTransform joystickKnob;
|
||||
private bool joystickMouseCaptured;
|
||||
private int joystickTouchFingerId = -1;
|
||||
private bool joystickLoading;
|
||||
private bool actionPadLoading;
|
||||
private bool actorBehaviorCatalogLoading;
|
||||
private bool actorBehaviorCatalogLoaded;
|
||||
private static int materialLogCount;
|
||||
|
||||
public void Initialize(Action<FrameworkOpcode, byte[]> sendFramework, int playerId, string playerName, int figure)
|
||||
@@ -109,7 +119,10 @@ namespace XGame
|
||||
EnsureWorldRoot();
|
||||
worldRoot.gameObject.SetActive(true);
|
||||
EnsureCamera();
|
||||
EnsureActorBehaviorRuntime();
|
||||
StartCoroutine(EnsureActorBehaviorCatalogAsync());
|
||||
StartCoroutine(EnsureJoystickUIAsync());
|
||||
StartCoroutine(EnsureActionPadUIAsync());
|
||||
if (GetOrCreateAvatar(selfPlayerId, selfFigure, selfName) == null)
|
||||
{
|
||||
return;
|
||||
@@ -133,6 +146,10 @@ namespace XGame
|
||||
{
|
||||
joystickRoot.gameObject.SetActive(true);
|
||||
}
|
||||
if (actionPadRoot != null)
|
||||
{
|
||||
actionPadRoot.gameObject.SetActive(true);
|
||||
}
|
||||
send(FrameworkOpcode.LobbyJoin, new LobbyJoinMsg { Name = selfName, Figure = selfFigure }.Encode());
|
||||
}
|
||||
|
||||
@@ -152,6 +169,10 @@ namespace XGame
|
||||
{
|
||||
joystickRoot.gameObject.SetActive(false);
|
||||
}
|
||||
if (actionPadRoot != null)
|
||||
{
|
||||
actionPadRoot.gameObject.SetActive(false);
|
||||
}
|
||||
OnVirtualJoystickEnded();
|
||||
}
|
||||
|
||||
@@ -180,6 +201,7 @@ namespace XGame
|
||||
rotation = avatar.Obj.transform.rotation;
|
||||
hadAvatar = true;
|
||||
}
|
||||
RemoveActorBehavior(selfPlayerId);
|
||||
Destroy(avatar.Obj);
|
||||
avatars.Remove(selfPlayerId);
|
||||
}
|
||||
@@ -217,12 +239,14 @@ namespace XGame
|
||||
{
|
||||
UpdateRemoteAvatars();
|
||||
UpdateLocalMove();
|
||||
UpdateActorBehavior();
|
||||
UpdateCamera();
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
ReleaseJoystickUI(true);
|
||||
ReleaseActionPadUI(true);
|
||||
}
|
||||
|
||||
private void ApplyState(LobbyStateMsg state)
|
||||
@@ -269,6 +293,7 @@ namespace XGame
|
||||
}
|
||||
foreach (int id in remove)
|
||||
{
|
||||
RemoveActorBehavior(id);
|
||||
Destroy(avatars[id].Obj);
|
||||
avatars.Remove(id);
|
||||
}
|
||||
@@ -336,11 +361,14 @@ namespace XGame
|
||||
avatars.Remove(oldPlayerId);
|
||||
if (!avatars.ContainsKey(serverPlayerId))
|
||||
{
|
||||
RemoveActorBehavior(oldPlayerId);
|
||||
oldAvatar.PlayerId = serverPlayerId;
|
||||
avatars[serverPlayerId] = oldAvatar;
|
||||
RegisterActorBehavior(oldAvatar);
|
||||
}
|
||||
else if (oldAvatar.Obj != null)
|
||||
{
|
||||
RemoveActorBehavior(oldPlayerId);
|
||||
Destroy(oldAvatar.Obj);
|
||||
}
|
||||
}
|
||||
@@ -567,8 +595,10 @@ namespace XGame
|
||||
{
|
||||
if (avatar.Figure == figure)
|
||||
{
|
||||
UpdateActorBehaviorActor(avatar);
|
||||
return avatar;
|
||||
}
|
||||
RemoveActorBehavior(playerId);
|
||||
Destroy(avatar.Obj);
|
||||
avatars.Remove(playerId);
|
||||
}
|
||||
@@ -580,6 +610,7 @@ namespace XGame
|
||||
avatar.Target = avatar.Obj.transform.position;
|
||||
avatar.Animator = avatar.Obj.GetComponentInChildren<Animator>();
|
||||
avatars[playerId] = avatar;
|
||||
RegisterActorBehavior(avatar);
|
||||
SetMoveState(avatar, false);
|
||||
return avatar;
|
||||
}
|
||||
@@ -689,6 +720,7 @@ namespace XGame
|
||||
a.Animator = a.Obj.GetComponentInChildren<Animator>();
|
||||
a.IsPlaceholder = false;
|
||||
a.AnimState = null; // 让 SetMoveState 重新触发动画
|
||||
RegisterActorBehavior(a);
|
||||
SetMoveState(a, a.Moving);
|
||||
}
|
||||
}
|
||||
@@ -769,6 +801,10 @@ namespace XGame
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (actorBehaviorRuntime != null && actorBehaviorRuntime.HasActiveBehavior(avatar.PlayerId))
|
||||
{
|
||||
return;
|
||||
}
|
||||
string state = moving ? "Walk" : "Stand";
|
||||
if (avatar.AnimState == state)
|
||||
{
|
||||
@@ -909,6 +945,247 @@ namespace XGame
|
||||
camObj.transform.rotation = Quaternion.Euler(55f, 0f, 0f);
|
||||
}
|
||||
|
||||
private void EnsureActorBehaviorRuntime()
|
||||
{
|
||||
if (actorBehaviorRuntime == null)
|
||||
{
|
||||
actorBehaviorRuntime = new LobbyActorBehaviorRuntime();
|
||||
}
|
||||
if (actorBehaviorPresentation == null)
|
||||
{
|
||||
actorBehaviorPresentation = GetComponent<ActorBehaviorPresentation>();
|
||||
if (actorBehaviorPresentation == null)
|
||||
{
|
||||
actorBehaviorPresentation = gameObject.AddComponent<ActorBehaviorPresentation>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerator EnsureActorBehaviorCatalogAsync()
|
||||
{
|
||||
EnsureActorBehaviorRuntime();
|
||||
if (actorBehaviorCatalogLoaded || actorBehaviorCatalogLoading)
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
|
||||
actorBehaviorCatalogLoading = true;
|
||||
BehaviorConfigCatalog catalog = null;
|
||||
yield return ActorBehaviorConfigLoader.LoadCatalog(LobbyActorBehaviorRuntime.DefaultCatalogType, loaded => catalog = loaded);
|
||||
actorBehaviorCatalogLoading = false;
|
||||
if (catalog == null)
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
|
||||
actorBehaviorRuntime.RegisterCatalog(catalog);
|
||||
actorBehaviorCatalogLoaded = true;
|
||||
UpdateActorBehaviorActors();
|
||||
}
|
||||
|
||||
private void RegisterActorBehavior(Avatar avatar)
|
||||
{
|
||||
if (avatar == null || avatar.Obj == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
EnsureActorBehaviorRuntime();
|
||||
actorBehaviorRuntime.RegisterOrUpdateActor(avatar.PlayerId, avatar.Obj.transform.position, avatar.Obj.transform.forward);
|
||||
actorBehaviorRuntime.SwitchActorCatalog(avatar.PlayerId, LobbyActorBehaviorRuntime.DefaultCatalogType);
|
||||
actorBehaviorPresentation.RegisterActor(avatar.PlayerId, avatar.Animator, avatar.Obj.transform, avatar.Obj.transform);
|
||||
}
|
||||
|
||||
private void UpdateActorBehaviorActor(Avatar avatar)
|
||||
{
|
||||
if (avatar == null || avatar.Obj == null || actorBehaviorRuntime == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
actorBehaviorRuntime.RegisterOrUpdateActor(avatar.PlayerId, avatar.Obj.transform.position, avatar.Obj.transform.forward);
|
||||
}
|
||||
|
||||
private void RemoveActorBehavior(int actorId)
|
||||
{
|
||||
if (actorBehaviorPresentation != null)
|
||||
{
|
||||
actorBehaviorPresentation.UnregisterActor(actorId, true);
|
||||
}
|
||||
if (actorBehaviorRuntime != null)
|
||||
{
|
||||
actorBehaviorRuntime.RemoveActor(actorId);
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateActorBehavior()
|
||||
{
|
||||
if (actorBehaviorRuntime == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
UpdateActorBehaviorActors();
|
||||
actorBehaviorRuntime.Tick(Time.deltaTime);
|
||||
DrainActorBehaviorEvents();
|
||||
}
|
||||
|
||||
private void UpdateActorBehaviorActors()
|
||||
{
|
||||
if (actorBehaviorRuntime == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (Avatar avatar in avatars.Values)
|
||||
{
|
||||
UpdateActorBehaviorActor(avatar);
|
||||
}
|
||||
}
|
||||
|
||||
private void DrainActorBehaviorEvents()
|
||||
{
|
||||
if (actorBehaviorRuntime == null || actorBehaviorPresentation == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
IReadOnlyList<BehaviorEvent> events = actorBehaviorRuntime.DrainEvents();
|
||||
if (events.Count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
actorBehaviorPresentation.PlayEvents(events);
|
||||
for (int i = 0; i < events.Count; i++)
|
||||
{
|
||||
BehaviorEvent evt = events[i];
|
||||
if (evt.Kind != BehaviorEventKind.BehaviorStopped)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (avatars.TryGetValue(evt.ActorId, out Avatar avatar))
|
||||
{
|
||||
avatar.AnimState = null;
|
||||
SetMoveState(avatar, avatar.Moving);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Vector3 GetSelfSkillForward()
|
||||
{
|
||||
if (lastMoveDirection.sqrMagnitude > 0.001f)
|
||||
{
|
||||
return lastMoveDirection;
|
||||
}
|
||||
if (avatars.TryGetValue(selfPlayerId, out Avatar avatar))
|
||||
{
|
||||
if (avatar.LastFaceDirection.sqrMagnitude > 0.001f)
|
||||
{
|
||||
return avatar.LastFaceDirection;
|
||||
}
|
||||
if (avatar.Obj != null)
|
||||
{
|
||||
return avatar.Obj.transform.forward;
|
||||
}
|
||||
}
|
||||
return Vector3.forward;
|
||||
}
|
||||
|
||||
private void OnVirtualActionButtonEvent(ActionButtonEvent evt)
|
||||
{
|
||||
EnsureActorBehaviorRuntime();
|
||||
if (!actorBehaviorCatalogLoaded)
|
||||
{
|
||||
if (LobbyActorBehaviorRuntime.IsSecondaryATrigger(evt))
|
||||
{
|
||||
Debug.LogWarning("[LobbyWorldController] actor behavior catalog is not ready.");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
BehaviorStartResult result = actorBehaviorRuntime.HandleActionButton(evt, selfPlayerId, GetSelfSkillForward());
|
||||
if (result.Success)
|
||||
{
|
||||
DrainActorBehaviorEvents();
|
||||
return;
|
||||
}
|
||||
|
||||
if (result.Error != "button ignored")
|
||||
{
|
||||
Debug.LogWarning("[LobbyWorldController] start behavior failed: " + result.Error);
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerator EnsureActionPadUIAsync()
|
||||
{
|
||||
EnsureEventSystem();
|
||||
if (actionPadRoot != null)
|
||||
{
|
||||
actionPadRoot.gameObject.SetActive(joined);
|
||||
yield break;
|
||||
}
|
||||
if (actionPadLoading)
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
actionPadLoading = true;
|
||||
|
||||
UObject prefab = null;
|
||||
yield return XResLoader.coLoadRes(ActionPadPrefabPath, typeof(GameObject), o => prefab = o);
|
||||
actionPadLoading = false;
|
||||
if (actionPadRoot != null)
|
||||
{
|
||||
actionPadRoot.gameObject.SetActive(joined);
|
||||
yield break;
|
||||
}
|
||||
|
||||
GameObject prefabObj = prefab as GameObject;
|
||||
if (prefabObj == null)
|
||||
{
|
||||
Debug.LogError("[LobbyWorldController] load action pad prefab failed: " + ActionPadPrefabPath);
|
||||
yield break;
|
||||
}
|
||||
|
||||
GameObject rootObj = Instantiate(prefabObj);
|
||||
UIManager.AttachTo(UILayer.HUD, rootObj);
|
||||
rootObj.name = "UI_VirtualActionPad";
|
||||
actionPadRoot = rootObj.GetComponent<RectTransform>();
|
||||
if (actionPadRoot == null)
|
||||
{
|
||||
actionPadRoot = rootObj.AddComponent<RectTransform>();
|
||||
}
|
||||
actionPadRoot.localScale = Vector3.one;
|
||||
|
||||
virtualActionPad = rootObj.GetComponent<VirtualActionPad>();
|
||||
if (virtualActionPad == null)
|
||||
{
|
||||
virtualActionPad = rootObj.AddComponent<VirtualActionPad>();
|
||||
}
|
||||
virtualActionPad.ButtonEvent -= OnVirtualActionButtonEvent;
|
||||
virtualActionPad.ButtonEvent += OnVirtualActionButtonEvent;
|
||||
actionPadRoot.gameObject.SetActive(joined);
|
||||
}
|
||||
|
||||
private void ReleaseActionPadUI(bool destroyObject)
|
||||
{
|
||||
if (virtualActionPad != null)
|
||||
{
|
||||
virtualActionPad.ButtonEvent -= OnVirtualActionButtonEvent;
|
||||
}
|
||||
|
||||
GameObject rootObj = actionPadRoot != null ? actionPadRoot.gameObject : null;
|
||||
virtualActionPad = null;
|
||||
actionPadRoot = null;
|
||||
actionPadLoading = false;
|
||||
|
||||
if (destroyObject && rootObj != null)
|
||||
{
|
||||
DestroyUnityObject(rootObj);
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerator EnsureJoystickUIAsync()
|
||||
{
|
||||
EnsureEventSystem();
|
||||
|
||||
Reference in New Issue
Block a user