-
Notifications
You must be signed in to change notification settings - Fork 63
Feature/mobile deployment #169
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
5945f88
b422687
cdaa253
9a22ba8
f20f79d
f66fa9d
ba1387c
cb5c95a
60acf90
3173777
dec9803
68091a4
ed11443
85bf058
cfab710
ac7cc3b
c0479e3
f797549
cb42e6e
295fae7
90b9914
2676f5c
f52ec09
b1af154
a5906bb
0e62b4a
69be315
2b159a3
2fbf92d
7f134a6
e9e2421
3f8f99a
5af3400
b484644
2dd9925
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,73 @@ | ||
| --- | ||
| title: "Chapter 01: Setting Up MonoGame for Android and iOS Development" | ||
| description: "Get started with MonoGame mobile development by setting up your development environment, tools, and SDKs for Android and iOS platforms." | ||
| --- | ||
|
|
||
| # Getting Started and Overview | ||
|
|
||
| This tutorial extends the [Dungeon Slime](https://github.com/MonoGame/MonoGame.Samples/tree/3.8.4/Tutorials/learn-monogame-2d) tutorial to mobile platforms. If you have not completed the desktop tutorial yet, we recommend finishing it first as we will be building directly on that foundation. | ||
|
|
||
| ## What You Will Learn | ||
|
|
||
| By the end of this mobile tutorial series, you will have: | ||
| - Ported the **Dungeon Slime** game to run on Android and iOS | ||
| - Implemented touch controls to replace mouse and keyboard input | ||
| - Set up cross-platform project architecture for code sharing | ||
| - Learned debugging techniques for mobile development | ||
| - Published your game to both Google Play and the App Store | ||
| - Created automated deployment workflows | ||
|
|
||
| # Development Requirements | ||
|
|
||
| ## Android Development | ||
|
|
||
| **Platform Support:** Android development can be accomplished on either Windows PC or Mac. | ||
|
|
||
| > [!NOTE] | ||
| > ARM64 variants of Windows do not run the Android simulator very well. | ||
| > | ||
|
|
||
| **Required Tools:** | ||
| - **Android Device Manager** - Used to set up simulators (accessible through Visual Studio) | ||
| - **Android SDK Manager** - Used to install the SDK platforms | ||
olivegamestudio marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| These tools are available by installing the Android Workload using the [MonoGame Getting Started Instructions](../../../../getting_started/platforms.md). | ||
|
|
||
| **Additional Notes:** For Windows users, ensure **Hyper-V** is enabled for better emulator performance. On Mac, Android Studio can be used alongside Rider for advanced emulator configurations. | ||
|
|
||
| For more information visit about getting started with Android development: | ||
|
|
||
| - [Getting Started with Android Development](https://learn.microsoft.com/en-us/dotnet/android/getting-started/installation/) | ||
| - [Getting Started with Maui Development](https://learn.microsoft.com/en-us/dotnet/maui/get-started/installation) | ||
|
|
||
| To release your game to the **Google Play Store**, you will need to sign up for a developer account at [Google Play Signup](https://play.google.com/console/signup). You will need to accept the Developer Distribution Agreement and pay a registration fee. | ||
|
|
||
| More information about the registration process can be found here [Registration process](https://support.google.com/googleplay/android-developer/answer/6112435). | ||
|
|
||
| ## iOS Development | ||
|
|
||
| **Platform Requirement:** For iOS development you will <ins>require</ins> a Mac, whether you develop entirely on one or use the **Pair to Mac** option with Windows Visual Studio. | ||
|
|
||
| Since **Visual Studio for Mac** has been deprecated, [JetBrains Rider](https://www.jetbrains.com/rider/) or [VS Code](https://code.visualstudio.com/) can be used to develop for iOS. There is a non-commercial licence available of Rider. | ||
|
|
||
| For information about Pairing between Visual Studio and Mac, learn more [here](https://learn.microsoft.com/en-us/dotnet/maui/ios/pair-to-mac). | ||
|
|
||
| **Additional Requirements:** | ||
| - **Xcode** - Required for iOS development and deployment | ||
| - **Apple Developer Account** - Required for physical device deployment and App Store publishing ([enrollment link](https://developer.apple.com/programs/enroll/)) | ||
|
|
||
| # Modern .NET Project Features | ||
|
|
||
| This tutorial utilizes modern .NET project management features to streamline cross-platform development: | ||
|
|
||
| ## Central Package Management | ||
|
|
||
| We will be using [Central Package Management](https://learn.microsoft.com/en-us/nuget/consume-packages/central-package-management) to maintain consistent package versions across all platform projects. This ensures your shared code library and platform-specific projects use identical dependency versions. | ||
|
|
||
| ## SLNX Solution Format | ||
|
|
||
| The sample projects use the new [SLNX solution format](https://devblogs.microsoft.com/dotnet/introducing-slnx-support-dotnet-cli/) for improved cross-platform development experience and better integration with modern .NET tooling. | ||
|
|
||
| # Next Steps | ||
|
|
||
| In the next chapter, we will convert the existing Windows-only Dungeon Slime game project to support iOS and Android platforms. | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,101 @@ | ||
| --- | ||
| title: "Chapter 02: Setting Up Cross-Platform Projects" | ||
| description: "Learn how to convert a Windows-only MonoGame project to support iOS and Android platforms, creating a unified codebase for multi-platform deployment." | ||
| --- | ||
|
|
||
| # What You Will Learn | ||
|
|
||
| In this chapter you will: | ||
| - Convert a Windows-only MonoGame project to support multiple platforms | ||
| - Understand the project structure for multi-platform games | ||
| - Set up shared code architecture for cross-platform development | ||
|
|
||
| # Prerequisites | ||
|
|
||
| - **For iOS Development:** | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This section is duplicating the previous chapter, please consolidate in chapter 1. Even in tutorials, you should follow the DRY pattern, unless essential. |
||
| - An App Store Developer Account | ||
| - **Certificates** and **Provisioning Profiles** configured and installed. | ||
| - **Mac 15.x (Sequoia) with Xcode 16 installed** - installed through the App Store. | ||
| - **For Android Development:** | ||
| - Android SDK and tools installed - through the Visual Studio Installer or through Jetbrains Rider. | ||
|
|
||
| # Converting the Dungeon Slime Project | ||
|
|
||
| The Dungeon Slime game from the 2D tutorial serves as our practical example for cross-platform conversion. This approach can be applied to any MonoGame project you want to deploy across multiple platforms. | ||
|
|
||
| The key principle is **code sharing** of the game logic between all platform variants - we will extract the game logic into a common library that all platform-specific projects can refer to and use. | ||
|
|
||
| # Cross-Platform Project Structure | ||
|
|
||
| When converted to support multiple platforms, your solution structure will look like this, as shown in the following figure. | ||
|
|
||
| |  | | ||
| | :----------------------------------------------------------------------------------------------------------------------------------------: | | ||
| | **Figure 2-1: Cross Platform Projects** | | ||
|
|
||
| This architecture separates concerns cleanly: | ||
| - **Shared game logic** in a common library | ||
| - **Platform-specific shells** that handle deployment and platform requirements | ||
| - **Consistent naming** for easy project management | ||
|
|
||
| ## DungeonSlime.Common - The Shared Library | ||
|
|
||
| The common project contains all your game logic and uses multi-targeting to support different platforms: | ||
|
|
||
| ```xml | ||
| <TargetFrameworks>net8.0;net8.0-ios;net8.0-android</TargetFrameworks> | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The shared library should only need "net8" as it is common. Only the runtime platforms will require the specific extensions |
||
| ``` | ||
|
|
||
| ## Platform-Specific Package References | ||
|
|
||
| Each target framework pulls in the appropriate MonoGame package: | ||
|
|
||
| For **iOS**: | ||
| ```xml | ||
| <ItemGroup Condition="'$(TargetFramework)'=='net8.0-ios'"> | ||
| <PackageReference Include="MonoGame.Framework.iOS" Version="3.8.5-develop.6" /> | ||
| </ItemGroup> | ||
| ``` | ||
|
|
||
| For **Android**: | ||
|
|
||
| ```xml | ||
| <ItemGroup Condition="'$(TargetFramework)'=='net8.0-android'"> | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These should be using |
||
| <PackageReference Include="MonoGame.Framework.Android" Version="3.8.5-develop.6" /> | ||
| </ItemGroup> | ||
| ``` | ||
|
|
||
| For **Windows**: | ||
|
|
||
| ```xml | ||
| <ItemGroup Condition="'$(TargetFramework)'=='net8.0'"> | ||
| <PackageReference Include="MonoGame.Framework.DesktopGL" Version="3.8.5-develop.6" /> | ||
| </ItemGroup> | ||
| ``` | ||
|
|
||
| ## Platform-Specific Projects | ||
|
|
||
| The individual platform projects become lightweight shells that: | ||
|
|
||
| - Reference the _common_ library | ||
| - Handle platform-specific initialization | ||
| - Manage deployment settings and assets | ||
| - Contain minimal platform-specific code | ||
|
|
||
| ## Project Structure | ||
|
|
||
| - **DungeonSlime.Windows** - Windows desktop version | ||
| - **DungeonSlime.Android** - Android mobile version | ||
| - **DungeonSlime.iOS** - iOS mobile version | ||
|
|
||
| The platform projects no longer contain the main Game class - this has been moved to the common library for sharing. | ||
|
|
||
| ## Third-Party Library Considerations | ||
|
|
||
| When using external libraries like **Gum**, ensure they support cross-platform development: | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How would the user check, assume they do not know anything or even how to check. Please provide guidance. Especially as in this case, the existing tutorial already includes GUM. |
||
|
|
||
| [https://github.com/vchelaru/Gum](https://github.com/vchelaru/Gum) | ||
|
|
||
| ```xml | ||
| <PackageReference Include="Gum.MonoGame" Version="2025.6.26.1" /> | ||
| ``` | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,207 @@ | ||
| --- | ||
| title: "Chapter 03: Touch Gesture Handling" | ||
| description: "Learn the fundamentals of touch gesture recognition in MonoGame - registration, detection, and processing." | ||
| --- | ||
|
|
||
| Before proceeding with the cross-platform conversion, let us review how to handle touch input in MonoGame. The concepts discussed here apply to any MonoGame project. For our Dungeon Slime demo, touch input is managed by the Gum library, but understanding the fundamentals is still important. | ||
|
|
||
| ## Gesture Registration | ||
|
|
||
| Before your application can respond to touch input, you must explicitly register for the gesture types you want to detect. | ||
|
|
||
| This is done during initialization: | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Initialization in which class / file, please be SPECIFIC when referring to files and locations. |
||
|
|
||
| ```csharp | ||
| protected override void Initialize() | ||
| { | ||
| TouchPanel.DisplayWidth = GraphicsDevice.PresentationParameters.BackBufferWidth; | ||
|
|
||
| TouchPanel.DisplayHeight = GraphicsDevice.PresentationParameters.BackBufferHeight; | ||
|
|
||
| TouchPanel.EnabledGestures = GestureType.Tap | | ||
| GestureType.DoubleTap | | ||
| GestureType.Hold | | ||
| GestureType.Flick | | ||
| GestureType.FreeDrag | | ||
| GestureType.HorizontalDrag | | ||
| GestureType.VerticalDrag | | ||
| GestureType.Pinch | | ||
| GestureType.DragComplete | | ||
| GestureType.PinchComplete; | ||
|
|
||
| base.Initialize(); | ||
| } | ||
| ``` | ||
|
|
||
| ### Available Gesture Types | ||
|
|
||
| | Gesture Type | Description | Common Use Cases | | ||
| |--------------|-------------|------------------| | ||
| | `Tap` | Quick touch and release | Button presses, object selection | | ||
| | `DoubleTap` | Two quick taps in succession | Zoom to fit, special actions | | ||
| | `Hold` | Touch and hold for extended time | Context menus, charged actions | | ||
| | `Flick` | Quick swipe motion | Throwing objects, page navigation | | ||
| | `FreeDrag` | Continuous dragging motion | Moving objects, drawing | | ||
| | `HorizontalDrag` | Dragging constrained to horizontal | Sliders, horizontal scrolling | | ||
| | `VerticalDrag` | Dragging constrained to vertical | Vertical scrolling, pull-to-refresh | | ||
| | `Pinch` | Two-finger pinch/spread motion | Zoom in/out, scaling | | ||
| | `DragComplete` | End of any drag operation | Finalize object placement | | ||
| | `PinchComplete` | End of pinch operation | Finalize zoom level | | ||
|
|
||
| > [!NOTE] | ||
| > Only register for gestures you actually need. Each enabled gesture type has a small performance cost. | ||
|
|
||
| ## Gesture Detection Loop | ||
|
|
||
| Touch gestures are processed using a polling approach in your `Update` method. Use `TouchPanel.IsGestureAvailable` to check if gestures are waiting to be processed: | ||
|
|
||
| ```csharp | ||
| protected override void Update(GameTime gameTime) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. DungeonSlime currently uses a dedicated input manager and separate "modules" for different inputs. So is this creating a new input module for use by the input manager, or where is it meant to go. If this is all theory at this point, make sure to start this section with a highlighted note informing the reader "not to do anything but read" :D |
||
| { | ||
| // Process all available gestures each frame | ||
| while (TouchPanel.IsGestureAvailable) | ||
| { | ||
| GestureSample gesture = TouchPanel.ReadGesture(); | ||
| ProcessGesture(gesture); | ||
| } | ||
|
|
||
| base.Update(gameTime); | ||
| } | ||
| ``` | ||
|
|
||
| ### Why Use a Loop? | ||
|
|
||
| Multiple gestures can occur between frames, especially during complex touch interactions. The `while` loop ensures you process all queued gestures rather than missing any: | ||
|
|
||
| - **Single `if` statement** - Might miss gestures if multiple occur | ||
| - **`while` loop** - Processes all queued gestures until none remain | ||
|
|
||
| ## Reading and Processing Gestures | ||
|
|
||
| Each gesture is read using `TouchPanel.ReadGesture()`, which returns a `GestureSample` containing the gesture details: | ||
|
|
||
| ```csharp | ||
| void ProcessGesture(GestureSample gesture) | ||
| { | ||
| switch (gesture.GestureType) | ||
| { | ||
| case GestureType.Tap: | ||
| HandleTap(gesture.Position); | ||
| break; | ||
|
|
||
| case GestureType.Flick: | ||
| HandleFlick(gesture.Position, gesture.Delta); | ||
| break; | ||
|
|
||
| case GestureType.Pinch: | ||
| HandlePinch(gesture.Position, gesture.Position2); | ||
| break; | ||
|
|
||
| // Handle other gesture types... | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| ### GestureSample Properties | ||
|
|
||
| Each `GestureSample` provides different data depending on the gesture type: | ||
|
|
||
| - **`GestureType`** - The type of gesture detected | ||
| - **`Position`** - Primary touch point location (screen coordinates) | ||
| - **`Position2`** - Secondary touch point (used for pinch gestures) | ||
| - **`Delta`** - Movement vector for drag and flick gestures | ||
| - **`Timestamp`** - When the gesture occurred | ||
|
|
||
| ### Example: Processing Different Gesture Data | ||
|
|
||
| ```csharp | ||
| switch (gesture.GestureType) | ||
| { | ||
| case GestureType.Tap: | ||
| // Use: Position | ||
| Vector2 tapLocation = gesture.Position; | ||
| break; | ||
|
|
||
| case GestureType.Flick: | ||
| // Use: Position (start), Delta (direction/speed) | ||
| Vector2 flickStart = gesture.Position; | ||
| Vector2 flickDirection = gesture.Delta; | ||
| break; | ||
|
|
||
| case GestureType.Pinch: | ||
| // Use: Position (finger 1), Position2 (finger 2) | ||
| Vector2 finger1 = gesture.Position; | ||
| Vector2 finger2 = gesture.Position2; | ||
| break; | ||
| } | ||
| ``` | ||
|
|
||
| ## Complete Example | ||
|
|
||
| Here is a minimal working example demonstrating all three concepts: | ||
|
|
||
| ```csharp | ||
| public class TouchGame : Game | ||
| { | ||
| protected override void Initialize() | ||
| { | ||
| // 1. Register for gestures | ||
| TouchPanel.EnabledGestures = GestureType.Tap | GestureType.Flick; | ||
| base.Initialize(); | ||
| } | ||
|
|
||
| protected override void Update(GameTime gameTime) | ||
| { | ||
| // 2. Check for available gestures | ||
| while (TouchPanel.IsGestureAvailable) | ||
| { | ||
| // 3. Read and process each gesture | ||
| GestureSample gesture = TouchPanel.ReadGesture(); | ||
|
|
||
| switch (gesture.GestureType) | ||
| { | ||
| case GestureType.Tap: | ||
| Console.WriteLine($"Tap at {gesture.Position}"); | ||
| break; | ||
|
|
||
| case GestureType.Flick: | ||
| Console.WriteLine($"Flick from {gesture.Position} with delta {gesture.Delta}"); | ||
| break; | ||
| } | ||
| } | ||
|
|
||
| base.Update(gameTime); | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| ## Dungeon Slime Sample | ||
|
|
||
| In the _DungeonSlime_ game, touch input is encapsulated in a new **TouchInfo** class, which internally uses the **TouchPanel** API to detect and process gestures. | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. OK, so I can see the above was just theory but it wasn't clear previously. Alternatively (recommended) restructure the chapter to start with implementing and then each of the steps above while doing them. In testing of the original tutorial, readers felt they understood better being told about features as they implemented them, and it also gave them something to do while reading. |
||
|
|
||
| This class abstracts gesture handling and exposes methods like `IsTouchSwipeUp()`, `IsTouchSwipeDown()`, etc., making it easy to check for swipe actions. | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Missing instructions for HOW to achieve this, best to ensure instructions are SPECIFIC in operation:
Hope that helps. |
||
|
|
||
| The **TouchInfo** class is then integrated into the **GameController** class, allowing the game logic to respond to touch gestures in a platform-agnostic way. This modular approach keeps input handling clean and maintainable, and ensures that touch support works seamlessly alongside keyboard and gamepad input. | ||
|
|
||
| ### Extending Move Functions with Touch Gestures | ||
|
|
||
| To support touch input alongside keyboard and gamepad, extend your movement functions to include checks for swipe gestures. | ||
|
|
||
| For example: | ||
|
|
||
| ```csharp | ||
| public static bool MoveUp() | ||
| { | ||
| return s_keyboard.WasKeyJustPressed(Keys.Up) || | ||
| s_keyboard.WasKeyJustPressed(Keys.W) || | ||
| s_gamePad.WasButtonJustPressed(Buttons.DPadUp) || | ||
| s_gamePad.WasButtonJustPressed(Buttons.LeftThumbstickUp) || | ||
| IsTouchSwipeUp(); <=== extended to support touch | ||
| } | ||
| ``` | ||
|
|
||
| This approach ensures your game responds to swipe gestures for movement, providing a consistent experience across touch, keyboard, and gamepad input. | ||
|
|
||
| ## Conclusion | ||
|
|
||
| This foundation enables you to respond to touch input across iOS and Android platforms using MonoGame's cross-platform gesture system. | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
iOS mentions having an iOS developer account. Is the same setup not also required for Android?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A Google Developer account is required to publish, but not to build I think.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added comment to page to say that you do not need a paid developer account to build locally and test.