Monkey tips list!

Monkey Forums/Monkey Programming/Monkey tips list!

Grey Alien(Posted 2013) [#1]
Hi all, as I've been using Monkey and discovering things (and doing research on the forums), I've built up a list of all the tips 'n' tricks that I've found useful. This list assumes a certain basic understanding of monkey and OOP and mostly covers more advanced topics.

This isn't an exhaustive list and I'm sure it'll keep on growing, but it's what I've needed so far. Some of the text/examples are from other people who posted in the forum.

[EDIT] I removed the code formatting as it was making long sentences hard to read.

/////////////////////////
Folder Structure:
- yourgame/
- yourgame/myGameApp.monkey <--- file name is important!
- yourgame/character.monkey
- yourgame/whatnot.monkey
- yourgame/myGameApp.data/ <-- assets go here
- yourgame/myGameApp.data/images/dwarf.png
- yourgame/myGameApp.data/levels/stuff/ <-- sub directories can be done this way

/////////////////////////
Sound:

See Module mojo.audio for what formats to use on different OSes and what commands don't work.
In HTML5 IE supprts mp3 but Firefox doesn't. Firefox supports Ogg but IE doesn't.

/////////////////////////
Device Resolution and scaling:

'Device width and height
Global DEVICE_WIDTH%
Global DEVICE_HEIGHT%

' Screen width and height
Global SCREEN_WIDTH# = 480
Global SCREEN_HEIGHT# = 320

' Used for Virtual Res
Global SCREENX_RATIO# = 1
Global SCREENY_RATIO# = 1

...

Method OnCreate:Int()
' Store the device width and height
DEVICE_WIDTH = DeviceWidth()
DEVICE_HEIGHT = DeviceHeight()

SCREENX_RATIO = DEVICE_WIDTH/SCREEN_WIDTH
SCREENY_RATIO = DEVICE_HEIGHT/SCREEN_HEIGHT

...

Method OnRender:Int()
PushMatrix
Scale SCREENX_RATIO, SCREENY_RATIO
' Draw stuff here
PopMatrix

/////////////////////////
Touchscreen:

min touch area = 48x48 for basic iOS screen, double for retina display

/////////////////////////
Lists:

class wizard
end class

local mylist:List<wizard>=new List<wizard>

Or

Global list:List<Object>=New List<Object> (then typecast object obtained from list)

/////////////////////////
Function Pointers:

http://www.blitzbasic.com/Community/posts.php?topic=94283

Basically, not possible. Use a CallBack instead like this:

Class ICallBack Abstract
Method Call:Void() Abstract
End Class

/////////////////////////
Arguments by reference:

Not possible, Wrap them in a class instead.

OR

Use BoxInt, BoxBool, BoxString, and BoxFloat to put the primary datatypes into an object. Then use UnboxInt, UnboxBool, UnboxString, and UnboxFloat, respectively, to change them back to the primary datatypes. There's also ArrayBoxer<DataType>.Box and ArrayBoxer<DataType>.Unbox for passing arrays.

OR

Cheat and use an array. I would assume it's a little more lightweight (depending on target).

Function SomeFunction(arg:Float[])
arg[0] = 10
End

Local arr:Float[] = New Float[1]
SomeFunction(arr)
Print arr[0]

/////////////////////////
Asteroids source:

http://www.blitzbasic.com/Community/posts.php?topic=94239

/////////////////////////
Singleton Class:

Class TCharacterHandler
Function update:Void()
Print "WORKS"
End
End

TCharacterHandler.update()

/////////////////////////
REM
#rem .......... #end

/////////////////////////
Print variable intialisation status:

Print Int(player=Null)

/////////////////////////
Function Transform( ix#, iy#, jx#, jy#, tx#, ty# )

ix = scale * rotation cos(a)
iy = rotation -sin(a) (* scale)
jx = rotation sin(a) (* scale)
jy = scale * rotation cos(a)
tx = translate x
ty = translate y

Why is this useful? It allows you to do a scale and translate at once (so you don't have to to a costly x/Scale, y/Scale after your Scale command to get "nice" placement). I find it useful when displaying text with AngelFont.

So to combine a scale and normal x,y placement (without rotation):

PushMatrix()
Transform(scalex,0,0,scaley,placex,placey)
DrawImage img,1,1
..etc more drawing commands..
PopMatrix()

Remember to keep scale = 1.0 if you only want to do rotation.

If you're into performance, you could try the SetMatrix commands if you wish to overwrite any previous operations.

The values are the same for Transform, but it removes multiplying the current matrix. Make sure to use PushMatrix and PopMatrix before and after.

Function SetMatrix( ix#, iy#, jx#, jy#, tx#, ty# )

/////////////////////////
Arrays:

Here's a single dimensional Array:

Function Main()
Local Tiles:Int[]
Tiles = New Int[10]
Print Tiles.Length ' prints "10"
End

That declares Tiles to be an array of Ints and then initialises it with an array of length ten. You could also declare it directly:

Local Tiles:Int[] = [0,0,0,0,0,0,0,0,0,0]

Now, multidimensional arrays in Monkey follow the "Array of Arrays" model so, if you want a two-dimensional array that contains Ints, then you are going to be declaring an Array of Arrays of Ints.

Function Main()
Local Tiles:Int[][]
Tiles = [New Int[2],New Int[3],New Int[4]]
Tiles[2][3] = 99
Print Tiles.Length '3
Print Tiles[0].Length '2
Print Tiles[1].Length '3
Print Tiles[2].Length '4
Print Tiles[2][3] '99
End Function

Note that the arrays can be "ragged", i.e. the rows do not have to be the same length.

Note: assigning one array to another doesn't make a copy of it, they both point to the same one. Resizing or slicing an array does make a copy of it.

Slicing an array:

myArray = myArray[0 .. 1] 'will return an array of length 0


/////////////////////////
Timing:

http://www.monkeycoder.co.nz/Community/posts.php?topic=1436

/////////////////////////
String Slicing:

Left(i):
str[..i]


Right(i):
str[i..]


Mid(i,j):
str[i..j]

It's a bit confusing because you have to supply two consectutive numbers to get a single char string back. Think of it like everything is returned from the first value up to, but excluding, the second value.

Examples:
Local test:String = "TEST"
Print test[0 .. test.Length()] 'Returns TEST
Print test[0 .. test.Length() -1] 'Returns TES
Print test[0 .. 0] 'Returns null
Print test[0 .. 1] 'Returns T
Print test[2 .. 3] 'Returns S
Print test[0] 'Returns 84 which is the ASCII Char code for S. This is *not* a string.

/////////////////////////
Array Slicing:
* Use Resize when you want to change the size of an array
* Use Slices when you want to get elements of an array

Both of these operations return a new array and don't effect the one your are performing the operation on.

/////////////////////////
StringMap:

Faster...
For Local img:=EachIn diddyGame.images.Values()
Next

Fastest...

For Local it:=EachIn diddyGame.images
Local str:=it.Key
Local img:=it.Value
Next

/////////////////////////
Platform Target Advice from Skidracer:

If I was writing a game with Monkey I would first decide if I was targeting the desktop, the browser, or the handheld.

For the desktop I would use XNA for PC and GLFW for Mac/Linux.

For the browser I would use Flash.

For handhelds I would target iOS, and only once I'd made a shed load of money would I consider an android port.

Just because monkey allows you to target all the platforms from single code base doesn't make it a good idea.

Just because HTML5 is the next big thing doesn't make it a viable gaming platform now or any time soon.

/////////////////////////
Flash:

preloader:
http://www.monkeycoder.co.nz/Community/posts.php?topic=2406#23789

Put this at start of code to speed up Flash:
#MOJO_IMAGE_FILTERING_ENABLED=False

To change window size:
Edit the MonkeyGame.html in your .build folder.
Perhaps you have to edit your MonkeyGame.as too.
[SWF(width="480",height="800")]

For looping mp3s with no gap use mp3loopui.exe

/////////////////////////
GLFW exe issues

List of commercial game issues:
http://www.monkeycoder.co.nz/Community/posts.php?topic=4790

Toggle Full Screen:
http://www.monkeycoder.co.nz/Community/posts.php?topic=2292
http://www.monkeycoder.co.nz/Community/posts.php?topic=4418

Name and icons:
http://www.monkeycoder.co.nz/Community/posts.php?topic=3085

Window title:
#GLFW_WINDOW_TITLE="Titan Attacks"

Alt+tab enable (works on Windows 7 already but this may be needed for other OSes?):
Add this to Monkey/targets/glfw/main.cpp - main method:
glfwEnable( GLFW_SYSTEM_KEYS );

/////////////////////////
iOS:

IAP:
http://www.monkeycoder.co.nz/Community/posts.php?topic=1219
http://www.monkeycoder.co.nz/Community/post.php?topic=1219&post=17156
http://www.monkeycoder.co.nz/Community/post.php?topic=1219&post=25143

iPhone 5 resolution:
- I added a 640x1136 launch image on the Summary page in xcode and the game detected the larger resolution. Otherwise DeviceHeight() only returns 960 (iPhone 4 height).

Orientation change:
DeviceWidth() and DeviceHeight() change immediately when device is turned around.

Quit button:
Do not add one to the game otherwise Apple will reject it.

Optimising pngs:
http://www.monkeycoder.co.nz/Community/posts.php?topic=2464

Avoid drawing too much alpha on slow devices (e.g 3G, 3GS, iPad1)

Mark has added Game Center and AdMob functionality to Monkey.

Set icons in XCode not Monkey. App Name too:
http://www.monkeycoder.co.nz/Community/post.php?topic=2280&post=22260

Retina Display discussion (other threads exist too):
http://www.monkeycoder.co.nz/Community/posts.php?topic=5030

Chartboost:
http://www.monkeycoder.co.nz/Community/post.php?topic=4385&post=49973

/////////////////////////
Android:

"I can confirm that you definitely do not want to be creating and destroying objects on a per-frame basis on Android (or iOS for that matter.) Object pooling is a must for dynamic objects."

Locking screen on Android:
http://www.blitzbasic.com/Community/posts.php?topic=94122


Ken(Posted 2013) [#2]
Huzzah Grey Alien,

Now *that*'s a useful post!

Thanks!

-Ken


Amon(Posted 2013) [#3]
Nice one!


semar(Posted 2013) [#4]
Extremely useful, many thanks Grey Alien :)


ordigdug(Posted 2013) [#5]
Thanks, very helpful.


Why0Why(Posted 2013) [#6]
Could be a great post for everyone to add their tips and have a bunch of great info in one location in a nice, cohesive format. A monkey cheat sheet!


silentshark(Posted 2013) [#7]
I like it. Very handy! Thank you for sharing..


Chroma(Posted 2013) [#8]
Not sure PushMatrix and PopMatrix are you needed anymore in OnRender. I stopped using them awhile back and everything draws, rotates, scales just fine. Can anyone second that?

Something else of note is the DrawImage command and how you can put the rotation and scale in it.

IE.

DrawImage myimage, x, y, 0, rotation, scale_x, scale_y


therevills(Posted 2013) [#9]
The Push/Pop Matrix Grey has shown here is a quick Virtual Resolution solution...

@Jake:
Global list:List<Object>=New List<Object> (then typecast object obtained from list)

Kinds of defeats the purpose of generics, you'll want to use Interfaces or Super Objects instead of pure Object.


David Casual Box(Posted 2013) [#10]
Amazing. Thanks Jake.


Skn3(Posted 2013) [#11]
Here are a few meaty ones to add to your list.

(v70+) How to inject your own "native" code into an existing module that doesn't support a particular target.
I'll use tcpstream as an example.


If you place this in your code, you can then implement a html5 version of the tcpstream without having to modify any of the original modules.


How to iterate over a list without creating much garbage.



How to have target specific data:
1) in your data folder create a folder called 'html5'.
2) in your data folder create a folder called 'glfw'.
3) add a file myfile.txt to each of these folders.
4) add the following to your code:



Midimaster(Posted 2013) [#12]
Does this mean, that the file from the other folder are really not included in the finale file?

Is there a chance to use "selfmade" compiler variables like "ISDEMO"

Function LoadSound:Sound(path:String)
	#IF ISDEMO = TRUE
		Return NULL
	#ElseIf ISDEMO = FALSE
		Return LoadSound("sounds/" + path)
	#End	
End


A combination of this both would make my free version APKs smaller without thinking about it on every build....


Skn3(Posted 2013) [#13]
Midimaster yup, it will only import the files that match the paths specified. You can use self written compiler variables yup, how would you use them to reduce the size though?


Midimaster(Posted 2013) [#14]
The difference between my free and payed app is "with sound" or "without". It is the same source code and at the moment I uses the same data-folder. so both Apks are 1.8Mb, but without sounds the free one would be 0.4Mb.

In the manual I cannot find anything about self defined preprocessor directives... Where can I find informations?


Skn3(Posted 2013) [#15]
Ah I see, well you could definitely set a SOUND_FILES per custom preprocess var then.

They are relatively new I think, but you simply do...
#blah = 123


You can then access this var as per any other preprocess var.


Grey Alien(Posted 2013) [#16]
Glad people have found it useful!

@Skn3: Thanks!

@therevills: Unfortunately I don't understand what you mean. I think my OOP knowledge isn't so good.


arawkins(Posted 2013) [#17]
This is awesome, thanks! I wish this was here when I started working in Monkey.


Soap(Posted 2014) [#18]
This thread should be moved to http://www.monkeycoder.co.nz/Community/topics.php?forum=228 and stickied there.