XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet

AshfallFrontier

【Unity】灰烬边境,一款生存策略游戏

公开
关注 0 Fork 0 Star 0
UTF-8
using System;

namespace Ashfall.Core
{
    [Serializable]
    public struct V2
    {
        public float x, y;
        public V2(float x, float y) { this.x = x; this.y = y; }
        public float Length => (float)Math.Sqrt(x * x + y * y);
        public float SqrLength => x * x + y * y;
        public bool Finite => MathEx.Finite(x) && MathEx.Finite(y);
        public V2 Normalized => Length > .0001f ? this / Length : new V2();
        public static V2 operator +(V2 a, V2 b) => new V2(a.x + b.x, a.y + b.y);
        public static V2 operator -(V2 a, V2 b) => new V2(a.x - b.x, a.y - b.y);
        public static V2 operator *(V2 a, float b) => new V2(a.x * b, a.y * b);
        public static V2 operator /(V2 a, float b) => new V2(a.x / b, a.y / b);
        public static float Distance(V2 a, V2 b) => (a - b).Length;
        public static float Dot(V2 a, V2 b) => a.x * b.x + a.y * b.y;
        public static V2 Lerp(V2 a, V2 b, float t) => a + (b - a) * MathEx.Clamp(t, 0, 1);
        public V2 Rotate(float degrees)
        {
            double r = degrees * Math.PI / 180;
            return new V2((float)(x * Math.Cos(r) - y * Math.Sin(r)),
                (float)(x * Math.Sin(r) + y * Math.Cos(r)));
        }
        public override string ToString() => $"({x:0.00}, {y:0.00})";
    }

    [Serializable]
    public struct Box2
    {
        public V2 center, size;
        public Box2(V2 center, V2 size) { this.center = center; this.size = size; }
        public bool Contains(V2 p, float inset = 0) =>
            Math.Abs(p.x - center.x) <= size.x * .5f - inset &&
            Math.Abs(p.y - center.y) <= size.y * .5f - inset;
        public bool Overlaps(Box2 b, float gap = 0) =>
            Math.Abs(center.x - b.center.x) < (size.x + b.size.x) * .5f + gap &&
            Math.Abs(center.y - b.center.y) < (size.y + b.size.y) * .5f + gap;
        public bool BlocksSegment(V2 a, V2 b, float padding = 0)
        {
            float near = 0, far = 1;
            V2 d = b - a;
            return Clip(a.x, d.x, center.x - size.x / 2 - padding, center.x + size.x / 2 + padding, ref near, ref far)
                && Clip(a.y, d.y, center.y - size.y / 2 - padding, center.y + size.y / 2 + padding, ref near, ref far);
        }
        private static bool Clip(float start, float direction, float min, float max, ref float near, ref float far)
        {
            if (Math.Abs(direction) < .00001f) return start >= min && start <= max;
            float a = (min - start) / direction, b = (max - start) / direction;
            if (a > b) { float t = a; a = b; b = t; }
            near = Math.Max(near, a); far = Math.Min(far, b);
            return near <= far;
        }
    }

    public static class MathEx
    {
        public static bool Finite(float f) => !float.IsNaN(f) && !float.IsInfinity(f);
        public static float Clamp(float f, float a, float b) => Math.Max(a, Math.Min(f, b));
        public static float Approach(float value, float target, float amount) => value < target
            ? Math.Min(target, value + amount) : Math.Max(target, value - amount);
        public static float Angle(V2 direction) => (float)(Math.Atan2(direction.y, direction.x) * 180 / Math.PI) - 90;
        public static float DeltaAngle(float a, float b) => ((b - a + 540) % 360 + 360) % 360 - 180;
        public static float NormalizeAngle(float value) => (value % 360 + 360) % 360;
    }

    public static class Projection
    {
        public const float GroundScale = .819152f;
        public const float HeightScale = .573576f;
        public static V2 ToScreen(V2 ground, float height = 0) =>
            new V2(ground.x, ground.y * GroundScale + height * HeightScale);
        public static V2 ToGround(V2 screen, float height = 0) =>
            new V2(screen.x, (screen.y - height * HeightScale) / GroundScale);
        public static V2 InteriorToWorld(V2 local, V2 origin, float heading) => origin + local.Rotate(heading);
        public static V2 WorldToInterior(V2 world, V2 origin, float heading) => (world - origin).Rotate(-heading);
    }

    public enum Species { Human, Brood }
    public enum BroodForm { Worm, Adult }
    public enum Family { Mechanical, Biological }
    public enum SpaceKind { Exterior, Building, Vehicle }
    public enum StationRole { Driver, Gunner }
    public enum FlightMode { Ground, Low, Cruise }
    public enum PieceKind { Floor, Wall, Door, Stairs, Research, Generator, Storage, Turret }
    public enum FacilityKind { Research, Generator, Storage, Workshop, Medical }
    public enum CommandKind { Interact, LeaveStation, InstallModule, Build, Dismantle, Research, Craft, Transfer, Cruise, ChangeAltitude, Repair, SwitchSpecies, Ability, Collect, Evolve }

    [Serializable]
    public class ActionResult
    {
        public bool success;
        public string message;
        public static ActionResult Ok(string text = "完成") => new ActionResult { success = true, message = text };
        public static ActionResult Fail(string text) => new ActionResult { success = false, message = text };
    }
}