Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
62a2760
Game controller support
bijington Feb 11, 2025
2a6a319
Remove deprecated call
bijington Feb 11, 2025
11fa7ca
Some modifications to the game mode
bijington Feb 13, 2025
5ce7cbd
Update .NET SDK version
bijington Feb 13, 2025
7bb6d1f
Make jumping loosely work
bijington Feb 13, 2025
b78dd1c
Merge branch 'feature/game-controller-support' of github.com:bijingto…
bijington Feb 13, 2025
566e43b
Fix movement and jumping
bijington Feb 13, 2025
a0397b8
Introduce a controller manager to deal with detection of controllers
bijington Feb 14, 2025
3d91842
Add a best guess at something for Windows
bijington Feb 14, 2025
a351b7c
Tidy up
bijington Feb 14, 2025
64aeac2
Update dotnet-macos.yml
bijington Feb 14, 2025
7322e90
Update dotnet-windows.yml
bijington Feb 14, 2025
e460b10
Correct windows usings
bijington Feb 14, 2025
e69e42e
Merge branch 'feature/game-controller-support' of github.com:bijingto…
bijington Feb 14, 2025
31ca086
Assign properties
bijington Feb 14, 2025
cfac5aa
Add support for automatically attaching to views in Android
bijington Feb 19, 2025
7b8e398
Improvements for Windows
bijington Feb 20, 2025
e6afa86
Tidy up options
bijington Feb 23, 2025
a2067c5
Code tidy up
bijington Feb 24, 2025
8ea8ed0
Add in initial keyboard support
bijington Feb 25, 2025
11a55b9
Fix Windows options
bijington Feb 26, 2025
3a2a174
Add some readme bits
bijington Mar 2, 2025
32c8dad
Refactor to make it safer to lookup names
bijington Mar 2, 2025
6b5f0b9
Introduce float comparison
bijington Mar 2, 2025
f1096bb
Merge branch 'feature/game-controller-support' of github.com:bijingto…
bijington Mar 2, 2025
8a38cbf
Correct Windows to match new refactorings
bijington Mar 4, 2025
2ca611c
Add some extra options and start xml docs
bijington Mar 4, 2025
99df170
Merge branch 'feature/game-controller-support' of github.com:bijingto…
bijington Mar 4, 2025
e011603
Fixes for movement issues on Windows
bijington Mar 4, 2025
70cc808
Extra documentation
bijington Mar 4, 2025
d502c2f
Introduce a PowerShell script to manage packing and publishing of mul…
bijington Mar 5, 2025
d92adea
Release builds for pipeline
bijington Mar 5, 2025
367ecf2
Fix some os version warnings
bijington Mar 5, 2025
926f65d
Revert readme changes in favour of a separate readme for Orbit.Input
bijington Mar 5, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -216,13 +216,13 @@ dotnet_naming_rule.public_fields_should_be_pascalcase.severity = suggestion
dotnet_naming_rule.public_fields_should_be_pascalcase.symbols = public_fields
dotnet_naming_rule.public_fields_should_be_pascalcase.style = pascalcase

dotnet_naming_rule.private_fields_should_be__camelcase.severity = suggestion
dotnet_naming_rule.private_fields_should_be__camelcase.symbols = private_fields
dotnet_naming_rule.private_fields_should_be__camelcase.style = _camelcase
dotnet_naming_rule.private_fields_should_be_camelcase.severity = suggestion
dotnet_naming_rule.private_fields_should_be_camelcase.symbols = private_fields
dotnet_naming_rule.private_fields_should_be_camelcase.style = camelcase

dotnet_naming_rule.private_static_fields_should_be_s_camelcase.severity = suggestion
dotnet_naming_rule.private_static_fields_should_be_s_camelcase.symbols = private_static_fields
dotnet_naming_rule.private_static_fields_should_be_s_camelcase.style = s_camelcase
dotnet_naming_rule.private_static_fields_should_be_camelcase.severity = suggestion
dotnet_naming_rule.private_static_fields_should_be_camelcase.symbols = private_static_fields
dotnet_naming_rule.private_static_fields_should_be_camelcase.style = camelcase

dotnet_naming_rule.public_constant_fields_should_be_pascalcase.severity = suggestion
dotnet_naming_rule.public_constant_fields_should_be_pascalcase.symbols = public_constant_fields
Expand Down
14 changes: 9 additions & 5 deletions .github/workflows/dotnet-macos.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,20 @@ jobs:
- name: Setup .NET
uses: actions/setup-dotnet@v2
with:
dotnet-version: 8.0.x
dotnet-version: 9.0.x
- name: workload install
run: dotnet workload install maui
- name: Restore dependencies
- name: Restore dependencies - engine
run: dotnet restore engine/Orbit.Engine/Orbit.Engine.csproj
- name: Restore dependencies
- name: Restore dependencies - input
run: dotnet restore engine/Orbit.Input/Orbit.Input.csproj
- name: Restore dependencies - tests
run: dotnet restore engine/Orbit.Engine.Tests/Orbit.Engine.Tests.csproj
- name: Build engine
run: dotnet build engine/Orbit.Engine/Orbit.Engine.csproj --no-restore
run: dotnet build engine/Orbit.Engine/Orbit.Engine.csproj --no-restore -c Release
- name: Build input
run: dotnet build engine/Orbit.Input/Orbit.Input.csproj --no-restore -c Release
- name: Build tests
run: dotnet build engine/Orbit.Engine.Tests/Orbit.Engine.Tests.csproj --no-restore
run: dotnet build engine/Orbit.Engine.Tests/Orbit.Engine.Tests.csproj --no-restore -c Release
- name: Run tests
run: dotnet test engine/Orbit.Engine.Tests/Orbit.Engine.Tests.csproj --no-restore
14 changes: 9 additions & 5 deletions .github/workflows/dotnet-windows.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,20 @@ jobs:
- name: Setup .NET
uses: actions/setup-dotnet@v2
with:
dotnet-version: 8.0.x
dotnet-version: 9.0.x
- name: workload install
run: dotnet workload install maui
- name: Restore dependencies
- name: Restore dependencies - engine
run: dotnet restore engine/Orbit.Engine/Orbit.Engine.csproj
- name: Restore dependencies
- name: Restore dependencies - input
run: dotnet restore engine/Orbit.Input/Orbit.Input.csproj
- name: Restore dependencies - tests
run: dotnet restore engine/Orbit.Engine.Tests/Orbit.Engine.Tests.csproj
- name: Build engine
run: dotnet build engine/Orbit.Engine/Orbit.Engine.csproj --no-restore
run: dotnet build engine/Orbit.Engine/Orbit.Engine.csproj --no-restore -c Release
- name: Build input
run: dotnet build engine/Orbit.Input/Orbit.Input.csproj --no-restore -c Release
- name: Build tests
run: dotnet build engine/Orbit.Engine.Tests/Orbit.Engine.Tests.csproj --no-restore
run: dotnet build engine/Orbit.Engine.Tests/Orbit.Engine.Tests.csproj --no-restore -c Release
- name: Run tests
run: dotnet test engine/Orbit.Engine.Tests/Orbit.Engine.Tests.csproj --no-restore
24 changes: 8 additions & 16 deletions .github/workflows/nuget-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ on:
tags:
- "v[0-9]+.[0-9]+.[0-9]+"
- "v[0-9]+.[0-9]+.[0-9]+-preview[0-9]+"
- "engine[0-9]+.[0-9]+.[0-9]+"
- "engine[0-9]+.[0-9]+.[0-9]+-preview[0-9]+"
- "input[0-9]+.[0-9]+.[0-9]+"
- "input[0-9]+.[0-9]+.[0-9]+-preview[0-9]+"
jobs:
release-nuget:

Expand All @@ -21,21 +25,9 @@ jobs:
id: get_version
uses: battila7/get-version-action@v2

- name: Restore dependencies
run: dotnet restore engine/Orbit.Engine/Orbit.Engine.csproj

- name: Build
run: dotnet build --configuration Release --no-restore engine/Orbit.Engine/Orbit.Engine.csproj /p:Version=${{ steps.get_version.outputs.version-without-v }}

- name: Pack
run: dotnet pack engine/Orbit.Engine/Orbit.Engine.csproj -c Release /p:Version=${{ steps.get_version.outputs.version-without-v }} --no-build --output .

- name: Push
run: dotnet nuget push Bijington.Orbit.Engine.${{ steps.get_version.outputs.version-without-v }}.nupkg -s https://api.nuget.org/v3/index.json -k ${{ secrets.NUGET_API_KEY }}
env:
GITHUB_TOKEN: ${{ secrets.NUGET_API_KEY }}

- name: Push symbols
run: dotnet nuget push Bijington.Orbit.Engine.${{ steps.get_version.outputs.version-without-v }}.snupkg -s https://api.nuget.org/v3/index.json -k ${{ secrets.NUGET_API_KEY }}
- name: Package releases
shell: pwsh
run: |
.\scripts\package-releases.ps1 -Version ${{ steps.get_version.outputs.version-without-v }} -ApiKey ${{ secrets.NUGET_API_KEY }}
env:
GITHUB_TOKEN: ${{ secrets.NUGET_API_KEY }}
2 changes: 1 addition & 1 deletion engine/Orbit.Engine.Tests/Orbit.Engine.Tests.csproj
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<TargetFramework>net9.0</TargetFramework>
<Nullable>enable</Nullable>
<UseMaui>true</UseMaui>

Expand Down
2 changes: 1 addition & 1 deletion engine/Orbit.Engine/GameSceneManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ private void UpdateScene()
var postUpdate = DateTime.UtcNow;
var updateDuration = callbackMilliseconds - (postUpdate - currentUpdate).TotalMilliseconds;

var delayUntilNextUpdate = Math.Min(updateDuration, callbackMilliseconds);
var delayUntilNextUpdate = Math.Clamp(updateDuration, 0, callbackMilliseconds);

dispatcher.DispatchDelayed(
TimeSpan.FromMilliseconds(delayUntilNextUpdate),
Expand Down
14 changes: 7 additions & 7 deletions engine/Orbit.Engine/Orbit.Engine.csproj
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>net8.0;net8.0-android;net8.0-ios;net8.0-maccatalyst</TargetFrameworks>
<TargetFrameworks Condition="$([MSBuild]::IsOSPlatform('windows'))">$(TargetFrameworks);net8.0-windows10.0.19041.0</TargetFrameworks>
<TargetFrameworks>net9.0;net9.0-android;net9.0-ios;net9.0-maccatalyst</TargetFrameworks>
<TargetFrameworks Condition="$([MSBuild]::IsOSPlatform('windows'))">$(TargetFrameworks);net9.0-windows10.0.19041.0</TargetFrameworks>
<!-- Uncomment to also build the tizen app. You will need to install tizen by following this: https://github.com/Samsung/Tizen.NET -->
<!-- <TargetFrameworks>$(TargetFrameworks);net8.0-tizen</TargetFrameworks> -->
<!-- <TargetFrameworks>$(TargetFrameworks);net9.0-tizen</TargetFrameworks> -->
<UseMaui>true</UseMaui>
<SingleProject>true</SingleProject>
<ImplicitUsings>enable</ImplicitUsings>

<GenerateDocumentationFile>True</GenerateDocumentationFile>

<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'ios'">14.2</SupportedOSPlatformVersion>
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'maccatalyst'">14.0</SupportedOSPlatformVersion>
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'ios'">15.0</SupportedOSPlatformVersion>
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'maccatalyst'">15.0</SupportedOSPlatformVersion>
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'android'">21.0</SupportedOSPlatformVersion>
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'windows'">10.0.19041.0</SupportedOSPlatformVersion>
<TargetPlatformMinVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'windows'">10.0.19041.0</TargetPlatformMinVersion>
Expand Down Expand Up @@ -58,10 +58,10 @@
<None Include="..\..\readme.md" Pack="true" PackagePath="\"/>
</ItemGroup>

<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Debug|net8.0-ios|AnyCPU'">
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Debug|net9.0-ios|AnyCPU'">
<CreatePackage>false</CreatePackage>
</PropertyGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net8.0-windows10.0.19041.0'">
<ItemGroup Condition="'$(TargetFramework)' == 'net9.0-windows10.0.19041.0'">
<PackageReference Include="Microsoft.Maui.Graphics.Win2D.WinUI.Desktop" Version="$(MauiVersion)">
</PackageReference>
</ItemGroup>
Expand Down
76 changes: 76 additions & 0 deletions engine/Orbit.Input/GameControllers/ButtonValue.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
namespace Orbit.Input;

/// <summary>
/// Represents a game controller button and its associated value.
/// </summary>
public abstract class ButtonValue
{
/// <summary>
/// Creates a new instance of <see cref="ButtonValue"/>.
/// </summary>
/// <param name="parent">The name of the component of a game controller that this button belongs to.</param>
/// <param name="name">The name of the button.</param>
protected ButtonValue(string parent, string name)
{
Name = NameHelper.GetName(parent, name);
}

/// <summary>
/// Gets the name of the button.
/// </summary>
public string Name { get; }
}

/// <inheritdoc />
public class ButtonValue<TValue> : ButtonValue where TValue : struct
{
private readonly GameController gameController;
private readonly IComparer<TValue> comparer;
private TValue buttonValue;

/// <summary>
/// Creates a new instance of <see cref="ButtonValue"/>.
/// </summary>
/// <param name="gameController">The <see cref="GameController"/> that this button belongs to.</param>
/// <param name="parent">The name of the component of a game controller that this button belongs to.</param>
/// <param name="name">The name of the button.</param>
/// <param name="comparer">The <see cref="IComparer{T}"/> to use in comparisons for value changed events. Particularly useful when dealing with values like <see cref="float"/> where accuracy can be messy.</param>
public ButtonValue(GameController gameController, string parent, string name, IComparer<TValue>? comparer = null)
: base(parent, name)
{
this.gameController = gameController;
this.comparer = comparer ?? Comparer<TValue>.Default;
}

/// <summary>
/// Creates a new instance of <see cref="ButtonValue"/>.
/// </summary>
/// <param name="gameController">The <see cref="GameController"/> that this button belongs to.</param>
/// <param name="name">The name of the button.</param>
/// <param name="comparer">The <see cref="IComparer{T}"/> to use in comparisons for value changed events. Particularly useful when dealing with values like <see cref="float"/> where accuracy can be messy.</param>
public ButtonValue(GameController gameController, string name, IComparer<TValue>? comparer = null)
: base(string.Empty, name)
{
this.gameController = gameController;
this.comparer = comparer ?? Comparer<TValue>.Default;
}

/// <summary>
/// Gets the current value for the button.
/// </summary>
public TValue Value
{
get => buttonValue;
internal set
{
if (comparer.Compare(buttonValue, value) == 0)
{
return;
}

buttonValue = value;

this.gameController.RaiseButtonValueChanged(this);
}
}
}
31 changes: 31 additions & 0 deletions engine/Orbit.Input/GameControllers/FloatComparer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
namespace Orbit.Input;

/// <summary>
/// A <see cref="float"/> based implementation of <see cref="IComparer{T}"/>.
/// </summary>
public class FloatComparer : IComparer<float>
{
private readonly float threshold;

internal static FloatComparer Default { get; set; } = new FloatComparer(0.001f);

/// <summary>
/// Creates a new instance of <see cref="FloatComparer"/>.
/// </summary>
/// <param name="threshold">The threshold to use when determining whether values are equal.</param>
public FloatComparer(float threshold)
{
this.threshold = threshold;
}

/// <inheritdoc cref="IComparer{T}.Compare"/>
public int Compare(float x, float y)
{
if (Math.Abs(x - y) < this.threshold)
{
return 0;
}

return x < y ? 1 : -1;
}
}
95 changes: 95 additions & 0 deletions engine/Orbit.Input/GameControllers/GameController.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
namespace Orbit.Input;

/// <summary>
/// Represents a physical game controller that is connected to a device.
/// </summary>
public partial class GameController
{
private readonly WeakEventManager weakEventManager = new();

/// <summary>
/// Gets the <see cref="Stick"/> that represents the D-pad on the game controller.
/// </summary>
public Stick Dpad { get; }

/// <summary>
/// Gets the <see cref="Stick"/> that represents the left thumbstick on the game controller.
/// </summary>
public Stick LeftStick { get; }

/// <summary>
/// Gets the <see cref="Stick"/> that represents the right thumbstick on the game controller.
/// </summary>
public Stick RightStick { get; }

/// <summary>
/// Gets the <see cref="ButtonValue{T}"/> that represents the right most button on the controller.
/// Circle on Playstation and B on XBox controllers.
/// </summary>
public ButtonValue<bool> East { get; }

/// <summary>
/// Gets the <see cref="ButtonValue{T}"/> that represents the top most button on the controller.
/// Triangle on Playstation and Y on XBox controllers.
/// </summary>
public ButtonValue<bool> North { get; }

/// <summary>
/// Gets the <see cref="ButtonValue{T}"/> that represents the bottom most button on the controller.
/// X on Playstation and A on XBox controllers.
/// </summary>
public ButtonValue<bool> South { get; }

/// <summary>
/// Gets the <see cref="ButtonValue{T}"/> that represents the left most button on the controller.
/// Square on Playstation and X on XBox controllers.
/// </summary>
public ButtonValue<bool> West { get; }

/// <summary>
/// Gets the <see cref="ButtonValue{T}"/> that represents the left most button on the controller.
/// Options on Playstation and hamburger on XBox controllers.
/// </summary>
public ButtonValue<bool> Pause { get; }

/// <summary>
/// Gets the <see cref="Shoulder"/> that represents the left hand shoulder on the controller.
/// </summary>
public Shoulder LeftShoulder { get; }

/// <summary>
/// Gets the <see cref="Shoulder"/> that represents the right hand shoulder on the controller.
/// </summary>
public Shoulder RightShoulder { get; }

/// <summary>
/// Event that is raised when a button on the game controller is detected as being pressed or released.
/// </summary>
public event EventHandler<GameControllerButtonChangedEventArgs> ButtonChanged
{
add => weakEventManager.AddEventHandler(value);
remove => weakEventManager.RemoveEventHandler(value);
}

/// <summary>
/// Event that is raised when a button that supports a varying value on the game controller is detected as being pressed or released to some degree.
/// </summary>
public event EventHandler<GameControllerValueChangedEventArgs> ValueChanged
{
add => weakEventManager.AddEventHandler(value);
remove => weakEventManager.RemoveEventHandler(value);
}

internal void RaiseButtonValueChanged(ButtonValue buttonValue)
{
switch (buttonValue)
{
case ButtonValue<float> floatValue:
weakEventManager.HandleEvent(this, new GameControllerValueChangedEventArgs(buttonValue.Name, floatValue.Value), nameof(ValueChanged));
break;
case ButtonValue<bool> boolValue:
weakEventManager.HandleEvent(this, new GameControllerButtonChangedEventArgs(buttonValue.Name, boolValue.Value), nameof(ButtonChanged));
break;
}
}
}
Loading
Loading