feat: add actor behavior client presentation

This commit is contained in:
ud18010
2026-07-30 16:27:27 +08:00
parent 8ef870ff6c
commit 03cee1036d
7 changed files with 518 additions and 0 deletions
@@ -0,0 +1,129 @@
using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;
using XGame.ActorBehavior;
using XWorld.Framework.ActorBehavior;
public sealed class ActorBehaviorPresentationRouterTests
{
[Test]
public void Dispatch_TimelineAnimation_PlaysAnimatorState()
{
var sink = new RecordingSink();
var router = new ActorBehaviorPresentationRouter();
router.Dispatch(new[]
{
new BehaviorEvent
{
Kind = BehaviorEventKind.TimelineAnimation,
ActorId = 7,
Animation = "140_skill01a_qt"
}
}, sink);
Assert.That(sink.Animations, Is.EqualTo(new[] { "7:140_skill01a_qt" }));
}
[Test]
public void Dispatch_TimelineEffect_PlaysPrefabAtEventPosition()
{
var sink = new RecordingSink();
var router = new ActorBehaviorPresentationRouter();
router.Dispatch(new[]
{
new BehaviorEvent
{
Kind = BehaviorEventKind.TimelineEffect,
ActorId = 7,
Prefab = "Assets/Game/Art/Effect/Prefab/skill/9110004_zhujue_quantao_skill01a.prefab",
Position = new BehaviorVector3(1f, 2f, 3f)
}
}, sink);
Assert.That(sink.Effects.Select(e => e.ActorId), Is.EqualTo(new[] { 7 }));
Assert.That(sink.Effects.Select(e => e.PrefabPath), Is.EqualTo(new[] { "Assets/Game/Art/Effect/Prefab/skill/9110004_zhujue_quantao_skill01a.prefab" }));
Assert.That(sink.Effects[0].Position.X, Is.EqualTo(1f));
Assert.That(sink.Effects[0].Position.Y, Is.EqualTo(2f));
Assert.That(sink.Effects[0].Position.Z, Is.EqualTo(3f));
Assert.That(sink.Effects[0].HasExplicitPosition, Is.True);
}
[Test]
public void Dispatch_ProjectileTimelineEffect_TreatsZeroPositionAsExplicitWorldPosition()
{
var sink = new RecordingSink();
var router = new ActorBehaviorPresentationRouter();
router.Dispatch(new[]
{
new BehaviorEvent
{
Kind = BehaviorEventKind.TimelineEffect,
ActorId = 7,
FlyObjectId = "arrow01",
Prefab = "Assets/Game/Art/Effect/Prefab/skill/hit.prefab",
Position = BehaviorVector3.Zero
}
}, sink);
Assert.That(sink.Effects[0].HasExplicitPosition, Is.True);
}
[Test]
public void Dispatch_BehaviorStopped_StopsActorPresentation()
{
var sink = new RecordingSink();
var router = new ActorBehaviorPresentationRouter();
router.Dispatch(new[]
{
new BehaviorEvent
{
Kind = BehaviorEventKind.BehaviorStopped,
ActorId = 7
}
}, sink);
Assert.That(sink.StoppedActors, Is.EqualTo(new[] { 7 }));
}
private sealed class RecordingSink : IActorBehaviorPresentationSink
{
public readonly List<string> Animations = new List<string>();
public readonly List<EffectRecord> Effects = new List<EffectRecord>();
public readonly List<int> StoppedActors = new List<int>();
public void PlayAnimation(int actorId, string stateName)
{
Animations.Add(actorId + ":" + stateName);
}
public void PlayEffect(int actorId, string prefabPath, BehaviorVector3 position, bool hasExplicitPosition)
{
Effects.Add(new EffectRecord(actorId, prefabPath, position, hasExplicitPosition));
}
public void StopActorPresentation(int actorId)
{
StoppedActors.Add(actorId);
}
}
private readonly struct EffectRecord
{
public readonly int ActorId;
public readonly string PrefabPath;
public readonly BehaviorVector3 Position;
public readonly bool HasExplicitPosition;
public EffectRecord(int actorId, string prefabPath, BehaviorVector3 position, bool hasExplicitPosition)
{
ActorId = actorId;
PrefabPath = prefabPath;
Position = position;
HasExplicitPosition = hasExplicitPosition;
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 28bdddb483244b36967eea08c1fe7f58
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: