Archive

Monthly Archives: January 2012

Yesterday Alexander Orlov mentioned interesting mind exercise: using mouse by left hand (if you use it by right one on regular basis). This trick stimulates the right hemisphere to force our mind to generate even more crazy ideas. After first day of such left-mouse clicking I created simple but fun html5 down counter in the address bar of the browser (isn’t that fun?). I tested it in FF, Chrome, Opera and Safari. It doesn’t work in IE (means html5 is still dangerous territory or IE must die, underline your own).

Advertisements

From time to time we need to translate some application from one platform/language to another. For example, we need to implement the same mobile/social game for web/flash, iOS and Android. Of course, we can use some multi-platform framework like Corona to build such system, but it’s not so power like native software development tools.

The idea is to design and implement the core (model) of the game in some universal module in Lua programming language. The model may be pretty complicated for the games like chess or poker. I implemented the game ‘Guess The Number’ in Lua as an example. Then I separated the model:

GuesGame = {}GuesGame.WIN = 1GuesGame.LOSE = 2GuesGame.GREATER = 3GuesGame.LESS = 4GuesGame.MIN = 1GuesGame.MAX = 10GuesGame.MAX_TRY = 3function GuesGame:new()        return setmetatable({                _counter = GuesGame.MAX_TRY        }, {                __index = GuesGame        })endfunction GuesGame:start()        self._x = math.random(GuesGame.MIN, GuesGame.MAX)        self._counter = 0endfunction GuesGame:play(a)        if self._counter >= GuesGame.MAX_TRY then                return GuesGame.LOSE        end        self._counter = self._counter + 1        if a == self._x then                return GuesGame.WIN        else                if self._counter >= GuesGame.MAX_TRY then                        return GuesGame.LOSE                elseif self._x > a then                        return GuesGame.GREATER                else                        return GuesGame.LESS                end        endend

As you can see, there is just classic ‘guess the number’ game. The program chooses integer number from 1 to 10 randomly. And the player is trying to guess it in 3 tries.

Next steps were implementation of the game as console applications in pure lua, Objective-C and Java. Lua engine is built as C library, so, there are not problems with Objective-C. In case of Java I used LuaJ. Keep in mind, I used exactly the same lua code of the game model for all implementations. Generally, it was not only that lua code. I need to add some support code for initialization and interface with UI side implemented in native language specified for the appropriate case.

E:ProjectsGuesGamepure_Lua>lua GuesGame.luaq - quit, s - start new game, 1-10 - guesTry to gues a number between 1 and 10?5Less3Win! :-)q

After that I implemented iOS version as iPhone application in the same way. There were no problems at all.

Ios_lua_gues_the_numver_game

To do flash (action script) game I used lua via alchemy. It costs me some performance. Alchemy is going slow at line of calling it from action script side because of huge serialization. So, if you are going to touch you game model often, then you better avoid such scenario and port the model to action script.

Flash_alchemy_lua_gues_the_number_game

We can’t use LuaJava on Android as for pure Java because of differences in JVM. So, I used Android NDK to compile lua engine as C module for Android game.

Android_ndk_lua_gues_the_number_game

In game development performance is very important factor, especially in case of hi-load on-line multi player games in social networks. As we know one of useful tricks is to hard code as much as possible to avoid huge reading or initialization.

In the other hand, it’s hard to support such hard-coded solution (they even call it anti-pattern). For example, we have list of items in the game. It should be the same on servers side and on client side. If list is pretty long then it’s easy to make a fatal mistake, so, lists would be different. Better approach is to hold all the data in single place handy to modify/support and automation system to synchronize the data with all other places in the source code. There are a lot of benefits. As it’s single place then it’s easy to support and avoid difference mistakes. As it automated then we don’t need developer to spend his time to update it.

I created such system. I called it transistor. There are 3 parts:

  • The python script transistor.py
  • Data composed into CSV
  • Source code with hard coded section and template to fill it

We can use one or more CSV tables. One table may have reference(s) as index(es) to another. CSV content should be available via HTTP or locally. I use Google Docs Spreadsheets for that. First line of each CSV table should have case-sensitive fields (columns) names. Other rows have the data. Later the script will parse those data into the list of dictionaries.

My first try was using of pure python string formatting as template. It means that the template and its logic were in python code on the script side. There were bad design and huge ugly implementation. Well, if you have a lot of code then it is almost always bad architecture. There should be very small amount of code. So, I declined that prototype. The second (and the best) design approach was to make that script universal and move all specific template data and logic to the template situated in the same source code file (in comments).

/*// gunTypes begin{% set gunTypes = tables.gunTypes -%}{%- for g in gunTypes -%}{%- if g.shoot_width -%}{%- if loop.index0 > 0 %},{% endif -%}new GunType({{g.id}}, new Shape({{g.base_width}}, {{g.base_height}}, new byte[]{                        {{g.base_shape|replace('n', 'n                                                        ')}}        }), new Shape({{g.shoot_width}}, {{g.shoot_height}}, new byte[]{                        {{g.shoot_shape|replace('n', 'n                                                        ')}}        })){%- endif %}{%- endfor %}// gunTypes template end */        // ... here would be generated content ...// gunTypes end

Hard-coded section in the source code file has header, footer and template delimiter. There are the template between header and template delimiter and the generated content between delimiter and the footer. Usage example:

python transistor.py --file=GunTypesDict.cs --section=gunTypes                --table=gunTypes                --url="https://docs.google.com/spreadsheet/pub?...&output=csv"
or more complicated with 2 tables:
python transistor.py --file=LocationsDict.cs --section=locations                --table=fields --table=locations                --url="https://docs.google.com/spreadsheet/pub?...&output=csv"                --url="https://docs.google.com/spreadsheet/pub?...&output=csv"
After such data publishing we have the same source code like:
/*// gunTypes begin{% set gunTypes = tables.gunTypes -%}{%- for g in gunTypes -%}{%- if g.shoot_width -%}{%- if loop.index0 > 0 %},{% endif -%}new GunType({{g.id}}, new Shape({{g.base_width}}, {{g.base_height}}, new byte[]{                        {{g.base_shape|replace('n', 'n                                                        ')}}        }), new Shape({{g.shoot_width}}, {{g.shoot_height}}, new byte[]{                        {{g.shoot_shape|replace('n', 'n                                                        ')}}        })){%- endif %}{%- endfor %}// gunTypes template end */new GunType(0, new Shape(1, 2, new byte[]{                        1,1        }), new Shape(1, 1, new byte[]{                        5        })),new GunType(1, new Shape(2, 1, new byte[]{                        1,1        }), new Shape(2, 2, new byte[]{                        0,5,                        5,0        }))// gunTypes end
At line of development process automation, I designed and built special script and methodology for easy and fast generation of hard coded data definition in the source code by provided relative data composed separately in the spreadsheets. The script loads csv data and render it into special section in existing source code file by the template provided in the same file.
The script is implemented in python, so, I need some cool template engine. I was looking at Mako and Jinja2.
After brief research I was try Mako. But it was very ugly at line of source code generation. Just look at this example:

# coma separator example

print Template("""<% c = 0 %>% for i in list:<%    coma = ''    if c < len(list) - 1: coma = ','    c += 1%>${i}${coma}% endfor""").render(list=(0,1,2))

So, I decided to use Jinja2. It’s much better for source code generation and looks like more power template engine as a whole. Here is several cool features I’m able to implement with jinja2:

  • separator
  • multiline indentation
  • correct new lines

Template:

{% set gunTypes = tables.gunTypes -%}{%- for g in gunTypes -%}{%- if g.shoot_width -%}{%- if loop.index0 > 0 %},{% endif -%}new GunType(                   {{g.id}},                   new Shape({{g.base_width}}, {{g.base_height}}, new <int>[                           {{g.base_shape|replace('n', 'n                               ')}}                   ]),                   new Shape({{g.shoot_width}}, {{g.shoot_height}}, new <int>[                           {{g.shoot_shape|replace('n', 'n                               ')}}                   ])           ){%- endif %}{%- endfor %}

Result:

new GunType(                   0,                   new Shape(1, 2, new <int>[                           1,1                   ]),                   new Shape(1, 1, new <int>[                           5                   ])           ),new GunType(                   1,                   new Shape(2, 1, new <int>[                           1,1                   ]),                   new Shape(2, 2, new <int>[                           0,5,                           5,0                   ])           )

 

Sometimes I use python or ruby script as Pre/Post-Build step configured in settings of a project in IDE. There my be situation when such extra steps are not needed. We can provide one more configuration without those Pre/Post-Build steps but it’s much faster just to comment the commands in some way, so, to enable them later.

In MS Visual Studio I added rem as old-school .bat files comment

  • rem command arg1 arg2

and true in case of Flash Develop IDE

  • true command arg1 arg2

It looks like VS just ignore or skip the commands like first one. Unfortunately, such trick doesn’t work in case of FalshDevelop. So, I use more universal method. The commend in second example would be called by IDE. It does nothing and return correct exit code, so IDE continues regular build scenario.