Mobile game considerations?

Questions about the LÖVE API, installing LÖVE and other support related questions go here.
Forum rules
Before you make a thread asking for help, read this.
Post Reply
Kemair
Prole
Posts: 2
Joined: Wed Jul 29, 2020 12:27 am

Mobile game considerations?

Post by Kemair »

Hello everyone,

I'm a new coder who finished CS50 about a month ago, so I have some basics of programming, and have made pong and the basic mario-like game from the CS50 tutorials. Please tailor your advice accordingly.

I'm currently coding a game that is exclusively a mobile phone game. It will be using pixel art I'll have commissioned. I'd like it to be on Android and iOS. My control scheme exclusively consists of pressing buttons on the game's UI, so I'm not too worried about getting the controls to work on the phones. All the other game mechanics I have in my head shouldn't have to be altered for a different platform (so I hope haha).

What I am worried about is I have no idea if I should be planning for anything in my code for the game to work on Android/iOS. I have already read the topics on the wiki and forums regarding distribution. I have no problem spending the time working out how to get features to work, I just don't want to spend months making something and finding out it all has to be redone because I wasn't aware of something basic.

1. Conceptually, what are the issues regarding screen size, resolution, and having my art assets work with all that? If the game works on my laptop, will the art scale on the phone? Should I be testing everything from the start in a certain resolution on my laptop to emulate the phone screen? Are you aware of any good resources regarding these types of topics?

2. Is my code just going to work after I import it with the distribution tools? Are there certain features of love or Lua that I should avoid using because they aren't cross platform? Do phones work in some different way that I should structure how my code handles my game mechanics? Should I be skeptical of Lua's tables and getting creative with them? Is multi-threading at all a relevant consideration for a somewhat simple game?

3. Does running a (cloud) server change any considerations? Is this required to stop cheating from happening on a leaderboard system? Do I have to consider hackers altering in game values or does Android/iOS prevent this from happening? How are in-game real life money purchases handed normally? Any good resources on this as well is appreciated.

4. Is there any other category of a potential problem I'm not even aware of?

I've always wanted to make games, so thank you all for helping me out on my journey!
User avatar
pgimeno
Party member
Posts: 3550
Joined: Sun Oct 18, 2015 2:58 pm

Re: Mobile game considerations?

Post by pgimeno »

Note that this post is my personal opinion.
Kemair wrote: Wed Jul 29, 2020 1:25 am 1a. Conceptually, what are the issues regarding screen size, resolution, and having my art assets work with all that?
Good question with no easy answer.

Kemair wrote: Wed Jul 29, 2020 1:25 am 1b. If the game works on my laptop, will the art scale on the phone?
Probably not. Phones usually have bigger resolutions than desktops. In that case, the graphics may look pixel-y or blurry. Or more rarely, it can be the other way around, if you have a large laptop screen and a phone with low resolution.

You can make the assets big enough to look fine at the biggest resolution, and then reduce them. But in that case, test! Something that isn't very well known is that downscaling works by default up to 1/2 the original size. Past that you must activate mipmaps if you don't want your reduced images to look like crap.

Fonts should be handled separately, because they don't support mipmaps, but fortunately they are generated at multiple sizes with perfect resolution, as they are vector graphics, sort of.

Kemair wrote: Wed Jul 29, 2020 1:25 am 1c. Should I be testing everything from the start in a certain resolution on my laptop to emulate the phone screen?
You should check in the actual phone from time to time. Preferably in several phones with different resolutions.

Kemair wrote: Wed Jul 29, 2020 1:25 am 1d. Are you aware of any good resources regarding these types of topics?
I am not. Maybe someone else.

Kemair wrote: Wed Jul 29, 2020 1:25 am 2a. Is my code just going to work after I import it with the distribution tools?
Start by testing this. Make sure you can do it and that it works as you expect. And then hope for no changes having occurred by the time you want to release your final product (like the recent mandatory 64-bit change, or store policies or whatever).

Kemair wrote: Wed Jul 29, 2020 1:25 am 2b. Are there certain features of love or Lua that I should avoid using because they aren't cross platform?
There are two groups that I'm aware of: from phone to desktop, the ones that are typically phone-specific like touch events and accelerometer; from desktop to phone, the keyboard controls; these are hard to port. As far as I understand neither is a concern to you if your controls are basically going to consists of pressing UI buttons, so you can restrict yourself to using the mouse events.

Note that gestures won't work in desktop. If you want something that requires a gesture, you'll have to be prepared to make that available by some other mechanism in platforms that don't have touch screens. For example, a popup context menu could be enabled with both RMB and touching with two fingers.

Kemair wrote: Wed Jul 29, 2020 1:25 am 2c. Do phones work in some different way that I should structure how my code handles my game mechanics?
I'd say the controls mark the big difference. But for the kind of controls you're planning on, not fundamentally. Maybe the kind of public for one platform or the other differs, but that's a "meta issue" not really related to Löve.

Kemair wrote: Wed Jul 29, 2020 1:25 am 2d. Should I be skeptical of Lua's tables and getting creative with them?
Lua has a problem. The garbage collector sucks. The more objects the GC needs to deal with, the slower it gets. For big projects, GC issues manifest themselves as lag spikes.

There are two ways to stress the GC: to have lots of active objects, and to generate lots of garbage. The first means that the fewer tables you use, the better. For example, in case of 2D maps, it's better to flatten your map to 1D, than having 1 table with NROWS sub-tables each with a row.

The second means that you should avoid creating temporary variables that need cleaning up. For example, avoid things like this:

Code: Select all

myFunc{param1 = 3, param2 = 5}
You could rewrite it like this:

Code: Select all

local myTable = {} -- place this where it will be executed only once
...
-- every time you want to call, overwrite the current values:
myTable.param1 = 3
myTable.param2 = 5
myFunc(myTable)
Avoid creating functions on the fly; in most cases you don't need them to work as closures, or you can make non-closure versions. Keep them until they are really needed. For example, this is bad:

Code: Select all

local function newObj()
  local obj = {x = 0}
  function obj:incX()
     obj.x = obj.x + 1
  end
  return obj
end
Instead, create the function outside the other function, making use of the `self` parameter, and add a reference to it in the object:

Code: Select all

local function obj_incX(self)
  self.x = self.x + 1
end

local function newObj()
  local obj = {x = 0, incX = obj_incX}
  return obj
end
Relying exclusively on metatables for parent class access may not be a good idea, because that requires following the full chain of metatables for every call to a method on the base class. It's better to copy the methods from the parent class to the child in the constructor. Think of that as a cache of the parent methods in the child. That's not saying to avoid using metatables; just to do the copying additionally.

Kemair wrote: Wed Jul 29, 2020 1:25 am 2e. Is multi-threading at all a relevant consideration for a somewhat simple game?
Probably not.

Kemair wrote: Wed Jul 29, 2020 1:25 am 3. Does running a (cloud) server change any considerations? Is this required to stop cheating from happening on a leaderboard system? Do I have to consider hackers altering in game values or does Android/iOS prevent this from happening? How are in-game real life money purchases handed normally? Any good resources on this as well is appreciated.
I'll defer these questions to others.

Kemair wrote: Wed Jul 29, 2020 1:25 am 4. Is there any other category of a potential problem I'm not even aware of?
I don't know of any.
User avatar
zorg
Party member
Posts: 3444
Joined: Thu Dec 13, 2012 2:55 pm
Location: Absurdistan, Hungary
Contact:

Re: Mobile game considerations?

Post by zorg »

I'll keep my opinions on monetized mobile software to myself, so i'll just add a few relevant things instead:

Multi-threading depends on what kind of simple game you're making, however there might be one more consideration i'll touch upon a bit later.

Both ios and android platforms disable the JIT part of luaJIT, that löve uses; what this means for you is that you should/can not use some more advanced things, like the FFI library, along with the fact that things *might* be a bit slower at times... again, depending on game simplicity and how much you want to optimize things, this is probably a moot point, but alas, i thought to mention it.

Your 3rd point is a bit complex, so i'll take it one at a time.
Since you want a centralized leaderboard that can't be cheated, indeed values need to somehow be sent to a server (and then retrieved). For the netcode to not block, you might want to either use coroutines, or a separate thread; i don't know if the former's enough, but it might depend on the networking library you're using if that supports non-blocking calls or not. (iirc luasocket and enet both do, that are included with löve; no https/ssl support for now though, which is kind of needed, probably - especially for money stuff, unless the library dealing with this is secure itself...)

I know cheatengine exists for desktop, but idk if there are apps like that, or even if it's possible to alter memory, on mobile os-es. You should still safeguard the values sent to the server somehow though (e.g. with a hash or something, maybe queried through some process tied to the user's account that is needed to deal with IAP-s). Since you also mentioned in-app purchases, you'll probably need some external library to facilitate those calls; there's one that integrates admob into löve on the forums, but idk if that's relevant/useful for your use-case or not.
Me and my stuff :3True Neutral Aspirant. Why, yes, i do indeed enjoy sarcastically correcting others when they make the most blatant of spelling mistakes. No bullying or trolling the innocent tho.
User avatar
pgimeno
Party member
Posts: 3550
Joined: Sun Oct 18, 2015 2:58 pm

Re: Mobile game considerations?

Post by pgimeno »

zorg wrote: Wed Jul 29, 2020 12:57 pm Both ios and android platforms disable the JIT part of luaJIT, that löve uses; what this means for you is that you should/can not use some more advanced things, like the FFI library,
I don't think that's correct, at least for Android. FFI runs just fine with the JIT off. There's even an FFI library for PUC Lua almost compatible with LuaJIT's.

For iOS, I'm not sure. I know that the JIT is disabled due to Apple's restrictive policies; I'm not sure if FFI is as well.

The JIT is disabled on Android for now, but that will change soon. https://love2d.org/forums/viewtopic.php ... 79#p234179
User avatar
ivan
Party member
Posts: 1911
Joined: Fri Mar 07, 2008 1:39 pm
Contact:

Re: Mobile game considerations?

Post by ivan »

Kemair wrote: Wed Jul 29, 2020 1:25 am My control scheme exclusively consists of pressing buttons on the game's UI, so I'm not too worried about getting the controls to work on the phones.
Touchscreen input is probably the biggest difference between desktop and mobile gaming.
Your controls may work, but that's not enough the question should be "is the game fun to play on a tiny touchscreen".
That's why it's good to look into gestures and multitouch input.
As for dealing with hackers and cheating, I doubt that will be an issue unless your game is already very popular.
Kemair
Prole
Posts: 2
Joined: Wed Jul 29, 2020 12:27 am

Re: Mobile game considerations?

Post by Kemair »

Thank you everyone for the replies! Currently have a lot going so it took some time to get back to this post.
pgimeno wrote: Wed Jul 29, 2020 11:43 am
Kemair wrote: Wed Jul 29, 2020 1:25 am 2d. Should I be skeptical of Lua's tables and getting creative with them?
Lua has a problem. The garbage collector sucks. The more objects the GC needs to deal with, the slower it gets. For big projects, GC issues manifest themselves as lag spikes.

There are two ways to stress the GC: to have lots of active objects, and to generate lots of garbage. The first means that the fewer tables you use, the better. For example, in case of 2D maps, it's better to flatten your map to 1D, than having 1 table with NROWS sub-tables each with a row.

The second means that you should avoid creating temporary variables that need cleaning up. For example, avoid things like this:

Code: Select all

myFunc{param1 = 3, param2 = 5}
You could rewrite it like this:

Code: Select all

local myTable = {} -- place this where it will be executed only once
...
-- every time you want to call, overwrite the current values:
myTable.param1 = 3
myTable.param2 = 5
myFunc(myTable)
I'm not sure I understand the difference here with the code. Are you saying I should minimize the amount of tables I use by writing over values in a single table instead of creating separate tables? What about nested tables in a single table, is this better?

Can I flag a table for deletion by the GC as such?:

Code: Select all

local myTable = {}

myTable.param1 = 3
myTable.param2 = 5
...

myTable = nil
pgimeno wrote: Wed Jul 29, 2020 11:43 am Avoid creating functions on the fly; in most cases you don't need them to work as closures, or you can make non-closure versions. Keep them until they are really needed. For example, this is bad:

Code: Select all

local function newObj()
  local obj = {x = 0}
  function obj:incX()
     obj.x = obj.x + 1
  end
  return obj
end
Instead, create the function outside the other function, making use of the `self` parameter, and add a reference to it in the object:

Code: Select all

local function obj_incX(self)
  self.x = self.x + 1
end

local function newObj()
  local obj = {x = 0, incX = obj_incX}
  return obj
end
I intuitively understand what passing 'self' to a function does. Can you explain what it does on the code and performance level? Is it just passing values by reference to the function so it can access the variables? Does this pass local variables as well?
zorg wrote: Wed Jul 29, 2020 12:57 pm I'll keep my opinions on monetized mobile software to myself, so i'll just add a few relevant things instead:
Thank you for your response zorg, I don't have any questions. In terms of monetization I'm looking to keep things as ethical as possible, avoiding pay to win, and keeping paid advantages mostly outside my core game loop. To be able to continue making fun games I do need some amount back in profit, but fun is my main objective here!
ivan wrote: Fri Jul 31, 2020 6:29 am
Kemair wrote: Wed Jul 29, 2020 1:25 am My control scheme exclusively consists of pressing buttons on the game's UI, so I'm not too worried about getting the controls to work on the phones.
Touchscreen input is probably the biggest difference between desktop and mobile gaming.
Your controls may work, but that's not enough the question should be "is the game fun to play on a tiny touchscreen".
That's why it's good to look into gestures and multitouch input.
As for dealing with hackers and cheating, I doubt that will be an issue unless your game is already very popular.
I'm more worried about building things (like art assets), and finding out later that they are completely unusable and having to have them redone. The genre I have in mind has a low reliance on inputs from the player, so tweaking them doesn't radically change other parts of the code or design (generally). I'm also fully ready to tweak things for polish (and will probably add some gestures as this could be a good idea!), just really looking for general red flags that a noobie has no idea they are walking into.

Thanks again everyone!
User avatar
pgimeno
Party member
Posts: 3550
Joined: Sun Oct 18, 2015 2:58 pm

Re: Mobile game considerations?

Post by pgimeno »

Kemair wrote: Mon Aug 24, 2020 1:46 pm
pgimeno wrote: Wed Jul 29, 2020 11:43 am The second means that you should avoid creating temporary variables that need cleaning up. For example, avoid things like this:

Code: Select all

myFunc{param1 = 3, param2 = 5}
You could rewrite it like this:

Code: Select all

local myTable = {} -- place this where it will be executed only once
...
-- every time you want to call, overwrite the current values:
myTable.param1 = 3
myTable.param2 = 5
myFunc(myTable)
I'm not sure I understand the difference here with the code. Are you saying I should minimize the amount of tables I use by writing over values in a single table instead of creating separate tables? What about nested tables in a single table, is this better?
When you can afford to do that, it's better. This is not always the case.

Every time you write a table constructor { ... }, a new object needs to be allocated. If this object is temporary, like for passing arguments to a function, it's an object that needs to be created and destroyed for no good. Best to avoid creating interfaces that rely on parameters that come in tables. That is, try to avoid creating interfaces like that of love.window.setMode, for example, although in this specific case it's harmless because it runs very few times per program (in most cases 0 to 1 times). And if you can't avoid it, try to reuse a table as I indicated.

Consider also that it's almost always faster to clear a table used as an array, than to rewrite the variable with a new fresh table.

Kemair wrote: Mon Aug 24, 2020 1:46 pm Can I flag a table for deletion by the GC as such?:

Code: Select all

local myTable = {}

myTable.param1 = 3
myTable.param2 = 5
...

myTable = nil
Yes. And that gives work to the GC, which is what you need to avoid if possible.

Kemair wrote: Mon Aug 24, 2020 1:46 pm I intuitively understand what passing 'self' to a function does. Can you explain what it does on the code and performance level? Is it just passing values by reference to the function so it can access the variables? Does this pass local variables as well?
OK, not sure if you understand colon syntax. If not, I give a quick intro here: https://love2d.org/forums/viewtopic.php ... 94#p223194 or here: https://love2d.org/forums/viewtopic.php ... 70#p227470

So, this code:

Code: Select all

local function newObj()
  local obj = {x = 0}
  function obj:incX()
     obj.x = obj.x + 1
  end
  return obj
end
is exactly equivalent to this:

Code: Select all

local function newObj()
  local obj = {x = 0}
  obj.incX = function (self)
    obj.x = obj.x + 1
  end
  return obj
end
But in this last form, it's clearer that the function can be extracted out of newObj if we use the parameter 'self' instead of the upvalue 'obj' to reference the object, and use colon syntax when calling the method.

Colon syntax means that these two function calls are equivalent:

Code: Select all

obj:incX()
obj.incX(obj)
So, if you call object:method(params) you're in fact passing the object as the first parameter to the method. That's how OOP is done in about every language that supports it, to my knowledge.

You could almost say that tables are passed by reference, yes. It's not exactly how passing by reference works in languages that support that, though. It's more like passing by value a pointer to the table. If you alter the pointer inside the function, for example, to point to another table, the caller does not get a modified value (in real passing by reference it would). But if you alter the object pointed to, every variable pointing to it will see the change.

Hope this clarifies it:

Code: Select all

local A = {a = 1}
local B = {b = 1}
local C = A

local function f1(param)
  param = B -- this does not change anything in the caller; a real pass-by-reference would
end

local function f2(param)
  param.a = 5 -- this alters the table passed to the function
end

print(A) -- prints some value X
print(B) -- prints some value Y
f1(A)
print(A) -- prints the value X, NOT the value Y
f2(A)
print(C.a) -- prints 5
Post Reply

Who is online

Users browsing this forum: No registered users and 199 guests