-
Notifications
You must be signed in to change notification settings - Fork 3
main.cpp
This is the main entry point for any application that uses 'olcPixelGameEngine_Mobile.cpp'. It is from this class you start and create all our your amazing PGE mobile games.
To get our OLC PGE Engine up and running on both Android & iOS we need a few headers and some #define
. These work together to allow you to just development your application/game using the amazing PGE 2.0 and C++ without having to handle all complicitly under the hood to get your code to work smoothly on both operating systems.
We like to keep things super simple here at the One Lone Coder Community so this is all done and dusted for you :)
-
pch.h
Pre-Complied Header, this is used to setup and complied required headers, makes comply times faster, and helps us to ensure the correct sub headers for Android & iOS are complied and ready for you to use. NOTE the iOSpch.h
file is handled within the Objective C -
#include "../_ProjectName_/pch.h"
the ProjectName is auto generated, do not change, well you can, but I wouldn't ;) -
#if defined (__ANDROID__)
Complier Talk Tells the complier to use this block of code to for Android Devices
#if defined (__ANDROID__)
#include "../<ProjectName>/pch.h"
#endif //__ANDROID__
-
#if defined (__APPLE__)
Complier Talk Tells the complier to use this block of code to for APPLE iOS Devices -
ios_native_app_glue.h
the is a GLUE interface between the PGE Mobile 2.0 and the iOS application. -
#include <memory>
there are a few Smart Pointers needed to get thing running and linking, therefore we include thememory.h
here
#if defined (__APPLE__)
#include "ios_native_app_glue.h"
#include <memory>
#endif
- SIMD (SSE2) is enabled by default for all x86/64 CPUs, and is auto disabled when an ARM/ARM64 CPU is detected
-
#define STBI_NO_SIMD
Complier Talk Tells the complier not to use SIMD. This is commented out by default. - SIMD/NEON greatly improves the speed of your game
- NOTE Mobile devices CPU/GPU are very weak compared to their big sisters in computers. SIMD/NEON technology is used to greatly reduce this gap.
//#define STBI_NO_SIMD // Removes SIMD Support
// SIMD greatly improves the speed of your game
-
#if defined(__arm__)||(__aarch64__)
Complier Talk Tells the complier to use this block of code when an ARM or ARM64 CPU is detected -
#define STBI_NEON
for ARM/ARM64, Complier Talk Tells the complier to use use Advance SIMD NEON when loading and processing images. - Nearly every mobile device today use ARM/ARM64, except of course for the Intel Atom used in most Chrome Books and some Tablets
- NOTE Mobile devices CPU/GPU are very weak compared to their big sisters in Computers. SIMD/NEON technology is used to greatly reduce this gap.
#if defined(__arm__)||(__aarch64__)
#define STBI_NEON
#endif
-
#define OLC_PGE_APPLICATION
Complier Talk Tells the complier to use the olcPixelGameEngine.h as a header-only library, where the header both declares and also defines the bodies of the methods. -
#define OLC_IMAGE_STB
Complier Talk Tells the complier to useSTBImage.h
for image processing, we need to use this overlibpng.h
as it supports SIMD/NEON, otherwise, as stated above, things would be too slow. - Nearly every mobile device today use ARM/ARM64, except of course for the Intel Atom used in most Chrome Books and some Tablets
-
#include "olcPixelGameEngine_Mobile.h"
IMPORTANT: we must includeolcPixelGameEngine_Mobile.h
notolcPixelGameEngine.h
, the mobile edition ; althought contains the same functionality; is very different under the hood. - The OLC PGE 2.0 Mobile only supports Android and iOS only.
- NOTE OLC PGE 2.0 Mobile has support for iOS Apps downloaded from the Apple Store to a MAC only.
#define OLC_PGE_APPLICATION
#define OLC_IMAGE_STB
#include "olcPixelGameEngine_Mobile.h"
-
#define OLC_PGEX_MINIAUDIO
Complier Talk Tells the complier to use OLC PEGX Mini Audio for sounds - Checkout OLC PGEX MiniAudio Thanks Moro1138
#define OLC_PGEX_MINIAUDIO
#include "olcPGEX_MiniAudio.h" // Checkout https://github.com/Moros1138/olcPGEX_MiniAudio Thanks Moros1138
-
#include <fstream>
Used for saving the SaveState to a file, see add link to OnSaveStateRequested
#include <fstream> // Used for saving the SaveState to a file
To ensure proper cross platform support between Android and iOS it is recommended to keep the class name as PGE_Mobile, This will ensure the iOS can launch the engine correctly, if you change it make the required changes in <TODO: Link> GameViewController.mm in the iOS app to suit.
-
class PGE_Mobile : public olc::PixelGameEngine
creates an instance of our game class with a public interface of olc::PixelGameEngine, in short gives us access to all the cool and wonderful functionalities of the Pixel Game Engine -
PGE_Mobile() { ... }
Class constructor. NOTE Never load an image/object from the constructor, always useOnUserCreate()
(TODO: Add link to why this can break on iOS) -
sAppName = "Android/iOS Demo";
Stores the name of your game / application -
For information on
OnUserCreate()
,OnUserUpdated()
andOnUserDestroy()
please see the OLC PGE 2.0 wiki as these are standard PGE 2.0 methods -
void OnSaveStateRequested() override
fires when your application as lost focus and might be destoryed. i.e. An incoming phone call, Text Message, An Alert, anything where the user has moved away from your application.- The
void OnDestory() override
maybe not always fire, as it depends on the current actions of the user. However once thevoid OnDestory() override
is fired it means the OS is about to destroy your application. It is important you save what details you need. -
void OnSaveStateRequested() override
will always be the last method fired, i.e. it will always fire after an OnUserDestory() if requested from the OS. - You have limited time to save your game state, save only important information i.e. Player Location, Game Level etc. Do not try to store any memory objects, like Smart Points, Vectors etc, as once an application is destroyed all memory associated with the application is also destroyed.
- The
-
void OnRestoreStateRequested() override {
fires when your application loads.- Fires when your application loads regardless if the application was destroyed previously.
- Fires when your application regains focus, i.e. after an incoming call, text message etc
- Fires before the
OnUserCreate()
- Use this method to reload your game state
-
void OnLowMemoryWarning() override {
, fires when the OS detects it is low on memory- This method is fired on all currently active applications
- Use this method to clean up any unused, leftover or not needed memory (Sprites, Decals, vectors)
- Use this method to clear any vectors or blocks of memory that can be reloaded later
- Use this method to save memory to a file
- If the OS cannot gain back enough memory from its applications it will force close these applications
- Please follow the steps above to ensure your application is not force closed
- BTW Most Application Developers never implement this method, and then wonder why their app is closed at random, don't be one them please!
class PGE_Mobile : public olc::PixelGameEngine {
public:
PGE_Mobile() {
sAppName = "Android/iOS Demo";
}
bool OnUserCreate() override {
// Load images, objects, sounds etc etc
}
bool OnUserUpdate(float fElapsedTime) override {
// Execute Game Logic fires once a frame
return true;
}
bool OnUserDestroy() override {
// Fires when the app is about to be destroyed
return true;
}
void OnSaveStateRequested() override {
// Fires when the app is about to be destroyed
}
void OnRestoreStateRequested() override {
// Fires when the app is restored
}
void OnLowMemoryWarning() override {
// Fires when the OS is low on memory, reduce your memory usage or risk your app been closed
}
}
There are two entry points for Android and iOS respectfully. in order to maintain cross platform compatibility the entry points for both operating systems are different, as both Operation Systems work completely different.
The good news is once you have your entry point setup correctly, as detailed below, everything after this is the same for both Operating Systems.
We like to keep things super simple here at the One Lone Coder Community
Android:
-
#if defined (__ANDROID__)
Complier Talk Tells the complier to use this block of code to for Android Devices
#if defined (__ANDROID__)
/*
* Code stuff
*/
#endif //__ANDROID__
-
void android_main()
this is the main entry point of a native application - It runs in its own thread, with its own event loop for receiving input events and doing other things.
- This is now what drives the engine, the thread is controlled from the OS
void android_main(struct android_app* initialstate) {
/*
* Code stuff
*/
}
-
struct android_app* initialstate
initalstate allows you to make some more edits to your app before the PGE Engine starts - Recommended just to leave it at its defaults, but change it at your own risk
- to access the Android directly in your code
android_app* pMyAndroid = this->pOsEngine.app;
void android_main(struct android_app* initialstate) {
/*
* initialstate stuff
* <TODO> : Create a section for explaining intialstate
*/
}
-
PGE_Mobile demo
class instantiation, starts up the PGE Engine -
demo.Construct(1280, 720, 2, 2, true, false, false);
Note it is best to use HD(1280, 720, ? X ? pixel, Fullscreen = true) the engine can scale this best for all screen sizes, without affecting performance... well it will have a very small affect, it will depend on your pixel size. Note: cohesion is currently not working. -
demo.Start();
Start the application
PGE_Mobile demo;
demo.Construct(1280, 720, 2, 2, true, false, false);
demo.Start(); // Lets get the party started
- Example:
#if defined (__ANDROID__)
void android_main(struct android_app* initialstate) {
PGE_Mobile demo;
demo.Construct(1280, 720, 2, 2, true, false, false);
demo.Start(); // Lets get the party started
}
#endif
iOS:
-
#if defined (__APPLE__)
Complier Talk Tells the complier to use this block of code to for APPLE iOS Devices
#if defined (__APPLE__)
/*
* Code stuff
*/
#endif //__APPLE__
-
int ios_main(IOSNativeApp* pIOSNatvieApp)
The is the entry point from the iOS Objective C, called during the start-up of your application - Use the objects defined in IOSNativeApp to pass data to the Objective C
- By Default you must at minimum pass the game construct vars, pIOSNatvieApp->SetPGEConstruct
- iOS runs in its own threads, with its own event loop for receiving input events and doing other things.
- This is now what drives the engine, the thread is controlled from the OS
int ios_main(IOSNativeApp* pIOSNatvieApp) {
/*
* Code Stuff
*/
}
-
int ios_main(IOSNativeApp* pIOSNatvieApp)
pIOSNatvieApp allows access to the OS App options - The iOS will instance your app differently to how Android does it
- In the iOS it will automatically create the required classes and pointers to get the PGE up and running successfully.
- IMPORTANT: You must set your class name to PGE_Mobile (see above) always for iOS
- Don't worry it will not conflict with any other apps that use the same base class name of PGE_Mobile
- To access the iOS directly in your code
auto* pMyApple = this->pOsEngine.app;
int ios_main(IOSNativeApp* pIOSNatvieApp) {
/*
* pIOSNatvieApp-> <TODO> Create section explaining options
*/
}
-
pIOSNatvieApp->SetPGEConstruct(0, 0, 2, 2, true, true, false);
Note it is best to use HD(0, 0, ? X ? pixel, Fullscreen = true) the engine can scale this best for all screen sizes, without affecting performance... well it will have a very small affect, it will depend on your pixel size Note: cohesion is currently not working. -
return EXIT_SUCCESS;
You must return EXIT_SUCCESS in order to tell the iOS to start up the engine, you can return EXIT_FAILURE, error codes etc will stop the startup of the engine and the app will exit gracefully
pIOSNatvieApp->SetPGEConstruct(0, 0, 2, 2, true, true, false);
return EXIT_SUCCESS;
- Example:
#if defined(__APPLE__)
int ios_main(IOSNativeApp* pIOSNatvieApp)
{
pIOSNatvieApp->SetPGEConstruct(0, 0, 2, 2, true, true, false);
return EXIT_SUCCESS;
}
#endif
Please Note: Although this is considered to be the main entry point, under the hood it is not, the main entry point comes from the phone OS and is used to start up all the threads, memory, smart pointers etc in order for the PGE Engine to start up. The reason we state that main.cpp is the main entry point is to allow cross compatibility with the OLC PGE 2.0 engine for Windows, MAC, Linux, PlayStation and the list goes on.
//////////////////////////////////////////////////////////////////
// Pixel Game Engine Mobile Release 2.2.8 //
// John Galvin aka Johnngy63: 18-Jun-2024 //
// iOS Sensor NOT supported, coming soon //
// Please report all bugs to https://discord.com/invite/WhwHUMV //
// Or on Github: https://github.com/Johnnyg63 //
//////////////////////////////////////////////////////////////////
//
// Base Project
//
// Set up headers for the different platforms
#if defined (__ANDROID__)
#include "../ForWiki/pch.h"
//#include "pch.h"
#endif
#if defined (__APPLE__)
#include "ios_native_app_glue.h"
#include <memory>
#endif
//#define STBI_NO_SIMD // Removes SIMD Support
// SIMD greatly improves the speed of your game
#if defined(__arm__)||(__aarch64__)
// Use Advance SIMD NEON when loading images for STB Default is SSE2 (x86)
#define STBI_NEON
#endif
#define OLC_PGE_APPLICATION
#define OLC_IMAGE_STB
#include "olcPixelGameEngine_Mobile.h"
#define OLC_PGEX_MINIAUDIO
#include "olcPGEX_MiniAudio.h" // Checkout https://github.com/Moros1138/olcPGEX_MiniAudio Thanks Moros1138
#include <fstream> // Used for saving the savestate to a file
/// <summary>
/// To ensure proper cross platform support keep the class name as PGE_Mobile
/// This will ensure the iOS can launch the engine correctly
/// If you change it make the required changes in GameViewController.mm in the iOS app to suit
/// </summary>
class PGE_Mobile : public olc::PixelGameEngine {
public:
PGE_Mobile() {
sAppName = "Android/iOS Demo";
}
/* Vectors */
std::vector<std::string> vecMessages;
/* END Vectors*/
int nFrameCount = 0;
int nStep = 20;
/* Sprites */
olc::Sprite* sprTouchTester = nullptr;
olc::Sprite* sprOLCPGEMobLogo = nullptr;
/* END Sprites*/
/* Decals */
olc::Decal* decTouchTester = nullptr;
olc::Decal* decOLCPGEMobLogo = nullptr;
/* End Decals */
/* Sensors */
std::vector<olc::SensorInformation> vecSensorInfos;
/*End Sensors*/
// To keep track of our sample ID
// Ensure that all sound IDs are set to -1 stop memory leak when Android/iOS takes
// the app out of focus
int32_t song1 = -1;
// For demonstration controls, with sensible default values
float pan = 0.0f;
float pitch = 1.0f;
float seek = 0.0f;
float volume = 1.0f;
// The instance of the audio engine, no fancy config required.
olc::MiniAudio ma;
public:
//Example Save State Struct and Vector for when your app is paused
struct MySaveState {
std::string key;
int value;
};
std::vector<MySaveState> vecLastState;
std::string sampleAFullPath; // Holds the full path to sampleA.wav
public:
bool OnUserCreate() override {
//NOTE: To access the features with your phone device use:
#if defined(__ANDROID__)
// Access android directly
//android_app* pMyAndroid = this->pOsEngine.app;
// USE OF SOUND olcPGE_MiniAudio
/*
* For Android you cannot play the sounds directly from the assets as you would
* on a Windows/Mac/Linux system. Android compress your assets in a compress file to
* save on valuable phone storage. AndroidAudio (AAudio), miniAudio, and most others need
* to be able to stream the music data, in short they are not very good at streaming for
* a compress file.
* Therefore you will need to extract these sound files to internal storage so the sounds
* can be played.
*
* In short, as I know you didn't read the above, you cannot stream from an asset in Android
*
*/
std::string songFullPath = (std::string)app_GetInternalAppStorage() + "/sounds/song1.mp3";
olc::rcode fileRes = olc::filehandler->ExtractFileFromAssets("sounds/song1.mp3", songFullPath);
switch (fileRes) {
case olc::rcode::NO_FILE:
{ break; }
case olc::rcode::FAIL:
{ break; }
case olc::rcode::OK:
{
// only load the song if it is not already loaded
song1 = ma.LoadSound(songFullPath);
break;
}
}
sampleAFullPath = (std::string)app_GetInternalAppStorage() + "/sounds/SampleA.wav";
olc::filehandler->ExtractFileFromAssets("sounds/SampleA.wav", sampleAFullPath);
#endif
#if defined(__APPLE__)
// Access iOS directly
//apple_app* pMyApple = this->pOsEngine.app;
// USE OF SOUND olcPGE_MiniAudio
std::string songFullPath = (std::string)app_GetInternalAppStorage() + "/sounds/song1.mp3";
olc::rcode fileRes = olc::filehandler->ExtractFileFromAssets("sounds/song1.mp3", songFullPath);
switch (fileRes) {
case olc::rcode::NO_FILE:
{ break; }
case olc::rcode::FAIL:
{ break; }
case olc::rcode::OK:
{
if (song1 < 0)
{
song1 = ma.LoadSound(songFullPath);
}
break;
}
}
sampleAFullPath = (std::string)app_GetInternalAppStorage() + "/sounds/SampleA.wav";
olc::filehandler->ExtractFileFromAssets("sounds/SampleA.wav", sampleAFullPath);
#endif
sprTouchTester = new olc::Sprite("images/north_south_east_west_logo.png");
decTouchTester = new olc::Decal(sprTouchTester);
sprOLCPGEMobLogo = new olc::Sprite("images/olcpgemobilelogo.png");
decOLCPGEMobLogo = new olc::Decal(sprOLCPGEMobLogo);
return true;
}
// <summary>
/// Draws a Target Pointer at the center position of Center Point
/// </summary>
/// <param name="vCenterPoint">Center Position of the target</param>
/// <param name="nLineLenght">Length of lines</param>
/// <param name="nCircleRadus">Center Circle radius</param>
void DrawTargetPointer(olc::vi2d vCenterPoint, int32_t nLineLenght, int32_t nCircleRadus, olc::Pixel p = olc::WHITE)
{
/*
|
|
----O----
|
|
*/
FillCircle(vCenterPoint, nCircleRadus, p);
DrawLine(vCenterPoint, { vCenterPoint.x, vCenterPoint.y + nLineLenght }, p);
DrawLine(vCenterPoint, { vCenterPoint.x, vCenterPoint.y - nLineLenght }, p);
DrawLine(vCenterPoint, { vCenterPoint.x + nLineLenght, vCenterPoint.y }, p);
DrawLine(vCenterPoint, { vCenterPoint.x - nLineLenght, vCenterPoint.y }, p);
}
bool OnUserUpdate(float fElapsedTime) override {
SetDrawTarget(nullptr);
Clear(olc::BLUE);
nFrameCount = GetFPS();
std::string sLineBreak = "-------------------------";
std::string sMessage = "OneLoneCoder.com";
vecMessages.push_back(sMessage);
sMessage = "PGE Mobile Release 2.2.8";
vecMessages.push_back(sMessage);
sMessage = "Now With iOS Support";
vecMessages.push_back(sMessage);
sMessage = "NOTE: Android FPS = CPU FPS, iOS = GPU FPS";
vecMessages.push_back(sMessage);
sMessage = sAppName + " - FPS: " + std::to_string(nFrameCount);
vecMessages.push_back(sMessage);
sMessage = "---";
vecMessages.push_back(sMessage);
sMessage = "Volume <" + std::to_string(volume) + "> Btn Up, Btn Down";
vecMessages.push_back(sMessage);
if (ma.IsPlaying(song1))
{
sMessage = "Touch Screen: Pause";
vecMessages.push_back(sMessage);
}
else
{
sMessage = "Touch Screen: Play";
vecMessages.push_back(sMessage);
}
sMessage = "---";
vecMessages.push_back(sMessage);
sMessage = "Music: Joy Ride [Full version] by MusicLFiles";
vecMessages.push_back(sMessage);
sMessage = "Free download:";
vecMessages.push_back(sMessage);
sMessage = "https://filmmusic.io/song/11627-joy-ride-full-version";
vecMessages.push_back(sMessage);
sMessage = "Licensed under CC BY 4.0:";
vecMessages.push_back(sMessage);
sMessage = "https://filmmusic.io/standard-license";
vecMessages.push_back(sMessage);
vecMessages.push_back(sLineBreak);
std::string sTouchScreen = "Touch the screen with two fingers";
vecMessages.push_back(sTouchScreen);
vecMessages.push_back(sLineBreak);
olc::vi2d centreScreenPos = GetScreenSize();
centreScreenPos.x = centreScreenPos.x / 2;
centreScreenPos.y = centreScreenPos.y / 2;
DrawTargetPointer(centreScreenPos, 50, 10);
// Get the default touch point
// This is alway Index 0 and first touch piont
olc::vi2d defautTouchPos = GetTouchPos();
std::string defautTouch = "Default Touch 0: X: " + std::to_string(defautTouchPos.x) + " Y: " + std::to_string(defautTouchPos.y);
vecMessages.push_back(defautTouch);
if (GetTouch().bHeld)
{
DrawLine(centreScreenPos, defautTouchPos, olc::YELLOW, 0xF0F0F0F0);
DrawTargetPointer(defautTouchPos, 50, 10, olc::YELLOW);
}
/*
You asked for Multi-touch... you got it!
You can support up to 126 touch points, however most phones and tablets can only handle 5
As always with touch sensors it is an approximate and always will be
I would recommend no more that 3 points
When you are using lots of touch points it is best to run ClearTouchPoints();
every so often to ensure lost touch points are cleared
*/
olc::vi2d touchPos;
// The more touch points the harder to manage
for (int i = 1; i < 5; i++)
{
if (GetTouch(i).bHeld)
{
touchPos = GetTouchPos(i);
std::string TouchID = "Touch ID: " + std::to_string(i) + " X: " + std::to_string(touchPos.x) + " Y: " + std::to_string(touchPos.y);
vecMessages.push_back(TouchID);
DrawLine(centreScreenPos, touchPos, olc::WHITE, 0xF0F0F0F0);
DrawTargetPointer(touchPos, 50, 10);
}
}
// Called once per frame, draws random coloured pixels
// Uncomment me if you dare
/*for (int x = 0; x < ScreenWidth(); x++)
for (int y = 0; y < ScreenHeight(); y++)
Draw(x, y, olc::Pixel(rand() % 256, rand() % 256, rand() % 256));
*/
nStep = 10;
for (auto& s : vecMessages)
{
DrawString(20, nStep, s);
nStep += 10;
}
vecMessages.clear();
if (GetTouch(0).bPressed) {
// Toggle takes a sample ID (int) and either starts playback or pauses playback
// depending on whether the sample is currently playing, or not.
ma.Toggle(song1);
}
if (GetTouch(1).bPressed) {
ma.Play(sampleAFullPath);
}
if (GetKey(olc::A).bHeld)
{
volume += 1.0f * fElapsedTime;
if (volume > 1.0f) volume = 1.0f;
}
if (GetKey(olc::B).bHeld)
{
volume -= 1.0f * fElapsedTime;
if (volume < 0.0f) volume = 0.0f;
}
if (GetKey(olc::VOLUME_DOWN).bHeld) {
// NOTE: Android volume buttons can be read but cannot be captured
// NOTE: iOS volume buttons cannot be read and cannot be captured
volume -= 1.0f * fElapsedTime;
if (volume < 0.0f) volume = 0.0f;
}
if (GetKey(olc::VOLUME_UP).bHeld) {
// NOTE: Android volume buttons can be read but cannot be captured
// NOTE: iOS volume buttons cannot be read and cannot be captured
volume += 1.0f * fElapsedTime;
if (volume > 1.0f) volume = 1.0f;
}
// Set volume, takes a sample ID (int), and a float
// 0.0 to 1.0 where 1.0 is full volume
ma.SetVolume(song1, volume);
// Gets the current playback position in the provided sample ID (int),
// returns float 0.0 to 1.0, nearer 1.0 is near the end
seek = ma.GetCursorFloat(song1);
// Draw Logo
DrawDecal({ 5.0f, (float)ScreenHeight() - 100 }, decOLCPGEMobLogo, { 0.5f, 0.5f });
// Draw The Playback Cursor (aka the position in the sound file)
FillRect({ 0, ScreenHeight() - 10 }, { (int)(ScreenWidth() * seek), 10 }, olc::YELLOW);
return true;
}
bool OnUserDestroy() override {
return true;
}
void OnSaveStateRequested() override
{
// Fires when the OS is about to put your game into pause mode
// You have, at best 30 Seconds before your game will be fully shutdown
// It depends on why the OS is pausing your game though, Phone call, etc
// It is best to save a simple Struct of your settings, i.e. current level, player position etc
// NOTE: The OS can terminate all of your data, pointers, sprites, layers can be freed
// Therefore do not save sprites, pointers etc
// Example 1: vector
vecLastState.clear();
vecLastState.push_back({ "MouseX", 55 });
vecLastState.push_back({ "MouseY", 25 });
vecLastState.push_back({ "GameLevel", 5 });
#if defined(__ANDROID__)
// You can save files in the android Internal app storage
const char* internalPath = app_GetInternalAppStorage(); //Android protected storage
#endif
#if defined(__APPLE__)
// For iOS the internal app storage is read only, therefore we use External App Storage
const char* internalPath = app_GetExternalAppStorage(); // iOS protected storage AKA /Library
#endif
std::string dataPath(internalPath);
// internalDataPath points directly to the files/ directory
std::string lastStateFile = dataPath + "/lastStateFile.bin";
std::ofstream file(lastStateFile, std::ios::out | std::ios::binary);
if (file)
{
float fVecSize = vecLastState.size();
file.write((char*)&fVecSize, sizeof(long));
for (auto& vSS : vecLastState)
{
file.write((char*)&vSS, sizeof(MySaveState));
}
file.close();
}
}
void OnRestoreStateRequested() override
{
// This will fire every time your game launches
// OnUserCreate will be fired again as the OS may have terminated all your data
#if defined(__ANDROID__)
// You can save files in the android Internal app storage
const char* internalPath = app_GetInternalAppStorage(); //Android protected storage
#endif
#if defined(__APPLE__)
// For iOS the internal app storage is read only, therefore we use External App Storage
const char* internalPath = app_GetExternalAppStorage(); // iOS protected storage AKA /Library
#endif
std::string dataPath(internalPath);
std::string lastStateFile = dataPath + "/lastStateFile.bin";
vecLastState.clear();
std::ifstream file(lastStateFile, std::ios::in | std::ios::binary);
MySaveState saveState;
if (file)
{
float fVecSize = 0.0f;
file.read((char*)&fVecSize, sizeof(long));
for (long i = 0; i < fVecSize; i++)
{
file.read((char*)&saveState, sizeof(MySaveState));
vecLastState.push_back(saveState);
}
file.close();
// Note this is a temp file, we must delete it
std::remove(lastStateFile.c_str());
}
}
};
#if defined (__ANDROID__)
/**
* This is the main entry point of a native application that is using
* android_native_app_glue. It runs in its own thread, with its own
* event loop for receiving input events and doing other things.
* This is now what drives the engine, the thread is controlled from the OS
*/
void android_main(struct android_app* initialstate) {
/*
initalstate allows you to make some more edits
to your app before the PGE Engine starts
Recommended just to leave it at its defaults
but change it at your own risk
to access the Android/iOS directly in your code
android_app* pMyAndroid = this->pOsEngine.app;;
*/
PGE_Mobile demo;
/*
Note it is best to use HD(1280, 720, ? X ? pixel, Fullscreen = true) the engine can scale this best for all screen sizes,
without affecting performance... well it will have a very small affect, it will depend on your pixel size
Note: cohesion is currently not working
*/
demo.Construct(1280, 720, 2, 2, true, false, false);
demo.Start(); // Lets get the party started
}
#endif
#if defined(__APPLE__)
/*
* The is the calling point from the iOS Objective C, called during the start-up of your application
* Use the objects definded in IOSNativeApp to pass data to the Objective C
* By Default you must at minmum pass the game construct vars, pIOSNatvieApp->SetPGEConstruct
*
* iOS runs in its own threads, with its own
* event loop for receiving input events and doing other things.
* This is now what drives the engine, the thread is controlled from the OS
*/
int ios_main(IOSNativeApp* pIOSNatvieApp)
{
// The iOS will instance your app differently to how Android does it
// In the iOS it will automatically create the required classes and pointers
// to get the PGE up and running successfully.
// IMPORTANT: You must set your class name to PGE_Mobile (see above) always for iOS
// Don't worry it will not conflict with any other apps that use the same base class name of PGE_Mobile
// I got your back
// Finally just like the Android you can access any available OS options using pIOSNatvieApp
// Please note options will NOT be the same across both platforms
// It is best to use the build in functions for File handling, Mouse/Touch events, Key events, Joypad etc
//
// To access the iOS directly in your code
// auto* pMyApple = this->pOsEngine.app;
//
/*
Note it is best to use HD(0, 0, ? X ? pixel, Fullscreen = true) the engine can scale this best for all screen sizes,
without affecting performance... well it will have a very small affect, it will depend on your pixel size
Note: cohesion is currently not working
Note: It is best to set maintain_aspect_ratio to false, Fullscreen to true and use the olcPGEX_TransformView.h to manage your world-view
in short iOS does not want to play nice, the screen ratios and renta displays make maintaining a full screen with aspect radio a pain to manage
*/
pIOSNatvieApp->SetPGEConstruct(0, 0, 2, 2, true, true, false);
// We now need to return SUCCESS or FAILURE to get the party stated!!!!
return EXIT_SUCCESS;
}
#endif
- For Visual Studio All In One Android and iOS (Windows) Project Template: OLC Pixel Game Engine Mobile 2.2.8 Visual Studio for Android and iOS
- For Visual Studio Android Only (Windows) Use this project: OLC Pixel Game Engine Mobile 2.2.8 for Android Visual Studio
- For Android Studio (Windows/Linux/MAC) Use this project: OLC Pixel Game Engine Mobile 2.2.8 for Android Studio
- For Xcode (MAC) Use this project: OLC Pixel Game Engine Mobile 2.2.8 for Xcode