feat: added android platform template

This commit is contained in:
Syntriax 2025-08-09 21:50:42 +03:00
parent 6bee6f44c4
commit 80d29a71ed
9 changed files with 258 additions and 1 deletions

2
Engine

@ -1 +1 @@
Subproject commit efed24de2011eb9aad6fbeac38697eb9a7c37e3f Subproject commit a4b83679b1c45313b57a7a2581547aacf9f3064f

View File

@ -0,0 +1,36 @@
{
"version": 1,
"isRoot": true,
"tools": {
"dotnet-mgcb": {
"version": "3.8.1.303",
"commands": [
"mgcb"
]
},
"dotnet-mgcb-editor": {
"version": "3.8.1.303",
"commands": [
"mgcb-editor"
]
},
"dotnet-mgcb-editor-linux": {
"version": "3.8.1.303",
"commands": [
"mgcb-editor-linux"
]
},
"dotnet-mgcb-editor-windows": {
"version": "3.8.1.303",
"commands": [
"mgcb-editor-windows"
]
},
"dotnet-mgcb-editor-mac": {
"version": "3.8.1.303",
"commands": [
"mgcb-editor-mac"
]
}
}
}

View File

@ -0,0 +1,42 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net9.0-android</TargetFramework>
<SupportedOSPlatformVersion>23</SupportedOSPlatformVersion>
<OutputType>Exe</OutputType>
<ApplicationId>com.MyCompany.MyGame</ApplicationId>
<ApplicationVersion>1</ApplicationVersion>
<ApplicationDisplayVersion>1.0</ApplicationDisplayVersion>
<EmbedAssembliesIntoApk>true</EmbedAssembliesIntoApk>
<AndroidUseSharedRuntime>true</AndroidUseSharedRuntime>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="MonoGame.Content.Builder.Task" Version="3.8.1.303" />
<PackageReference Include="MonoGame.Framework.Android" Version="3.8.1.303" />
</ItemGroup>
<ItemGroup>
<MonoGameContentReference Include="../../Shared/Content/Content.mgcb">
<Link>Content/Content.mgcb</Link>
</MonoGameContentReference>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="../../Shared/Shared.csproj" />
</ItemGroup>
<Target Name="RestoreDotnetTools" BeforeTargets="Restore">
<Message Text="Restoring dotnet tools" Importance="High" />
<Exec Command="dotnet tool restore" />
</Target>
<!-- TODO: Currently I have no idea how to set this up properly and am in a hurry so... Find a better solution for the bellow -->
<!-- Windows-specific settings -->
<!-- <PropertyGroup Condition="'$([System.Runtime.InteropServices.RuntimeInformation]::IsOSPlatform($([System.Runtime.InteropServices.OSPlatform]::Windows)))' == 'true'">
<JavaSdkDirectory>C:/Program Files/Java/jdk-17.0.5</JavaSdkDirectory>
<AndroidSdkDirectory>C:/android-sdk</AndroidSdkDirectory>
</PropertyGroup> -->
</Project>

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
package="com.MyCompany.MyGame"
android:versionCode="1"
android:versionName="1.0">
<uses-sdk android:minSdkVersion="23" android:targetSdkVersion="36" />
<uses-feature android:glEsVersion="0x00020000" android:required="true" />
<application android:label="MyGame" />
</manifest>

View File

@ -0,0 +1,90 @@
using System.Collections.Generic;
using Microsoft.Xna.Framework.Input.Touch;
using Engine.Core;
using Engine.Systems.Input;
using MyUniverse.Shared.Behaviours.Abstract;
namespace MyUniverse.Platforms.Android;
public class MobileInputs : Behaviour, IUpdate, IGameInputs
{
public Event<IButtonInputs<IGameInputs.Button>, IButtonInputs<IGameInputs.Button>.ButtonCallbackArguments> OnAnyButtonPressed { get; } = new();
public Event<IButtonInputs<IGameInputs.Button>, IButtonInputs<IGameInputs.Button>.ButtonCallbackArguments> OnAnyButtonReleased { get; } = new();
private readonly Dictionary<IGameInputs.Button, Event<IButtonInputs<IGameInputs.Button>, IButtonInputs<IGameInputs.Button>.ButtonCallbackArguments>> OnPressed = new(256);
private readonly Dictionary<IGameInputs.Button, Event<IButtonInputs<IGameInputs.Button>, IButtonInputs<IGameInputs.Button>.ButtonCallbackArguments>> OnReleased = new(256);
private TouchCollection touchCollection = default;
public void RegisterOnPress(IGameInputs.Button key, Event<IButtonInputs<IGameInputs.Button>, IButtonInputs<IGameInputs.Button>.ButtonCallbackArguments>.EventHandler callback)
{
if (OnPressed.TryGetValue(key, out Event<IButtonInputs<IGameInputs.Button>, IButtonInputs<IGameInputs.Button>.ButtonCallbackArguments> @event))
{
@event.AddListener(callback);
return;
}
@event = new();
@event.AddListener(callback);
OnPressed.Add(key, @event);
}
public void UnregisterOnPress(IGameInputs.Button key, Event<IButtonInputs<IGameInputs.Button>, IButtonInputs<IGameInputs.Button>.ButtonCallbackArguments>.EventHandler callback)
{
if (OnPressed.TryGetValue(key, out Event<IButtonInputs<IGameInputs.Button>, IButtonInputs<IGameInputs.Button>.ButtonCallbackArguments> @event))
@event.RemoveListener(callback);
}
public void RegisterOnRelease(IGameInputs.Button key, Event<IButtonInputs<IGameInputs.Button>, IButtonInputs<IGameInputs.Button>.ButtonCallbackArguments>.EventHandler callback)
{
if (OnReleased.TryGetValue(key, out Event<IButtonInputs<IGameInputs.Button>, IButtonInputs<IGameInputs.Button>.ButtonCallbackArguments> @event))
{
@event.AddListener(callback);
return;
}
@event = new();
@event.AddListener(callback);
OnReleased.Add(key, @event);
}
public void UnregisterOnRelease(IGameInputs.Button key, Event<IButtonInputs<IGameInputs.Button>, IButtonInputs<IGameInputs.Button>.ButtonCallbackArguments>.EventHandler callback)
{
if (OnReleased.TryGetValue(key, out Event<IButtonInputs<IGameInputs.Button>, IButtonInputs<IGameInputs.Button>.ButtonCallbackArguments> @event))
@event.RemoveListener(callback);
}
public void Update()
{
touchCollection = TouchPanel.GetState();
if (touchCollection.Count > 0)
{
TouchLocation touchLocation = touchCollection[(int)IGameInputs.Button.Interact];
if (touchLocation.State == TouchLocationState.Pressed)
{
if (OnPressed.TryGetValue(IGameInputs.Button.Interact, out Event<IButtonInputs<IGameInputs.Button>, IButtonInputs<IGameInputs.Button>.ButtonCallbackArguments> @event))
@event.Invoke(this, new(IGameInputs.Button.Interact));
OnAnyButtonPressed?.Invoke(this, new(IGameInputs.Button.Interact));
}
else if (touchLocation.State == TouchLocationState.Released)
{
if (OnReleased.TryGetValue(IGameInputs.Button.Interact, out Event<IButtonInputs<IGameInputs.Button>, IButtonInputs<IGameInputs.Button>.ButtonCallbackArguments> @event))
@event.Invoke(this, new(IGameInputs.Button.Interact));
OnAnyButtonReleased?.Invoke(this, new(IGameInputs.Button.Interact));
}
}
}
public bool IsPressed(IGameInputs.Button button)
{
if (touchCollection.Count > 0)
return false;
TouchLocation touchLocation = touchCollection[(int)IGameInputs.Button.Interact];
return touchLocation.State == TouchLocationState.Pressed || touchLocation.State == TouchLocationState.Moved;
}
}

View File

@ -0,0 +1,60 @@
using Microsoft.Xna.Framework;
using Android.App;
using Android.Content.PM;
using Android.OS;
using Android.Views;
using Engine.Integration.MonoGame;
using Engine.Core;
using Engine.Core.Debug;
namespace MyUniverse.Platforms.Android
{
[Activity(
Label = "@string/app_name",
MainLauncher = true,
Icon = "@drawable/icon",
AlwaysRetainTaskState = true,
LaunchMode = LaunchMode.SingleInstance,
ScreenOrientation = ScreenOrientation.Portrait,
ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.Keyboard | ConfigChanges.KeyboardHidden | ConfigChanges.ScreenSize
)]
public class Program : AndroidGameActivity
{
private MonoGameWindow _game;
private View _view;
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
Universe universe = new();
ILogger logger = new RotatingFileLogger("Logs", "MyGame");
universe.InstantiateUniverseObject().SetUniverseObject("Logger")
.BehaviourController.AddBehaviour<LoggerContainer>().Logger = ILogger.Shared = logger;
universe.InstantiateUniverseObject().SetUniverseObject("Desktop Inputs")
.BehaviourController.AddBehaviour<MobileInputs>();
universe.InstantiateUniverseObject().SetUniverseObject("Visual Managers")
.BehaviourController.AddBehaviour<DrawManager>()
.BehaviourController.AddBehaviour<LoadContentManager>();
/* For Networking
LiteNetLibClient client = universe.InstantiateUniverseObject().SetUniverseObject("Client").BehaviourController.AddBehaviour<LiteNetLibClient>();
client.BehaviourController.AddBehaviour<NetworkManager>();
universe.OnPreUpdate.AddOneTimeListener((_, _) => client.Connect("localhost", 8888));
*/
Shared.UniverseSource.ApplyUniverse(universe);
_game = new MonoGameWindow(universe);
_view = _game.Services.GetService(typeof(View)) as View;
SetContentView(_view);
_game.Run();
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.8 KiB

View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">MyGame</string>
</resources>

View File

@ -29,6 +29,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Engine.Integration.Yaml", "
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Engine.Integration.LiteNetLib", "Engine\Engine.Integration\Engine.Integration.LiteNetLib\Engine.Integration.LiteNetLib.csproj", "{7AA22306-772F-45F4-8F30-97EBD1FC124D}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Engine.Integration.LiteNetLib", "Engine\Engine.Integration\Engine.Integration.LiteNetLib\Engine.Integration.LiteNetLib.csproj", "{7AA22306-772F-45F4-8F30-97EBD1FC124D}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Android", "Platforms\Android\Android.csproj", "{6D4F3E3C-4E89-44A1-B6D3-03627AA8A8AF}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU Debug|Any CPU = Debug|Any CPU
@ -159,6 +161,18 @@ Global
{7AA22306-772F-45F4-8F30-97EBD1FC124D}.Release|x64.Build.0 = Release|Any CPU {7AA22306-772F-45F4-8F30-97EBD1FC124D}.Release|x64.Build.0 = Release|Any CPU
{7AA22306-772F-45F4-8F30-97EBD1FC124D}.Release|x86.ActiveCfg = Release|Any CPU {7AA22306-772F-45F4-8F30-97EBD1FC124D}.Release|x86.ActiveCfg = Release|Any CPU
{7AA22306-772F-45F4-8F30-97EBD1FC124D}.Release|x86.Build.0 = Release|Any CPU {7AA22306-772F-45F4-8F30-97EBD1FC124D}.Release|x86.Build.0 = Release|Any CPU
{6D4F3E3C-4E89-44A1-B6D3-03627AA8A8AF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6D4F3E3C-4E89-44A1-B6D3-03627AA8A8AF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6D4F3E3C-4E89-44A1-B6D3-03627AA8A8AF}.Debug|x64.ActiveCfg = Debug|Any CPU
{6D4F3E3C-4E89-44A1-B6D3-03627AA8A8AF}.Debug|x64.Build.0 = Debug|Any CPU
{6D4F3E3C-4E89-44A1-B6D3-03627AA8A8AF}.Debug|x86.ActiveCfg = Debug|Any CPU
{6D4F3E3C-4E89-44A1-B6D3-03627AA8A8AF}.Debug|x86.Build.0 = Debug|Any CPU
{6D4F3E3C-4E89-44A1-B6D3-03627AA8A8AF}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6D4F3E3C-4E89-44A1-B6D3-03627AA8A8AF}.Release|Any CPU.Build.0 = Release|Any CPU
{6D4F3E3C-4E89-44A1-B6D3-03627AA8A8AF}.Release|x64.ActiveCfg = Release|Any CPU
{6D4F3E3C-4E89-44A1-B6D3-03627AA8A8AF}.Release|x64.Build.0 = Release|Any CPU
{6D4F3E3C-4E89-44A1-B6D3-03627AA8A8AF}.Release|x86.ActiveCfg = Release|Any CPU
{6D4F3E3C-4E89-44A1-B6D3-03627AA8A8AF}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE
@ -173,5 +187,6 @@ Global
{7CC31BC4-38EE-40F4-BBBA-9FC2F4CF6283} = {9059393F-4073-9273-0EEC-2B1BA61B620B} {7CC31BC4-38EE-40F4-BBBA-9FC2F4CF6283} = {9059393F-4073-9273-0EEC-2B1BA61B620B}
{A15263DB-DF65-4A07-8CA1-33A2919501A0} = {FECFFD54-338F-4060-9161-1E5770D1DC33} {A15263DB-DF65-4A07-8CA1-33A2919501A0} = {FECFFD54-338F-4060-9161-1E5770D1DC33}
{7AA22306-772F-45F4-8F30-97EBD1FC124D} = {9059393F-4073-9273-0EEC-2B1BA61B620B} {7AA22306-772F-45F4-8F30-97EBD1FC124D} = {9059393F-4073-9273-0EEC-2B1BA61B620B}
{6D4F3E3C-4E89-44A1-B6D3-03627AA8A8AF} = {FECFFD54-338F-4060-9161-1E5770D1DC33}
EndGlobalSection EndGlobalSection
EndGlobal EndGlobal