diff options
| author | Sarah B <git@sarahduck.ca> | 2023-12-24 21:04:19 -0800 |
|---|---|---|
| committer | Sarah B <git@sarahduck.ca> | 2023-12-24 21:04:19 -0800 |
| commit | 0206e04e0a3542b8f0fc97996f1d885f7604a6fa (patch) | |
| tree | 575f1388978b110064993445b73dcf268218a750 | |
| parent | c4dd5d6fe58a21f9cab5ce271cd3554c2fe791e3 (diff) | |
network mouse click, restructure oneko, add framework for NPCState stuff
| -rw-r--r-- | MathExtensions.cs | 2 | ||||
| -rw-r--r-- | Mouse.cs | 2 | ||||
| -rw-r--r-- | MouseLocal.cs | 6 | ||||
| -rw-r--r-- | MouseNet.cs | 4 | ||||
| -rw-r--r-- | Net.cs | 16 | ||||
| -rw-r--r-- | NetServer.cs | 2 | ||||
| -rw-r--r-- | Oneko.cs | 171 | ||||
| -rw-r--r-- | OnekoLocal.cs | 55 | ||||
| -rw-r--r-- | OnekoNet.cs | 15 |
9 files changed, 158 insertions, 115 deletions
diff --git a/MathExtensions.cs b/MathExtensions.cs index 81db592..2e74442 100644 --- a/MathExtensions.cs +++ b/MathExtensions.cs @@ -28,6 +28,4 @@ public static class Directions public static readonly Vector2 UpRight = Vector2.Normalize(Up+Right); public static readonly Vector2 DownLeft = Vector2.Normalize(Down+Left); public static readonly Vector2 DownRight = Vector2.Normalize(Down+Right); - - public static readonly Vector2[] AllDirections = [Up,Down,Left,Right,UpLeft,UpRight,DownLeft,DownRight]; }
\ No newline at end of file @@ -13,6 +13,8 @@ abstract class Mouse : Drawable protected static List<Mouse> allMice = []; public static ReadOnlyCollection<Mouse> AllMice => allMice.AsReadOnly(); + public static Action<Mouse>? Clicked; + public Mouse() : base() { DrawOrder = 100; diff --git a/MouseLocal.cs b/MouseLocal.cs index 6a84731..0b38cd5 100644 --- a/MouseLocal.cs +++ b/MouseLocal.cs @@ -19,10 +19,14 @@ class MouseLocal : Mouse Visible = Raylib.IsCursorOnScreen() && Raylib.IsWindowFocused(); Position = Raylib.GetMousePosition()/OnekoOnline.WindowScale; + bool clicked = Raylib.IsMouseButtonPressed(MouseButton.MOUSE_BUTTON_LEFT); + if (clicked && Visible) Clicked?.Invoke(this); + if (Visible && OnekoOnline.Client!.Connected) { NetDataWriter writer = new(); - writer.Put(new PacketInfo(PacketType.MousePosition, OnekoOnline.Client.Id)); + writer.Put(new PacketInfo(PacketType.MouseState, OnekoOnline.Client.Id)); writer.Put(Position); + writer.Put(clicked); OnekoOnline.Client?.ConnectedServer.Send(writer, LiteNetLib.DeliveryMethod.Unreliable); } } diff --git a/MouseNet.cs b/MouseNet.cs index 9521a25..1588dd0 100644 --- a/MouseNet.cs +++ b/MouseNet.cs @@ -18,9 +18,11 @@ class MouseNet : Mouse }; Client.PacketRecived += (reader, user, packetType) => { - if (user != MyUser || packetType != PacketType.MousePosition) return; + if (user != MyUser || packetType != PacketType.MouseState) return; Position = reader.GetVector2(); + bool clicked = reader.GetBool(); + if (clicked) Clicked?.Invoke(this); InvisibleTimer = 0f; }; @@ -50,29 +50,23 @@ public static class NetExtensions public enum PacketType : byte { - MousePosition, - OnekoTargetPosition, + MouseState, + OnekoState, UserInfo, UserId, Disconnect, Invalid } -public struct PacketInfo +public struct PacketInfo(PacketType type, int id) { - public readonly PacketType Type; - public readonly int FromId; + public readonly PacketType Type = type; + public readonly int FromId = id; public const int SizeOf = sizeof(int) + 1; public readonly bool IsValid => Type != PacketType.Invalid; public static readonly PacketInfo InvalidPacket = new(PacketType.Invalid, -1); - public PacketInfo(PacketType type, int id) - { - Type = type; - FromId = id; - } - public readonly void Serialize(Span<byte> span) { span[0] = (byte)Type; diff --git a/NetServer.cs b/NetServer.cs index 5ff35f1..a8e3130 100644 --- a/NetServer.cs +++ b/NetServer.cs @@ -83,7 +83,7 @@ class Server } } - if (info.Type == PacketType.OnekoTargetPosition || info.Type == PacketType.MousePosition) { + if (info.Type == PacketType.OnekoState || info.Type == PacketType.MouseState) { writer.ResetWithInfo(new PacketInfo(info.Type, fromPeer.Id)); writer.Put(dataReader.GetRemainingBytes()); foreach (ServerUser toSend in users.Values) { @@ -4,19 +4,16 @@ using Raylib_cs; namespace OnekoOnline; -class Oneko : Drawable +abstract class Oneko : Drawable { public readonly Bitmap SpriteSheet; - OnekoAnimation Animation = ScratchSelf; + public Rectangle Sprite {get; protected set;} = Idle1; + protected Color ColorTint = Color.WHITE; - public Vector2 TargetPosition; - - float updateTimer = 0f; - const float updateRate = 1f/5f; - int Frame = 0; - int FrameCounter = 0; - - float InactivityTimer = 0f; + protected byte FrameId { + get => (byte)Array.IndexOf(FrameArray, Sprite); + set => Sprite = FrameArray[value]; + } public string Name = "Oneko"; @@ -50,36 +47,7 @@ class Oneko : Drawable Raylib.DrawTextEx(OnekoOnline.DefaultFont, Name, NametagPosition, 11, 0, Color.WHITE); //The neko - Raylib.DrawTexturePro(SpriteSheet.Texture, Animation.GetFrame(Frame), new Rectangle(Position.X, Position.Y, Size.X, Size.Y), Size/2, Rotation, Color.WHITE); - } - - public override void Update(float delta) - { - InactivityTimer += delta; - updateTimer += delta; - if (updateTimer < updateRate) return; - - OnekoUpdate(); - - updateTimer = 0f; - } - - public virtual void OnekoUpdate() - { - Vector2 TargetDirection = (TargetPosition-Position).LimitLength(10f); - if (TargetDirection.Length() > 1) { - Animation = GetDirectionalRun(TargetDirection); - InactivityTimer = 0f; - } - else Animation = Idle; - Position += TargetDirection; - - if (InactivityTimer > 3f) Animation = ScratchSelf; - if (InactivityTimer > 5f) Animation = Yawn; - if (InactivityTimer > 6f) Animation = Sleep; - - FrameCounter = (FrameCounter+1)%(Animation.AnimSpeed+1); - Frame = (int)MathF.Round((float)FrameCounter/(float)Animation.AnimSpeed); + Raylib.DrawTexturePro(SpriteSheet.Texture, Sprite, new Rectangle(Position.X, Position.Y, Size.X, Size.Y), Size/2, Rotation, ColorTint); } public override void Dispose() @@ -88,7 +56,7 @@ class Oneko : Drawable base.Dispose(); } - struct OnekoAnimation(Rectangle frame1, Rectangle frame2, byte animSpeed) + protected struct OnekoAnimation(Rectangle frame1, Rectangle frame2, byte animSpeed) { public byte AnimSpeed = animSpeed; Rectangle Frame1 = frame1; @@ -99,13 +67,13 @@ class Oneko : Drawable } } - static OnekoAnimation GetDirectionalRun(Vector2 direction) + static protected OnekoAnimation GetDirectionalRun(Vector2 direction) { direction = Vector2.Normalize(direction); Vector2 nearestDir = Directions.Up; float nearestDistance = 10f; - foreach (Vector2 dir in Directions.AllDirections) { + foreach (Vector2 dir in RunDirections.Keys) { float distanceCheck = Vector2.Distance(direction, dir); if (distanceCheck < nearestDistance) { nearestDir = dir; @@ -116,57 +84,57 @@ class Oneko : Drawable return RunDirections[nearestDir]; } - static readonly Rectangle Idle1 = new(32*3, 32*3, 32, 32); - static readonly Rectangle Alert1 = new(32*7, 32*3, 32, 32); - static readonly Rectangle Yawn1 = new(32*3, 32*2, 32, 32); - static readonly Rectangle Clean1 = new(32*7, 0, 32, 32); - static readonly Rectangle Scratch1 = new(32*5, 0, 32, 32); - static readonly Rectangle Scratch2 = new(32*6, 0, 32, 32); - static readonly Rectangle Sleep1 = new(32*2, 0, 32, 32); - static readonly Rectangle Sleep2 = new(32*2, 32, 32, 32); - static readonly Rectangle RunUp1 = new(32, 32*3, 32, 32); - static readonly Rectangle RunUp2 = new(32, 32*2, 32, 32); - static readonly Rectangle RunUpLeft1 = new(32, 32, 32, 32); - static readonly Rectangle RunUpLeft2 = new(32, 0, 32, 32); - static readonly Rectangle RunLeft1 = new(32*4, 32*3, 32, 32); - static readonly Rectangle RunLeft2 = new(32*4, 32*2, 32, 32); - static readonly Rectangle RunDownLeft1 = new(32*6, 32, 32, 32); - static readonly Rectangle RunDownLeft2 = new(32*5, 32*3, 32, 32); - static readonly Rectangle RunDown1 = new(32*7, 32*2, 32, 32); - static readonly Rectangle RunDown2 = new(32*6, 32*3, 32, 32); - static readonly Rectangle RunDownRight1 = new(32*5, 32*2, 32, 32); - static readonly Rectangle RunDownRight2 = new(32*5, 32, 32, 32); - static readonly Rectangle RunRight1 = new(32*3, 32, 32, 32); - static readonly Rectangle RunRight2 = new(32*3, 0, 32, 32); - static readonly Rectangle RunUpRight1 = new(0, 32*3, 32, 32); - static readonly Rectangle RunUpRight2 = new(0, 32*2, 32, 32); - static readonly Rectangle ScratchUp1 = new(0, 0, 32, 32); - static readonly Rectangle ScratchUp2 = new(0, 32, 32, 32); - static readonly Rectangle ScratchLeft1 = new(32*4, 0, 32, 32); - static readonly Rectangle ScratchLeft2 = new(32*4, 32, 32, 32); - static readonly Rectangle ScratchDown1 = new(32*7, 32, 32, 32); - static readonly Rectangle ScratchDown2 = new(32*6, 32*2, 32, 32); - static readonly Rectangle ScratchRight1 = new(32*2, 32*2, 32, 32); - static readonly Rectangle ScratchRight2 = new(32*2, 32*3, 32, 32); - - static readonly OnekoAnimation Idle = new(Idle1, Idle1, 1); - static readonly OnekoAnimation Alert = new(Alert1, Alert1, 1); - static readonly OnekoAnimation Yawn = new(Yawn1, Yawn1, 1); - static readonly OnekoAnimation Clean = new(Clean1, Clean1, 1); - static readonly OnekoAnimation ScratchSelf = new(Scratch1, Scratch2, 1); - static readonly OnekoAnimation Sleep = new(Sleep1, Sleep2, 10); - static readonly OnekoAnimation RunUp = new(RunUp1, RunUp2, 1); - static readonly OnekoAnimation RunUpLeft = new(RunUpLeft1, RunUpLeft2, 1); - static readonly OnekoAnimation RunLeft = new(RunLeft1, RunLeft2, 1); - static readonly OnekoAnimation RunDownLeft = new(RunDownLeft1, RunDownLeft2, 1); - static readonly OnekoAnimation RunDown = new(RunDown1, RunDown2, 1); - static readonly OnekoAnimation RunDownRight = new(RunDownRight1, RunDownRight2, 1); - static readonly OnekoAnimation RunRight = new(RunRight1, RunRight2, 1); - static readonly OnekoAnimation RunUpRight = new(RunUpRight1, RunUpRight2, 1); - static readonly OnekoAnimation ScratchUp = new(ScratchUp1, ScratchUp2, 1); - static readonly OnekoAnimation ScratchLeft = new(ScratchLeft1, ScratchLeft2, 1); - static readonly OnekoAnimation ScratchDown = new(ScratchDown1, ScratchDown2, 1); - static readonly OnekoAnimation ScratchRight = new(ScratchRight1, ScratchRight2, 1); + static protected readonly Rectangle Idle1 = new(32*3, 32*3, 32, 32); + static protected readonly Rectangle Alert1 = new(32*7, 32*3, 32, 32); + static protected readonly Rectangle Yawn1 = new(32*3, 32*2, 32, 32); + static protected readonly Rectangle Clean1 = new(32*7, 0, 32, 32); + static protected readonly Rectangle Scratch1 = new(32*5, 0, 32, 32); + static protected readonly Rectangle Scratch2 = new(32*6, 0, 32, 32); + static protected readonly Rectangle Sleep1 = new(32*2, 0, 32, 32); + static protected readonly Rectangle Sleep2 = new(32*2, 32, 32, 32); + static protected readonly Rectangle RunUp1 = new(32, 32*3, 32, 32); + static protected readonly Rectangle RunUp2 = new(32, 32*2, 32, 32); + static protected readonly Rectangle RunUpLeft1 = new(32, 32, 32, 32); + static protected readonly Rectangle RunUpLeft2 = new(32, 0, 32, 32); + static protected readonly Rectangle RunLeft1 = new(32*4, 32*3, 32, 32); + static protected readonly Rectangle RunLeft2 = new(32*4, 32*2, 32, 32); + static protected readonly Rectangle RunDownLeft1 = new(32*6, 32, 32, 32); + static protected readonly Rectangle RunDownLeft2 = new(32*5, 32*3, 32, 32); + static protected readonly Rectangle RunDown1 = new(32*7, 32*2, 32, 32); + static protected readonly Rectangle RunDown2 = new(32*6, 32*3, 32, 32); + static protected readonly Rectangle RunDownRight1 = new(32*5, 32*2, 32, 32); + static protected readonly Rectangle RunDownRight2 = new(32*5, 32, 32, 32); + static protected readonly Rectangle RunRight1 = new(32*3, 32, 32, 32); + static protected readonly Rectangle RunRight2 = new(32*3, 0, 32, 32); + static protected readonly Rectangle RunUpRight1 = new(0, 32*3, 32, 32); + static protected readonly Rectangle RunUpRight2 = new(0, 32*2, 32, 32); + static protected readonly Rectangle ScratchUp1 = new(0, 0, 32, 32); + static protected readonly Rectangle ScratchUp2 = new(0, 32, 32, 32); + static protected readonly Rectangle ScratchLeft1 = new(32*4, 0, 32, 32); + static protected readonly Rectangle ScratchLeft2 = new(32*4, 32, 32, 32); + static protected readonly Rectangle ScratchDown1 = new(32*7, 32, 32, 32); + static protected readonly Rectangle ScratchDown2 = new(32*6, 32*2, 32, 32); + static protected readonly Rectangle ScratchRight1 = new(32*2, 32*2, 32, 32); + static protected readonly Rectangle ScratchRight2 = new(32*2, 32*3, 32, 32); + + static protected readonly OnekoAnimation Idle = new(Idle1, Idle1, 1); + static protected readonly OnekoAnimation Alert = new(Alert1, Alert1, 1); + static protected readonly OnekoAnimation Yawn = new(Yawn1, Yawn1, 1); + static protected readonly OnekoAnimation Clean = new(Clean1, Clean1, 1); + static protected readonly OnekoAnimation ScratchSelf = new(Scratch1, Scratch2, 1); + static protected readonly OnekoAnimation Sleep = new(Sleep1, Sleep2, 10); + static protected readonly OnekoAnimation RunUp = new(RunUp1, RunUp2, 1); + static protected readonly OnekoAnimation RunUpLeft = new(RunUpLeft1, RunUpLeft2, 1); + static protected readonly OnekoAnimation RunLeft = new(RunLeft1, RunLeft2, 1); + static protected readonly OnekoAnimation RunDownLeft = new(RunDownLeft1, RunDownLeft2, 1); + static protected readonly OnekoAnimation RunDown = new(RunDown1, RunDown2, 1); + static protected readonly OnekoAnimation RunDownRight = new(RunDownRight1, RunDownRight2, 1); + static protected readonly OnekoAnimation RunRight = new(RunRight1, RunRight2, 1); + static protected readonly OnekoAnimation RunUpRight = new(RunUpRight1, RunUpRight2, 1); + static protected readonly OnekoAnimation ScratchUp = new(ScratchUp1, ScratchUp2, 1); + static protected readonly OnekoAnimation ScratchLeft = new(ScratchLeft1, ScratchLeft2, 1); + static protected readonly OnekoAnimation ScratchDown = new(ScratchDown1, ScratchDown2, 1); + static protected readonly OnekoAnimation ScratchRight = new(ScratchRight1, ScratchRight2, 1); static readonly Dictionary<Vector2, OnekoAnimation> RunDirections = new() { {Directions.Up, RunUp}, @@ -178,4 +146,19 @@ class Oneko : Drawable {Directions.DownRight, RunDownRight}, {Directions.DownLeft, RunDownLeft}, }; + + static readonly Rectangle[] FrameArray = [ + Idle1, Alert1, Yawn1, Clean1, + Scratch1, Scratch2, Sleep1, Sleep2, + RunUp1,RunUpLeft1, RunLeft1, RunDownLeft1, RunDown1, RunDownRight1, RunRight1, RunUpRight1, + RunUp2,RunUpLeft2, RunLeft2, RunDownLeft2, RunDown2, RunDownRight2, RunRight2, RunUpRight2, + ScratchUp1, ScratchLeft1, ScratchDown1, ScratchRight1, + ScratchUp2, ScratchLeft2, ScratchDown2, ScratchRight2 + ]; + + static readonly OnekoAnimation[] AnimationArray = [ + Idle, Alert, Yawn, Clean, ScratchSelf, Sleep, + RunUp,RunUpLeft, RunLeft, RunDownLeft, RunDown, RunDownRight, RunRight, RunUpRight, + ScratchUp, ScratchLeft, ScratchDown, ScratchRight + ]; }
\ No newline at end of file diff --git a/OnekoLocal.cs b/OnekoLocal.cs index 00eaf82..c33dd66 100644 --- a/OnekoLocal.cs +++ b/OnekoLocal.cs @@ -11,6 +11,17 @@ class OnekoLocal : Oneko static int Id => OnekoOnline.Client?.Id ?? -1; + OnekoAIState? CurrentAIState; + + Vector2 TargetPosition = Vector2.Zero; + float InactivityTimer = 0f; + + OnekoAnimation Animation; + float updateTimer = 0f; + const float updateRate = 1f/5f; + int Frame = 0; + int FrameCounter = 0; + public OnekoLocal() : base() { Instance ??= this; @@ -20,19 +31,55 @@ class OnekoLocal : Oneko Name = Client.UserName; } - public override void OnekoUpdate() + public override void Update(float delta) + { + updateTimer += delta; + if (updateTimer < updateRate) return; + + OnekoUpdate(updateTimer); + updateTimer = 0f; + } + + public void OnekoUpdate(float delta) { + InactivityTimer += delta; + Mouse? NearestMouse = Mouse.AllMice.Where(m => m.Visible).MinBy(m => Vector2.Distance(m.Position, Position)); if (NearestMouse != null) TargetPosition = NearestMouse.Position; else TargetPosition = new Vector2(Math.Clamp((Id+1)*40, 20, 300), 240/2); + Vector2 TargetDirection = (TargetPosition-Position).LimitLength(10f); + if (TargetDirection.Length() > 1) { + Animation = GetDirectionalRun(TargetDirection); + InactivityTimer = 0f; + } + else Animation = Idle; + Position += TargetDirection; + + if (InactivityTimer > 3f) Animation = ScratchSelf; + if (InactivityTimer > 5f) Animation = Yawn; + if (InactivityTimer > 6f) Animation = Sleep; + + FrameCounter = (FrameCounter+1)%(Animation.AnimSpeed+1); + Frame = (int)MathF.Round(FrameCounter/(float)Animation.AnimSpeed); + + Sprite = Animation.GetFrame(Frame); + if (OnekoOnline.Client!.Connected) { NetDataWriter writer = new(); - writer.Put(new PacketInfo(PacketType.OnekoTargetPosition, Id)); - writer.Put(TargetPosition); + writer.Put(new PacketInfo(PacketType.OnekoState, Id)); + writer.Put(Position); + writer.Put(FrameId); OnekoOnline.Client?.ConnectedServer.Send(writer, LiteNetLib.DeliveryMethod.Unreliable); } + } + + protected abstract class OnekoAIState(OnekoLocal neko) + { + protected OnekoLocal Neko = neko; - base.OnekoUpdate(); + public abstract int GetPriority(); + public abstract void Update(float delta); + protected bool IsCurrentState => Neko.CurrentAIState == this; } }
\ No newline at end of file diff --git a/OnekoNet.cs b/OnekoNet.cs index 27d6187..a5b2008 100644 --- a/OnekoNet.cs +++ b/OnekoNet.cs @@ -10,6 +10,8 @@ class OnekoNet : Oneko public static Dictionary<int, OnekoNet> NetNekos = []; + float NetworkIssueTimer = 0f; + public OnekoNet(Bitmap bitmap, User user) : base(bitmap) { MyUser = user; @@ -22,12 +24,23 @@ class OnekoNet : Oneko Client.PacketRecived += (reader, user, packetType) => { if (user != MyUser) return; - if (packetType == PacketType.OnekoTargetPosition) TargetPosition = reader.GetVector2(); + if (packetType == PacketType.OnekoState) { + Position = reader.GetVector2(); + FrameId = reader.GetByte(); + NetworkIssueTimer = 0f; + } }; Client.ServerDisconnected += Dispose; } + public override void Update(float delta) + { + NetworkIssueTimer += delta; + if (NetworkIssueTimer < 0.6f) ColorTint = Color.WHITE; + else ColorTint = Color.WHITE with {A = 120}; + } + public static void SpawnNetNeko(User user) { if (!NetNekos.ContainsKey(user.Id)) { |
