diff --git a/X10D.Tests/X10D.Tests.csproj b/X10D.Tests/X10D.Tests.csproj index 684b34a..bdba516 100644 --- a/X10D.Tests/X10D.Tests.csproj +++ b/X10D.Tests/X10D.Tests.csproj @@ -24,9 +24,11 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive + + diff --git a/X10D.Tests/src/Unity/Vector3Tests.cs b/X10D.Tests/src/Unity/Vector3Tests.cs new file mode 100644 index 0000000..2e02cf0 --- /dev/null +++ b/X10D.Tests/src/Unity/Vector3Tests.cs @@ -0,0 +1,93 @@ +namespace X10D.Tests.Unity +{ + using Microsoft.VisualStudio.TestTools.UnitTesting; + using UnityEngine; + using X10D.Unity; + + /// + /// Tests for . + /// + [TestClass] + public class Vector3Tests + { + /// + /// Tests for by rounding to the nearest 0.5. + /// + [TestMethod] + public void TestRoundHalf() + { + var vector = new Vector3(1.8f, 2.1f, 3.37f); + Assert.AreEqual(new Vector3(2, 2, 3.5f), vector.Round(0.5f)); + } + + /// + /// Tests for by rounding to the nearest integer. + /// + [TestMethod] + public void TestRoundInteger() + { + var vector = new Vector3(1.8f, 2.1f, 3.37f); + Assert.AreEqual(new Vector3(2, 2, 3), vector.Round()); + } + + /// + /// Tests for . + /// + [TestMethod] + public void TestWithX() + { + var vector = new Vector3(1, 2, 3); + Assert.AreEqual(new Vector3(4, 2, 3), vector.WithX(4)); + } + + /// + /// Tests for . + /// + [TestMethod] + public void TestWithXY() + { + var vector = new Vector3(1, 2, 3); + Assert.AreEqual(new Vector3(8, 10, 3), vector.WithXY(8, 10)); + } + + /// + /// Tests for . + /// + [TestMethod] + public void TestWithXZ() + { + var vector = new Vector3(1, 2, 3); + Assert.AreEqual(new Vector3(8, 2, 10), vector.WithXZ(8, 10)); + } + + /// + /// Tests for . + /// + [TestMethod] + public void TestWithY() + { + var vector = new Vector3(1, 2, 3); + Assert.AreEqual(new Vector3(1, 4, 3), vector.WithY(4)); + } + + /// + /// Tests for . + /// + [TestMethod] + public void TestWithYZ() + { + var vector = new Vector3(1, 2, 3); + Assert.AreEqual(new Vector3(1, 8, 10), vector.WithYZ(8, 10)); + } + + /// + /// Tests for . + /// + [TestMethod] + public void TestWithZ() + { + var vector = new Vector3(1, 2, 3); + Assert.AreEqual(new Vector3(1, 2, 4), vector.WithZ(4)); + } + } +} diff --git a/X10D.Unity/X10D.Unity.csproj b/X10D.Unity/X10D.Unity.csproj new file mode 100644 index 0000000..41ea494 --- /dev/null +++ b/X10D.Unity/X10D.Unity.csproj @@ -0,0 +1,72 @@ + + + + netstandard2.0 + 8.0 + Oliver Booth + en + true + https://github.com/oliverbooth/X10D + git + Extension methods on crack. + LICENSE.md + icon.png + + dotnet extension-methods unity + 2.2.0 + ..\X10D.ruleset + true + 2.4.0 + 2.4.0 + 2.4.0 + + + + + True + + + + True + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + + + + + + + + + + True + True + Resource.resx + + + + + + ResXFileCodeGenerator + Resource.Designer.cs + + + + \ No newline at end of file diff --git a/X10D.Unity/src/BetterBehavior.cs b/X10D.Unity/src/BetterBehavior.cs new file mode 100644 index 0000000..6069676 --- /dev/null +++ b/X10D.Unity/src/BetterBehavior.cs @@ -0,0 +1,107 @@ +namespace X10D.Unity +{ + using System.Diagnostics.CodeAnalysis; + using System.Threading.Tasks; + using UnityEngine; + + /// + /// Represents a class which inherits to offer wider functionality. + /// + [SuppressMessage("ReSharper", "MemberCanBePrivate.Global", Justification = "Unity property")] + [SuppressMessage("ReSharper", "UnusedAutoPropertyAccessor.Global", Justification = "Unity property")] + [SuppressMessage("ReSharper", "SA1300", Justification = "Unity API-compliant property")] + [SuppressMessage("ReSharper", "CA2007", Justification = "Unnecessary")] + [SuppressMessage("ReSharper", "RCS1090", Justification = "Unnecessary")] + [SuppressMessage("ReSharper", "RCS1213", Justification = "Unity method")] + [SuppressMessage("ReSharper", "UnusedParameter.Global", Justification = "Override method")] + public abstract class BetterBehavior : MonoBehaviour + { + /// + /// Gets the component attached to this object. + /// + public new Transform transform { get; private set; } + + /// + /// Awake is called when the script instance is being loaded. + /// + protected virtual void Awake() + { + this.transform = this.GetComponent(); + } + + /// + /// Frame-rate independent messaging for physics calculations. + /// + /// A snapshot of timing values. + protected virtual void OnFixedUpdate(in GameTime gameTime) + { + } + + /// + /// Frame-rate independent messaging for physics calculations. + /// + /// A snapshot of timing values. + /// Returns a task representing the result of the operation. + protected virtual Task OnFixedUpdateAsync(GameTime gameTime) + { + return Task.CompletedTask; + } + + /// + /// Called once per frame, after all Update calls. + /// + /// A snapshot of timing values. + protected virtual void OnLateUpdate(in GameTime gameTime) + { + } + + /// + /// Called once per frame, after all Update calls. + /// + /// A snapshot of timing values. + /// Returns a task representing the result of the operation. + protected virtual Task OnLateUpdateAsync(GameTime gameTime) + { + return Task.CompletedTask; + } + + /// + /// Called once per frame. + /// + /// A snapshot of timing values. + protected virtual void OnUpdate(in GameTime gameTime) + { + } + + /// + /// Called once per frame. + /// + /// A snapshot of timing values. + /// Returns a task representing the result of the operation. + protected virtual Task OnUpdateAsync(GameTime gameTime) + { + return Task.CompletedTask; + } + + private async void FixedUpdate() + { + var time = GameTime.CreateFromCurrentTimes(); + this.OnFixedUpdate(time); + await this.OnFixedUpdateAsync(time); + } + + private async void LateUpdate() + { + var time = GameTime.CreateFromCurrentTimes(); + this.OnLateUpdate(time); + await this.OnLateUpdateAsync(time); + } + + private async void Update() + { + var time = GameTime.CreateFromCurrentTimes(); + this.OnUpdate(time); + await this.OnUpdateAsync(time); + } + } +} diff --git a/X10D.Unity/src/GameObjectExtensions.cs b/X10D.Unity/src/GameObjectExtensions.cs new file mode 100644 index 0000000..3341e87 --- /dev/null +++ b/X10D.Unity/src/GameObjectExtensions.cs @@ -0,0 +1,64 @@ +namespace X10D.Unity +{ + using System; + using JetBrains.Annotations; + using UnityEngine; + + /// + /// Extension methods for . + /// + public static class GameObjectExtensions + { + /// + /// Rotates the component on the current such that is is facing another + /// . + /// + /// The current game object. + /// The target. + /// + /// is null + /// - or - + /// is null. + /// + public static void LookAt([NotNull] this GameObject gameObject, [NotNull] GameObject other) + { + if (gameObject is null) + { + throw new ArgumentNullException(nameof(gameObject)); + } + + if (other is null) + { + throw new ArgumentNullException(nameof(other)); + } + + gameObject.LookAt(other.transform); + } + + /// + /// Rotates the component on the current such that is is facing another + /// . + /// + /// The current game object. + /// The target. + /// + /// is null + /// - or - + /// is null. + /// + public static void LookAt([NotNull] this GameObject gameObject, [NotNull] Transform other) + { + if (gameObject is null) + { + throw new ArgumentNullException(nameof(gameObject)); + } + + if (other is null) + { + throw new ArgumentNullException(nameof(other)); + } + + gameObject.transform.LookAt(other); + } + } +} diff --git a/X10D.Unity/src/GameTime.cs b/X10D.Unity/src/GameTime.cs new file mode 100644 index 0000000..f59a6df --- /dev/null +++ b/X10D.Unity/src/GameTime.cs @@ -0,0 +1,54 @@ +namespace X10D.Unity +{ + using System; + using UnityEngine; + + /// + /// Represents a struct which contains game timing information. + /// + public readonly struct GameTime + { + private GameTime(float totalTime, float deltaTime, float fixedDeltaTime, int frameCount, float timeScale) + { + this.TotalTime = TimeSpan.FromSeconds(totalTime); + this.DeltaTime = TimeSpan.FromSeconds(deltaTime); + this.FixedDeltaTime = TimeSpan.FromSeconds(fixedDeltaTime); + this.FrameCount = frameCount; + this.TimeScale = timeScale; + } + + /// + /// Gets the time since the last frame was rendered. + /// + public TimeSpan DeltaTime { get; } + + /// + /// Gets the time since the last physics time step. + /// + public TimeSpan FixedDeltaTime { get; } + + /// + /// Gets the total number of frames which have been rendered. + /// + public int FrameCount { get; } + + /// + /// Gets the total time for which the game has been running. + /// + public TimeSpan TotalTime { get; } + + /// + /// Gets the time scale. + /// + public float TimeScale { get; } + + /// + /// Creates a new instance of the struct by creating a snapshot of values offered by . + /// + /// An instance of . + public static GameTime CreateFromCurrentTimes() + { + return new GameTime(Time.time, Time.deltaTime, Time.fixedDeltaTime, Time.frameCount, Time.timeScale); + } + } +} diff --git a/X10D.Unity/src/TransformExtensions.cs b/X10D.Unity/src/TransformExtensions.cs new file mode 100644 index 0000000..6cdb7e3 --- /dev/null +++ b/X10D.Unity/src/TransformExtensions.cs @@ -0,0 +1,37 @@ +namespace X10D.Unity +{ + using System; + using JetBrains.Annotations; + using UnityEngine; + + /// + /// Extension methods for . + /// + public static class TransformExtensions + { + /// + /// Rotates the current such that is is facing another . + /// + /// The current transform. + /// The target. + /// + /// is null + /// - or - + /// is null. + /// + public static void LookAt([NotNull] this Transform transform, [NotNull] GameObject other) + { + if (transform is null) + { + throw new ArgumentNullException(nameof(transform)); + } + + if (other is null) + { + throw new ArgumentNullException(nameof(other)); + } + + transform.LookAt(other.transform); + } + } +} diff --git a/X10D.Unity/src/Vector3Extensions.cs b/X10D.Unity/src/Vector3Extensions.cs new file mode 100644 index 0000000..3f9b1eb --- /dev/null +++ b/X10D.Unity/src/Vector3Extensions.cs @@ -0,0 +1,111 @@ +namespace X10D.Unity +{ + using UnityEngine; + + /// + /// Extension methods for . + /// + public static class Vector3Extensions + { + /// + /// Rounds a by calling on each of the components. + /// + /// The vector to round. + /// The nearest value. + /// rounded to the nearest . + public static Vector3 Round(this Vector3 vector, float nearest = 1) + { + return new Vector3(vector.x.Round(nearest), vector.y.Round(nearest), vector.z.Round(nearest)); + } + + /// + /// Returns a vector whose Y and Z components match that of a provided vector, and sets the X component to a provided value. + /// + /// The input vector. + /// The new X value. + /// + /// Returns a whose Y and Z components match that of , + /// but with the component set to . + /// + public static Vector3 WithX(this Vector3 vector, float x) + { + return new Vector3(x, vector.y, vector.z); + } + + /// + /// Returns a vector whose Z component matches that of a provided vector, and sets the X and Y components to provided values. + /// + /// The input vector. + /// The new X value. + /// The new Y value. + /// + /// Returns a whose Z component matches that of , + /// but with the and components set to and + /// respectively. + /// + public static Vector3 WithXY(this Vector3 vector, float x, float y) + { + return new Vector3(x, y, vector.z); + } + + /// + /// Returns a vector whose Y component matches that of a provided vector, and sets the X and Z components to provided values. + /// + /// The input vector. + /// The new X value. + /// The new Z value. + /// + /// Returns a whose Y component matches that of , + /// but with the and components set to and + /// respectively. + /// + public static Vector3 WithXZ(this Vector3 vector, float x, float z) + { + return new Vector3(x, vector.y, z); + } + + /// + /// Returns a vector whose X and Z components match that of a provided vector, and sets the Y component to a provided value. + /// + /// The input vector. + /// The new Y value. + /// + /// Returns a whose X and Z components match that of , + /// but with the component set to . + /// + public static Vector3 WithY(this Vector3 vector, float y) + { + return new Vector3(vector.x, y, vector.z); + } + + /// + /// Returns a vector whose X component matches that of a provided vector, and sets the Y and Z components to provided values. + /// + /// The input vector. + /// The new Y value. + /// The new Z value. + /// + /// Returns a whose X component matches that of , + /// but with the and components set to and + /// respectively. + /// + public static Vector3 WithYZ(this Vector3 vector, float y, float z) + { + return new Vector3(vector.x, y, z); + } + + /// + /// Returns a vector whose X and Y components match that of a provided vector, and sets the Z component to a provided value. + /// + /// The input vector. + /// The new Z value. + /// + /// Returns a whose X and Y components match that of , + /// but with the component set to . + /// + public static Vector3 WithZ(this Vector3 vector, float z) + { + return new Vector3(vector.x, vector.y, z); + } + } +} diff --git a/X10D.sln b/X10D.sln index 82dcd54..d20ed46 100644 --- a/X10D.sln +++ b/X10D.sln @@ -12,6 +12,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution .editorconfig = .editorconfig EndProjectSection EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "X10D.Unity", "X10D.Unity\X10D.Unity.csproj", "{C21ABC58-68D6-4CA0-9CE6-A2E96C5E89AE}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -26,6 +28,10 @@ Global {DF228EA2-D8EC-4A40-8917-E1E62E3B7D8E}.Debug|Any CPU.Build.0 = Debug|Any CPU {DF228EA2-D8EC-4A40-8917-E1E62E3B7D8E}.Release|Any CPU.ActiveCfg = Release|Any CPU {DF228EA2-D8EC-4A40-8917-E1E62E3B7D8E}.Release|Any CPU.Build.0 = Release|Any CPU + {C21ABC58-68D6-4CA0-9CE6-A2E96C5E89AE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C21ABC58-68D6-4CA0-9CE6-A2E96C5E89AE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C21ABC58-68D6-4CA0-9CE6-A2E96C5E89AE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C21ABC58-68D6-4CA0-9CE6-A2E96C5E89AE}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE