using System.Numerics; using OnekoOnline.Net; using Raylib_cs; namespace OnekoOnline; class Oneko : Drawable { public readonly Bitmap SpriteSheet; OnekoAnimation Animation = ScratchSelf; public Vector2 TargetPosition; float updateTimer = 0f; const float updateRate = 1f/5f; int Frame = 0; float InactivityTimer = 0f; public string Name = "Oneko"; public Oneko() : base() { Size = new(32,32); Position = new(320/2, 240/2); string SpriteSheetPath = OnekoOnline.Config.GetValue("SpriteSheetPath", "nekos/oneko.png"); if (File.Exists(SpriteSheetPath) && new FileInfo(SpriteSheetPath).Length < 128*256*3) { SpriteSheet = Bitmap.FromPNGMemory(File.ReadAllBytes(SpriteSheetPath)); } else { Console.WriteLine("Path to spritesheet was invalid, using the default."); SpriteSheet = Bitmap.FromPNGMemory(EmbeddedResources.GetResource("nekos.oneko.png")); } } public Oneko(Bitmap spriteSheet) : base() { Size = new(32,32); Position = new(0, 0); SpriteSheet = spriteSheet; } public override void Draw() { //Nametag Vector2 NametagPosition = new(Position.X-(Name.Length*3)+4, Position.Y-28); Raylib.DrawTextEx(OnekoOnline.DefaultFont, Name, NametagPosition+Directions.Down, 11, 0, Color.BLACK); //Shadow 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; Frame = (Frame + 1) % 2; if (InactivityTimer > 3f) Animation = ScratchSelf; if (InactivityTimer > 5f) Animation = Sleep; } public override void Dispose() { SpriteSheet.Dispose(); base.Dispose(); } struct OnekoAnimation(Rectangle frame1, Rectangle frame2) { public Rectangle Frame1 = frame1; Rectangle Frame2 = frame2; public readonly Rectangle GetFrame(int frame) { return (frame % 2 == 0) ? Frame1 : Frame2; } } static OnekoAnimation GetDirectionalRun(Vector2 direction) { direction = Vector2.Normalize(direction); Vector2 nearestDir = Directions.Up; float nearestDistance = 10f; foreach (Vector2 dir in Directions.AllDirections) { float distanceCheck = Vector2.Distance(direction, dir); if (distanceCheck < nearestDistance) { nearestDir = dir; nearestDistance = distanceCheck; } } 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); static readonly OnekoAnimation Alert = new(Alert1, Alert1); static readonly OnekoAnimation Yawn = new(Yawn1, Yawn1); static readonly OnekoAnimation Clean = new(Clean1, Clean1); static readonly OnekoAnimation ScratchSelf = new(Scratch1, Scratch2); static readonly OnekoAnimation Sleep = new(Sleep1, Sleep2); static readonly OnekoAnimation RunUp = new(RunUp1, RunUp2); static readonly OnekoAnimation RunUpLeft = new(RunUpLeft1, RunUpLeft2); static readonly OnekoAnimation RunLeft = new(RunLeft1, RunLeft2); static readonly OnekoAnimation RunDownLeft = new(RunDownLeft1, RunDownLeft2); static readonly OnekoAnimation RunDown = new(RunDown1, RunDown2); static readonly OnekoAnimation RunDownRight = new(RunDownRight1, RunDownRight2); static readonly OnekoAnimation RunRight = new(RunRight1, RunRight2); static readonly OnekoAnimation RunUpRight = new(RunUpRight1, RunUpRight2); static readonly OnekoAnimation ScratchUp = new(ScratchUp1, ScratchUp2); static readonly OnekoAnimation ScratchLeft = new(ScratchLeft1, ScratchLeft2); static readonly OnekoAnimation ScratchDown = new(ScratchDown1, ScratchDown2); static readonly OnekoAnimation ScratchRight = new(ScratchRight1, ScratchRight2); static readonly Dictionary RunDirections = new() { {Directions.Up, RunUp}, {Directions.Down, RunDown}, {Directions.Left, RunLeft}, {Directions.Right, RunRight}, {Directions.UpLeft, RunUpLeft}, {Directions.UpRight, RunUpRight}, {Directions.DownRight, RunDownRight}, {Directions.DownLeft, RunDownLeft}, }; }