tag:blogger.com,1999:blog-26224899995938419852024-03-19T05:20:47.175-07:00Programming HappensPeter Belanyihttp://www.blogger.com/profile/12575267258139359711noreply@blogger.comBlogger22125tag:blogger.com,1999:blog-2622489999593841985.post-84187245803397192492016-03-26T09:56:00.001-07:002016-03-26T09:56:29.364-07:003D!<div style="text-align: justify;">
Recently I've started to learn how to use the Unity engine. It has good documentation and accessible tutorials, so the learning curve is not steep. It has a basic set of standard assets, importing new assets is easy, and C# is a pleasant language for scripting. I think the main feature over developing my own engine is that the editor functions as a level editor too, so it's easy to start producing game content.</div>
<br />
<div style="text-align: justify;">
I wanted to try my hand at 3d games, so I created a simple demo game to see how far I can get, and decided to document it. It is one level of a puzzle game, inspired by The Talos Principle (which is an awesome game btw).</div>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhexTOdreySxY0lhgxiiF4MRhH7RJq9Jx1tpkKESoegF8eHHm6I35vq1lRXBdTsj1EPiJGzx6kgT9fbVQs3VHnx_QYYEsGL8_DJk4rmibPDY6CYRlb5SmdAizUnzISU6NDuWiNQB7RcEgo/s1600/demo1.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="225" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhexTOdreySxY0lhgxiiF4MRhH7RJq9Jx1tpkKESoegF8eHHm6I35vq1lRXBdTsj1EPiJGzx6kgT9fbVQs3VHnx_QYYEsGL8_DJk4rmibPDY6CYRlb5SmdAizUnzISU6NDuWiNQB7RcEgo/s400/demo1.png" width="400" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;"><i>Sketch of the beginning area with actual models and some placeholders</i></td></tr>
</tbody></table>
<div style="text-align: justify;">
I wrote my own scripts for FPS player control, mostly for learning experience, since the standard assets include such scripts. I also implemented the gameplay with scripts for controling doors and buttons, picking up (companion) cubes, and teleporting the player. Due to intellisense and the intuitive API, scripting is quite easy.</div>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhHPJTM_4EcD8vAp7Bh10v4Wpcvw9KoGIFXpbafRtHEjRv8pj4ktgqkgFuDSjZxMIb1lFEmtJJslK76Eq_cPFnaUnTUjh3le6_awt5PtX4YhYWtpHCrJeKFibkPatHbDHQ-VzB5yYrcbYw/s1600/demo2.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="225" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhHPJTM_4EcD8vAp7Bh10v4Wpcvw9KoGIFXpbafRtHEjRv8pj4ktgqkgFuDSjZxMIb1lFEmtJJslK76Eq_cPFnaUnTUjh3le6_awt5PtX4YhYWtpHCrJeKFibkPatHbDHQ-VzB5yYrcbYw/s400/demo2.png" width="400" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;"><i>Added my first trees, grass, and tried to paint the terrain</i></td></tr>
</tbody></table>
<div style="text-align: justify;">
There are some nice tools built into the editor that help creating basic content for certain kinds of games. The terrain editor can be used to sculpt and paint the terrain. Grass can be created as billboards from texture or from 3d models, and painted onto the terrain. The tree editor can be used to produce giant broccolis from mars, and also trees. It seems to use L-systems, and is an easy to use but versatile tool.</div>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjOehH9m13i4wPV6Kot2eIK4yV5E48h-u-DmMWwde24fnUMjkK8r7yKvy31hWHMRTSqoYrPC_qn68TNsCwZAIN1tOY4k3vEAgoyKWNCsFXlIujyflG2xcJY86yUCJRkdREItV5ObF9qmbU/s1600/demo3.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="225" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjOehH9m13i4wPV6Kot2eIK4yV5E48h-u-DmMWwde24fnUMjkK8r7yKvy31hWHMRTSqoYrPC_qn68TNsCwZAIN1tOY4k3vEAgoyKWNCsFXlIujyflG2xcJY86yUCJRkdREItV5ObF9qmbU/s400/demo3.png" width="400" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;"><i>Fleshing out more parts of the level</i></td></tr>
</tbody></table>
<div style="text-align: justify;">
I used Krita for drawing textures (it's a nice open source painting program) and Blender for modeling 3d assets. Learning blender is somewhat challenging. Due to the complex interface the learning curve is quite steep. I couldn't find very good tutorials either. The worst part is that most off the official tutorials are not free, which is pretty stupid IMO... how do they expect Blender to get popular if they restrict access to the learning material? Well, whatever.</div>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh_NejApcNiH-25FbVOG_m_i9EQ1Q7MaBayFNxz2MRNEBVl-unDACVL8Aj6y6BYU543gVgPJ8l3z0JM5hgb5rcKkIU4FTykX_AiJFBHTGd0Pit3ZQYt55fHdknxjHogJpYwr63EJA8ju70/s1600/demo5.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="225" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh_NejApcNiH-25FbVOG_m_i9EQ1Q7MaBayFNxz2MRNEBVl-unDACVL8Aj6y6BYU543gVgPJ8l3z0JM5hgb5rcKkIU4FTykX_AiJFBHTGd0Pit3ZQYt55fHdknxjHogJpYwr63EJA8ju70/s400/demo5.png" width="400" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;"><i>Placeholders replaced with final models</i></td></tr>
</tbody></table>
<div style="text-align: justify;">
It's not all sunshine though, I run into some difficulties. For example I spent quite a while trying to perfect picking up objects, and I had to settle with a mediocre solution (with object having physics disabled while picked up). I just couldn't find a combination of properties that didn't result in some physical weirdness.</div>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg0zLSzngD8vbUoDYBzzqgxyG3rwf8c57datdcsWlbB0paiw11_JzmUYS0LiVuCLxzguzclmTgutjrS_BUcpcjVlk8Up4SgIAKXD3sO6LDw7eldyVOjoC966NpUdEd0Sz_0wlWQ-8fQeYc/s1600/demo6.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="225" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg0zLSzngD8vbUoDYBzzqgxyG3rwf8c57datdcsWlbB0paiw11_JzmUYS0LiVuCLxzguzclmTgutjrS_BUcpcjVlk8Up4SgIAKXD3sO6LDw7eldyVOjoC966NpUdEd0Sz_0wlWQ-8fQeYc/s400/demo6.png" width="400" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;"><i>The whole level from birds eye view</i></td></tr>
</tbody></table>
<div style="text-align: justify;">
It's quite interesting to work on other aspects of game development (modeling, texturing, level design) than just programming. There are different kinds of problems popping up... how do I create interesting puzzles? How do I plan a realistic map? How to paint tileable textures? How to carve a cake out of a cylinder?</div>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjLHmcfIwGDOsbjBWhOBLRLCBG7Lbh6M6_HUcwCRHDP_7JUWKXxIlKO0j-Hz1K91DH9P7SBce3FnssuRcjZQ6nIE242EIBhriOeMnKMGEzSOiZoawwVb3mT18WWSaMo1w8FopV5pq7cz64/s1600/demo7.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="225" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjLHmcfIwGDOsbjBWhOBLRLCBG7Lbh6M6_HUcwCRHDP_7JUWKXxIlKO0j-Hz1K91DH9P7SBce3FnssuRcjZQ6nIE242EIBhriOeMnKMGEzSOiZoawwVb3mT18WWSaMo1w8FopV5pq7cz64/s400/demo7.png" width="400" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;"><i>End of the level - it's not a lie</i></td></tr>
</tbody></table>
<div style="text-align: justify;">
It's pretty cool for indies to have a full dev toolchain for free. Blender and Krita are open source, Unity is (mostly) free, and for coding MonoDevelop is open source, and Visual Studio is free. If only they all run on Linux...</div>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjqb-DjHMKYBAUqj27TKkcnEbmNwaEq82EeSdQunRcEBP0VW_3t3hYhK9s5I81pgrocuIrA_4w3KXiiYes0kCVfWYx7O9pk9Zpn7-A0C0jqwXzO65K4-4RBW84MMOV13agdytDaJaUAW84/s1600/blender.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="225" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjqb-DjHMKYBAUqj27TKkcnEbmNwaEq82EeSdQunRcEBP0VW_3t3hYhK9s5I81pgrocuIrA_4w3KXiiYes0kCVfWYx7O9pk9Zpn7-A0C0jqwXzO65K4-4RBW84MMOV13agdytDaJaUAW84/s400/blender.png" width="400" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;"><i>Texturing my model in blender</i></td></tr>
</tbody></table>
<div style="text-align: justify;">
I've also recorded a playthrough to have something better to show off:</div>
<div style="text-align: center;">
<br /></div>
<div style="text-align: center;">
<iframe allowfullscreen="" frameborder="0" height="315" src="https://www.youtube.com/embed/xD4xKXsS6l4" width="560"></iframe><br /></div>
<br />
<div style="text-align: justify;">
It's not very spectacular, but I'm quite proud of it, since this is my first real 3d game. I always thought working in 3d would be too much work for one developer, but turns out it's manageable. Next I think I'll try to make an actual full game, it would be nice to have another full game developed besides The Silliness of the Lambs. I have many ideas, but must of them are too complex for a single developer. Also, my modeling and other art skills are not too great. Though at least I have time, and I'm having fun.</div>
Peter Belanyihttp://www.blogger.com/profile/12575267258139359711noreply@blogger.com0tag:blogger.com,1999:blog-2622489999593841985.post-80452458663390674472015-08-24T10:21:00.001-07:002015-08-24T10:21:33.364-07:00C++ string formatting, etc.<div style="text-align: justify;">
<br />
The lack of articles recently is because I became a professional game developer. Since January I work as a senior programmer at a major indie developer studio, and for a while I didn't have much energy to work on private projects besides work. The new job also meant moving to yet another country, and it took some time to settle down.<br />
<br />
Although it's fun to code AI for bosses, improve the engine, gameplay, etc. as a fulltime job, after a while I felt like working on my own stuff, and recently started to experiment with an idea I had. I was wondering if a database would be suitable for storing all the data of a game, and to check it, I started to implement an engine with SQLite in it's core. I'm not sure how it will turn out in the end, so far I like it. It's convenient to have access to textures, sound files, configuration values, etc., or writing log messages with simple SQL queries, not having to handle files.<br />
<br />
As a side effect I've also developed the core of a simple and easy to use string formatting solution which uses C++11 features. I searched for good solutions to support formatted logging, but didn't really like any of them, so I wrote my own string formatter classes, and decided to turn them into a full library and release it as open source, since it might be useful for others too. It's available at <a href="https://gitlab.com/almonsin/fmt11" target="_blank">https://gitlab.com/almonsin/fmt11</a><br />
<br />
I plan to continue extending the new engine and try to make an actual game with it.
</div>
Peter Belanyihttp://www.blogger.com/profile/12575267258139359711noreply@blogger.com0tag:blogger.com,1999:blog-2622489999593841985.post-40475812723928854832014-08-22T07:31:00.000-07:002014-08-22T07:31:30.163-07:00Shaded Island<div style="text-align: justify;">
After writing the last article I have continued to perfect my island generator. I reimplemented the Gaussian blur to use separated kernels, which resulted in a huge speedup in the generation step, but rendering was still slow when the terrain resolution was big, so I wanted to improve on it.</div>
<br />
<div style="text-align: justify;">
I spent a long time on looking for the best rendering solution. First I checked out <a href="http://www.ogre3d.org/" target="_blank">Ogre</a>, which seemed to be a decent rendering engine. Unfortunately the configuration is very complicated and it's hard to find reliable, current documentation. I couldn't get anything get rendered on Linux with OpenGL after several hours of trying, so in the end I just gave up sadly.</div>
<br />
<div style="text-align: justify;">
Next I tried the <a href="https://github.com/bkaradzic/bgfx" target="_blank">bgfx</a> rendering library, which also looked nice and much simpler than Ogre. This time my problem was that I could not get it to cooperate with SFML, and I did not intend to ditch that library.</div>
<br />
<div style="text-align: justify;">
The next choice was <a href="http://oglplus.org/" target="_blank">OGLplus</a>, a C++ wrapper around OpenGL, looking good at first glance, but a bit complicated and bloated when I tried to use it. So after looking at options for weeks I kinda gave up. I considered using the vertex buffer and shader facilities provided by OpenGL, but was too lazy for it.</div>
<br />
<div style="text-align: justify;">
Then one day I accidentally discovered that the 2nd version of SFML, in contrast with the 1st version, has support for shaders. It's easy to load and use them, and the shader language is GLSL. It also supports vertex arrays, but unfortunately only with 2D coordinates for position, while I needed 3D. Luckily the SFML sources are easily readable, so I could figure out what's going on behind the scenes and learn how to use vertex arrays in OpenGL. </div>
<br />
<div style="text-align: justify;">
Switching to vertex arrays had a huge speed improvement, which is what I expected, since now there are no calls to glTexCoord2f and glVertex3f for every single vertex, only one call per frame to glVertexPointer, glNormalPointer, glTexCoordPointer and then glDrawArrays.</div>
<br />
<div style="text-align: justify;">
Using shaders enabled me to change from flat shading to <a href="http://en.wikipedia.org/wiki/Phong_shading" target="_blank">Phong shading</a>. It required calculating the vertex normals (which get interpolated in the shader for every pixel), not just the face normals for the triangles. The result is pretty nice:</div>
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj10-sijjMf4osOkTUsB3GSETEqAeBD4DyB_sS6M8VImON1dq3kHMCBhlUsJ_Ot7TrVhq8mSQ4O5h1AWk9nisbp4EjrpGq9t687rbJJYXRpHj-KmjP0chPAgZITzBYpYEXEkYvki64gOLE/s1600/Screenshot+from+2014-08-10+12:10:03.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj10-sijjMf4osOkTUsB3GSETEqAeBD4DyB_sS6M8VImON1dq3kHMCBhlUsJ_Ot7TrVhq8mSQ4O5h1AWk9nisbp4EjrpGq9t687rbJJYXRpHj-KmjP0chPAgZITzBYpYEXEkYvki64gOLE/s1600/Screenshot+from+2014-08-10+12:10:03.png" height="332" width="400" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Flat shading</td></tr>
</tbody></table>
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhENjfhtTIaQ3KxfrAN6NnPIZvjKedWj8ethBirIFNjrX0XhiXr1Dh9HTp3G6Nx68PmaaFSOVoYPeK0jRAEfVXW_XXhoH6UujF9v9nwCrsfe8fM1oQaVZ-cIVxLmuWrCaNBoFzkfsEL8Gs/s1600/Screenshot+from+2014-08-10+12:09:28.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhENjfhtTIaQ3KxfrAN6NnPIZvjKedWj8ethBirIFNjrX0XhiXr1Dh9HTp3G6Nx68PmaaFSOVoYPeK0jRAEfVXW_XXhoH6UujF9v9nwCrsfe8fM1oQaVZ-cIVxLmuWrCaNBoFzkfsEL8Gs/s1600/Screenshot+from+2014-08-10+12:09:28.png" height="332" width="400" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Phong shading</td></tr>
</tbody></table>
<br />
<div style="text-align: justify;">
Playing with shaders is fun, it opens up a lot of possibilities, for example I can modulate the colour of the terrain based on the height value (= z coordinate), e.g. set the lower parts to sandy colour and the higher parts to grassy green. It still needs tweaking, but the basics are done.</div>
<br />
<div style="text-align: justify;">
Another feature I have is the day night cycle. It was already present in the old renderer, but was very slow. For every frame the colour of every triangle was recalculated, based on the dot product between the sunlight direction and the triangle normal. In the new renderer the light direction is passed in to the shaders, and all the calculation is done on the GPU instead of the CPU.</div>
<br />
<div style="text-align: center;">
<iframe allowfullscreen="" frameborder="0" height="360" src="//www.youtube.com/embed/WRrxgTmfEiQ" width="480"></iframe>
</div>
<br />
<div style="text-align: justify;">
Next I plan to implement vegetation generation to add trees, bushes, etc., and other features needed to make it into a game.</div>
Peter Belanyihttp://www.blogger.com/profile/12575267258139359711noreply@blogger.com0tag:blogger.com,1999:blog-2622489999593841985.post-19974283814846049412014-04-07T10:38:00.000-07:002014-04-07T10:38:41.878-07:00Journey to the Perfect Island<div style="text-align: justify;">
I took a two-day break from work to have a long weekend and some rest, and rest included working on a small project: island generation. My goals were simple, I wanted to make a procedural terrain generator that would create nice looking islands, and a triangle based isometric renderer in OpenGL.</div>
<div style="text-align: justify;">
First I calculated on paper the view transformation matrix to render a 2d heightmap as triangles, and wrote a wireframe renderer to check my calculations.</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgaM8yTfZ1LLskA_ubnVTe6wQaAnYDodsJx99xe7D8SQ_yxNY6IBL3zjCLoL9iytrBgy1BM_07jYfiknZdSTitmfgpB7V9P8RSpRzctJYPa5YxrPuBjKUcq9ATw0MrSJMm_UdcOZU7Z9-o/s1600/1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgaM8yTfZ1LLskA_ubnVTe6wQaAnYDodsJx99xe7D8SQ_yxNY6IBL3zjCLoL9iytrBgy1BM_07jYfiknZdSTitmfgpB7V9P8RSpRzctJYPa5YxrPuBjKUcq9ATw0MrSJMm_UdcOZU7Z9-o/s1600/1.png" height="238" width="320" /></a></div>
<br />
<div style="text-align: justify;">
The view transformation was alright, so I added a noise texture and green colour to the triangles. First I also tried adding Gouraud shading, but it was ugly and the exact geometry couldn't be seen, so I switched to flat shading.</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgdWqWzSKN2_CNq5kq4g8gi0QHExm69Af3a1cwfzCp30X5HMUrJ_riCZw4N1qL_C9RaF4HbVfD9u2ivZdFj7-2HlT05zrHtt2iBZPR04pxMElRlWgrNF2ku6zYsQiQuGQfKffqm2G-s7v4/s1600/2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgdWqWzSKN2_CNq5kq4g8gi0QHExm69Af3a1cwfzCp30X5HMUrJ_riCZw4N1qL_C9RaF4HbVfD9u2ivZdFj7-2HlT05zrHtt2iBZPR04pxMElRlWgrNF2ku6zYsQiQuGQfKffqm2G-s7v4/s1600/2.png" height="240" width="320" /></a></div>
<br />
<div style="text-align: justify;">
So rendering was sufficient, it was time to start generating the terrain. My plan was to generate a fractal heightmap, and then multiply the height values with a scaled 2d Gaussian function to have some land in the middle and quickly reach zero, that is, sea, as getting further away from the centre. After checking out a few methods (e.g. perlin noise, simplex noise, midpoint displacement) I chose the diamond-square method to generate the terrain, because it seemed to result in nice looking terrain quite fast.</div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhDinA_y_OIiP9q_A9Aew6C4D7b0M_asUA0hOp5FrZ3OXF0JtCdGBMyrcSh3A8Pi4dHshuPGk7VmUj8KVvHRqVtm1szgW1DqF5LHtYVO6jgksZGOo7XKay9kHlIwmyxKJwoD_cxqVmIbYI/s1600/3.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhDinA_y_OIiP9q_A9Aew6C4D7b0M_asUA0hOp5FrZ3OXF0JtCdGBMyrcSh3A8Pi4dHshuPGk7VmUj8KVvHRqVtm1szgW1DqF5LHtYVO6jgksZGOo7XKay9kHlIwmyxKJwoD_cxqVmIbYI/s1600/3.png" height="266" width="320" /></a></div>
<br />
<div style="text-align: justify;">
It was not hard to implement it, and I was satisfied with the result. I also changed the viewing transformation from the skewed triangles to a more traditional isometric view. As the next step I have added the multiplication step with the 2d Gaussian bell curve, and also created the sea (and I saw that it was good) which is just a semi-transparent blueish plane slightly above the zero height level.</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgTxT1fHCL25E4ILiyberI1kqPsVtdxITxlQjM_fCR3JaHMNJZRLxiVhwvF2o1qE-9AqMhPbnrc9sckqz6PKmhEi91vhRuVxPdsKxJjdo2xKakTBL7COYdeYU7KoFUmpVJ0WomKKf_NRiY/s1600/4.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgTxT1fHCL25E4ILiyberI1kqPsVtdxITxlQjM_fCR3JaHMNJZRLxiVhwvF2o1qE-9AqMhPbnrc9sckqz6PKmhEi91vhRuVxPdsKxJjdo2xKakTBL7COYdeYU7KoFUmpVJ0WomKKf_NRiY/s1600/4.png" height="266" width="320" /></a></div>
<br />
<div style="text-align: justify;">
Looks good, right? Nope. It's the most boring island ever, a single pointy mount in the middle, an almost perfect circle shoreline, and most of the features from the fractal terrain are smoothed out. I refined my expectations: interesting mountains, nice beaches and complex shoreline. As a fix I tried to add the Gaussian function to the noise heightmap instead of multiplying with it.</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgyVbFZIXq3ptpy9okvsnC2rZYeWpSKDpdYWQwBVHyKeVECXK_2AvC3urIllGwrUzn6by_1IERWmru5E6dFtjs3nNnW-A3pArzWi4Ze3NJyKyxHRVy37FM7Os5DMr70NGXTmnvkRX11HPg/s1600/5.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgyVbFZIXq3ptpy9okvsnC2rZYeWpSKDpdYWQwBVHyKeVECXK_2AvC3urIllGwrUzn6by_1IERWmru5E6dFtjs3nNnW-A3pArzWi4Ze3NJyKyxHRVy37FM7Os5DMr70NGXTmnvkRX11HPg/s1600/5.png" height="266" width="320" /></a></div>
<br />
<div style="text-align: justify;">
Now it's not terribly awful, just relatively bad. The features of the original fractal terrain are somewhat kept, but it is still just a single mount and a circular shore, no nice flat beach... far from perfect. I went back to reading articles and in the end found <a href="http://www.ridgenet.net/~jslayton/FunWithWilburVol6/" target="_blank">this one</a>, which described a method similar to mine, but used another function instead of the Gaussian. It looked good, so I gave it a try.</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhIloats06LhNnwtXmLTCbLYlpR-9HwHfnaV2Q7UGEr1OfVbyh-UeB68Q3t8k5-c9KNfRfmLlpQEPCqkSLTMg077AC5gMyhUb8bJNzxxZbuPYFvKsnkd40G_M00ukzENDZMal8Ha35FZBw/s1600/6.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhIloats06LhNnwtXmLTCbLYlpR-9HwHfnaV2Q7UGEr1OfVbyh-UeB68Q3t8k5-c9KNfRfmLlpQEPCqkSLTMg077AC5gMyhUb8bJNzxxZbuPYFvKsnkd40G_M00ukzENDZMal8Ha35FZBw/s1600/6.png" height="166" width="200" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiKOHGZFrAiQ74B_jth9LV0Amx_5kSvhHvtX5YwXKQWpj5CxwOB3FMsOmugsiyItaeJZBC95oD-AVHP7brfUqjD6JHHyeldKpmaOfLfdnL5Yt3CL_0GaAjTFCv4RejGhaPmtojsjdeHqAA/s1600/7.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiKOHGZFrAiQ74B_jth9LV0Amx_5kSvhHvtX5YwXKQWpj5CxwOB3FMsOmugsiyItaeJZBC95oD-AVHP7brfUqjD6JHHyeldKpmaOfLfdnL5Yt3CL_0GaAjTFCv4RejGhaPmtojsjdeHqAA/s1600/7.png" height="166" width="200" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiAU3VaugJd6HFKLzSi5ZA1BuVYqleg8PuV30l7ZOMjbnnqXMY-NbAMuCyzyPaFVE6X_ys5b1hW3-L_kua24S8PP2nbnrBVAPb9hSRZ3aInuw0rshGUPWpIeDwP6-yWILOHLQNu3m5d4VI/s1600/8.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiAU3VaugJd6HFKLzSi5ZA1BuVYqleg8PuV30l7ZOMjbnnqXMY-NbAMuCyzyPaFVE6X_ys5b1hW3-L_kua24S8PP2nbnrBVAPb9hSRZ3aInuw0rshGUPWpIeDwP6-yWILOHLQNu3m5d4VI/s1600/8.png" height="166" width="200" /></a></div>
<br />
<div style="text-align: justify;">
Somewhat better, but still boring. I wanted something like <a href="http://voxels.blogspot.de/2014/01/procedural-terrain-heightmap-generation.html" target="_blank">this</a>, with the constraint that it should be an island. The problem with that method was that it was based on Diffusion-limited aggregation which seems to be a looong process to me, and also the result is not always an island. After a good night of sleep I came up with a new and simple method: I would generate a random walk with Brownian motion to define the skeleton of the mountains, and apply Gaussian blur (you can't escape Gauss) a few times with different radii to smooth it into hills and shores. It took a while to code the Brownian noise generator and the Gaussian blur, but it was worth it. When I finally saw the first generated island I immediately knew that this was what I wanted.</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh1GxYxghn7K7q1J89Dwqpq2sXR9ImmNjo0_lzDmaE3kq7rW3mPA1-AJYzK7X5S9rbTPnGSufz_eQ0s-Ybx8b2p-Zw-WBwh8ep6iKSJvT3Ov6jzVdYHq0co2me8YVTCKPnfPET7IoJCpbY/s1600/9.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh1GxYxghn7K7q1J89Dwqpq2sXR9ImmNjo0_lzDmaE3kq7rW3mPA1-AJYzK7X5S9rbTPnGSufz_eQ0s-Ybx8b2p-Zw-WBwh8ep6iKSJvT3Ov6jzVdYHq0co2me8YVTCKPnfPET7IoJCpbY/s1600/9.png" height="166" width="200" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEifcnfueV2xwcRZrYMrZAePQQ8sJ8A01PzqvUTx9q7SLXXJcLCNoW34T6XtgvyZ7PuvcKBQ0ZdPK7qzRD7OrhhWcn6ltUbV5LDnYpQWTcDJh0cxadxy4_MoOHEAwU4Fn5WdGPfrd0VDgiQ/s1600/10.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEifcnfueV2xwcRZrYMrZAePQQ8sJ8A01PzqvUTx9q7SLXXJcLCNoW34T6XtgvyZ7PuvcKBQ0ZdPK7qzRD7OrhhWcn6ltUbV5LDnYpQWTcDJh0cxadxy4_MoOHEAwU4Fn5WdGPfrd0VDgiQ/s1600/10.png" height="166" width="200" /></a></div>
<br />
<div style="text-align: justify;">
This method seems to satisfy all my criteria: complex mountain structures, wide flat beaches, interesting shoreline. The shape of the island is mostly defined by the result of the Brownian noise, and the size is somewhat related to the steps used to generate the noise, though it can be stuck in a small place and result in a small island even with many steps. The implementation needs some tweaking (resample the terrain for higher resolution, rewrite the Gaussian blur to use a separated kernel instead of the O(N^2) slow naive 2d convolution, and fine tune the number of steps for the random walk and the radii of the blurs), but otherwise I'm very satisfied with the method. Now I can play with decorating the island, and soon I will have my own island with palm trees and beaches.</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjBPQ0QrYjbC_bxrJN2PKEd4PPej4YImblO_dQm1jptGtGYeKVv4bpuwRHYn6j-ze3z4vRwVSSCBcDZwUZw1DtsPsVl_URwZtoXCGMXnwzJkQZc6ZdZpAzbyUY1a1J33uj-Jy61Qr3hnEI/s1600/11.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjBPQ0QrYjbC_bxrJN2PKEd4PPej4YImblO_dQm1jptGtGYeKVv4bpuwRHYn6j-ze3z4vRwVSSCBcDZwUZw1DtsPsVl_URwZtoXCGMXnwzJkQZc6ZdZpAzbyUY1a1J33uj-Jy61Qr3hnEI/s1600/11.png" height="266" width="320" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgzp23Pl8hZQqHlWqbe-vB1pdzTgaOXx5r66Sx9Os_u2mORqGvWmO3LmofJdYsjebumrqnawzUbzq42dd0J20qns1BYqNpK3vBI3Gt36EWGaEwfNsEGfKm4jmXIV5MhT1GYq4YomLWvhRs/s1600/12.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgzp23Pl8hZQqHlWqbe-vB1pdzTgaOXx5r66Sx9Os_u2mORqGvWmO3LmofJdYsjebumrqnawzUbzq42dd0J20qns1BYqNpK3vBI3Gt36EWGaEwfNsEGfKm4jmXIV5MhT1GYq4YomLWvhRs/s1600/12.png" height="266" width="320" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgnTST1KjZfYwjQI2ZHJe5ac30RpRkYlIKgmozdHHlNyRRki3TayjcWzfaHra5Kh49fCBLHWKF0ZTFhzD6KhqPHWmzDcrj2DouQYPZDabylqlT2Jyom0OLBJyZAmaPjMxA5XNok0doOpuY/s1600/13.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgnTST1KjZfYwjQI2ZHJe5ac30RpRkYlIKgmozdHHlNyRRki3TayjcWzfaHra5Kh49fCBLHWKF0ZTFhzD6KhqPHWmzDcrj2DouQYPZDabylqlT2Jyom0OLBJyZAmaPjMxA5XNok0doOpuY/s1600/13.png" height="266" width="320" /></a></div>
<br />Peter Belanyihttp://www.blogger.com/profile/12575267258139359711noreply@blogger.com0tag:blogger.com,1999:blog-2622489999593841985.post-11661483437693613732013-11-19T13:52:00.000-08:002013-11-19T13:54:43.733-08:00Concerning component-entity systems<br />
<div style="text-align: justify;">
Recently I have been discussing component based design with a friend, and he asked me how my implementation worked out in my platformer. My description grew quite long, so I thought I would make a post out of it - I wanted to do it anyway, I was just always procrastinating. And since there is not much practical info available about it, hopefully it might be useful for others as well. My system is based on <a href="http://t-machine.org/index.php/2007/09/03/entity-systems-are-the-future-of-mmog-development-part-1/">this article</a>, and probably this post will not be too clean without reading that one first.</div>
<div style="text-align: justify;">
<br />
In my C++ implementation Entity is just a typedef to int, they can be created by<i> entities_create();</i> and recycled by <i>entities_destroy(Entity i);</i>. Currently there are 6 components: Common, Physics, Graphics, Animation, Audio, Camera.</div>
<div style="text-align: justify;">
<br /></div>
<h3 style="text-align: justify;">
Components</h3>
<div style="text-align: justify;">
<br />
The most basic is the Common component, it contains the position, rotation and facing of an entity. I wanted to group together all the data into one component that most entities have and most other components access.</div>
<div style="text-align: justify;">
<br />
The Graphics component assigns images to entities. It accesses the Common component to know where to draw the image. The Animation component is quite similar, but instead of static images it uses animation instances.</div>
<div style="text-align: justify;">
<br />
The Audio component is also similar to the Graphics, it maps entities to Sound instances. At first I thought that it might be a limitation that one entity can have only one sound playing, but then I realized that I can create a new entity for each sound I want to play if needed. Simple.</div>
<div style="text-align: justify;">
<br />
The Physics part is more complicated, it consists of a main component which maps entities to Box2D bodies, and a subcomponent which maps entities to foot sensors (these are used to query whether an entity is standing on something). These are separate components, but due to the underlying Box2D implementation they are intertwined (the foot sensor needs to access the body), so I just put them together. A body can be either static (for platforms) or dynamic (for moving objects), so it could be possible to handle them as two separate components. Each turn the Physics component updates the position and rotation attributes in the Common component. </div>
<div style="text-align: justify;">
<br />
The Camera component is a bit special: only one entity can have it (that is, the Camera component has an Entity target; variable instead of a mapping from entities). I don’t remember the original article mentioning such components, but I thought it was logical to do it this way. Essentially it uses OpenGL transformations to follow The Entity so that it appears in the centre of the screen. Changing it to follow other entities can be used to simply implement nice effects, e.g. following a projectile and zooming in on it.</div>
<div style="text-align: justify;">
<br />
These are the components on the C++ side, but it’s just half of the story; most of the functions of the components are exported to the embedded Lua interpreter, so other components can be implemented in scripts. The C++ components are quite general and could be used to implement many kinds of games (at least I believe so), while the components related to the actual gameplay can be done in Lua. So far I have only implemented the Bullet component, but I was planning others (e.g. AI). Maybe one day I will continue working on this project.</div>
<div style="text-align: justify;">
<br /></div>
<h3>
Technical details</h3>
<div style="text-align: justify;">
</div>
<div style="text-align: justify;">
<br />
For each component I have header file to make all the public functions available to other components (and, more importantly, to Lua), for example <i>common.h</i> contains:</div>
<div style="text-align: justify;">
<br />
void common_init();<br />
void common_add(Entity e, float x=0, float y=0, float angle=0);<br />
void common_delete(Entity e);</div>
<div style="text-align: justify;">
<br />
And <i><name_of_component>.cpp</i> contains the implementation. Private variables and functions are static, public functions are exported in the header, and public variables are global. Yes, global, the second most evil thing after goto, and just slightly better than premature optimization. Please don’t stone me… at least until I blow this whistle. Even if I do say "global". But to be serious, I think this was one of the biggest advantages of using a component-entity system: that it taught me how to tame my globals. I was always told not to use them, because who knows which part of the program modifies them at what time, so they can cause lot’s of headache. But with this system it’s quite clear which component uses what other components, so the modifications can be easily tracked (at least I can do it since I am the only developer… this might be different in a team). And anyway, passing around one huge object containing all the game state is no better.</div>
<div style="text-align: justify;">
<br />
To provide the mappings between entities and components I use two classes (T is the type of the component, usually a struct):</div>
<div style="text-align: justify;">
<br />
template <class T> class DenseComp {...};<br />
template <class T> class SparseComp {...};</div>
<div style="text-align: justify;">
<br />
DenseComp uses <i>std::vector</i> to store the component, and it is used in the Common component. It works since a mapping from Entities (which are in fact integers) to component data is needed, and that’s what a vector does. Since usually most of the entities have the Common component, it’s not wasting space, and this way accessing the Common component of an entity (which is quite frequent) happens in constant time.</div>
<div style="text-align: justify;">
<br />
SparseComp uses <i>std::map</i> to map entities to a component, it is used in general for other components. It is more space-efficient than a vector when just a part of the entities have the component, and usually querying the component of a specific entity is not too frequent, so the slower lookup is not a problem.</div>
<div style="text-align: justify;">
<br />
Creating two separate classes for components might have been premature optimization, since currently I just have a handful of entities, so it does not really matter. Maybe using just the one with std::map would have been enough.</div>
<div style="text-align: justify;">
<br />
Using plain C functions and structs instead of C++ classes to implement components has a big advantage: it’s much easier to bind them to scripting languages. Most scripting language implementations support binding of C functions, but binding methods of C++ classes is complicated at best and usually requires some binding generator. And since Entities are just integers, it’s straightforward to use them in scripts, no need for wrapping classes or handling them as special user-data.</div>
<div style="text-align: justify;">
<br />
On a sidenote, I was experimenting with turning the engine inside-out, that is, throwing out the Lua interpreter, compiling the code as a shared library and then loading it from Ruby or Python or LuaJIT or any other language implementation which supports it, and this way making it available for other scripting languages. It was working fine on Linux, importing shared libs is a piece of cake with LibFFI in Ruby and ctypes in Python, but unfortunately I had issues on windows: loading the dll hung. The problem was related to using the SFML library, and I could not solve it even after a few days of debugging, so I gave up. I considered migrating to SDL, but it would have been much of a hassle.</div>
<div style="text-align: justify;">
<br /></div>
<h3>
Summary</h3>
<div style="text-align: justify;">
<br />
All in all the component-entity system worked out really well in my engine. My codebase is well organized, related code is contained in small, well-separated units. Adding a new feature usually means creating a new .cpp and .h file and requires very little change in existing code. Extending functionality is also easy, since modifications usually affect just one component.</div>
<div style="text-align: justify;">
<br />
This design also hands itself well for building a base engine with general functionality and creating the specific gameplay in scripts. I have no experience with building a complex engine based on OOP, I can imagine that it would work just as well.</div>
<div style="text-align: justify;">
<br />
One thing that is not clear is when to group together simple components into more complex ones, or the opposite, when should it be advantageous to cut a complicated component into several smaller ones. I suppose it needs some experience to decide this.</div>
<div style="text-align: justify;">
<br />
I did not completely throw objects out the window: I still use them as basic building blocks, and they are great for that. But on higher levels there are just entities and components. I think it’s like playing with lego. When you build a house you use the small bricks, but don’t really design it on the level of bricks; you say that the house should have a kitchen, a bedroom, and a garage, and then design those with bricks, and decide how they could fit together to make up a house.</div>
Peter Belanyihttp://www.blogger.com/profile/12575267258139359711noreply@blogger.com2tag:blogger.com,1999:blog-2622489999593841985.post-29919390460369059872013-08-25T07:39:00.000-07:002013-08-25T07:39:04.422-07:00And remember, respect is everything<div style="text-align: justify;">
After almost a year finally a new article. I wasn't idling, but on the one hand I had lots of other things to do (changed job, moved to a new country, made many new friends and discovered new activities like wall climbing), on the other hand I could not make significant progress on any of my projects, so there was nothing to write about.</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
I did not abandon the platformer engine, now and then I was tinkering with it. I have implemented the audio component, so game entities can have sound effects and music can be played in the background; I have added support for joysticks; and migrated to SFML 2.1 from 1.6, which was not trivial due to api changes, but was not hard either.</div>
<div style="text-align: justify;">
<br />After a while there was not much work to do on the engine, it was time to start creating artwork - I could not postpone it any longer. So I designed a character, painted the required body parts, scanned and processed them with Gimp, tried to make a simple walk animation, and failed miserably. It just couldn't get it look good. The main reason is that the animation system I designed did not turn out as good as I expected. Without a skeleton it was hard to keep body proportions and find the correct positions and orientations of the parts. So I designed another animation system based on a skeleton, but could not find motivation to actually implement it.<br /><br />Slowly the decision reaped in me that I should change to a game which does not require much animation, and then I decided I would try my hand at a GTA style game. Not the modern 3d GTAs, but the oldschool GTA 1 and 2 with top-down view. I researched my possibilities for physics and graphics, and finally decided to modify the platformer engine to be suitable for this game style instead of implementing a new engine from scratch. I went into a three day coding spree, and in the end I had the car and pedestrian physics, pseudo 3d buildings and very basic gameplay implemented.<br /><br />The physics is based on this nice <a href="https://github.com/domasx2/gamejs-box2d-car-example">Box2D car example</a> which I reimplemented in C++. It uses a body for the car, and a number of steered and/or driven wheels. The wheels can be placed anywhere on the body, so many different vehicles are possible: cars with front, rear or all-four-driving, motorbikes with 2 or 3 wheels, trucks and limos with 6 wheels. So I did not have to reinvent the wheel.<br /><br />The game logic and physics are 2d, but buildings are drawn in 3d, which gives a sense of depth; just like in the original games. Vehicles and buildings do not need animation, but I’ll have to implement it for humans. I plan an animation system based on separately drawn frames (like in <a href="http://proghappens.blogspot.com/p/silliness-of-lambs.html">The Silliness of the Lambs</a>), nothing complicated (like my <a href="http://proghappens.blogspot.com/2012/03/my-experiments-with-2d-animation.html">attempts for the platformer</a>).<br /><br />The gameplay should be full with action, gunfights, speeding, blood, gore, explosion, all that is fun. Maybe I’ll add RPGish features as well. But I don’t promise anything, I have many other things to do in The Outside, and I also want to experiment with some other ideas… so eventually something will happen to it.</div>
<div style="text-align: justify;">
</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjnXQ7JN3YtmtTPatef7uaYZ_b3yn_PutvhrCYFQvE7tzbQPjYkCG9jJdHcgjEoDxY9VLjmxyK8vBvi06OJ5hH31jmlKPeGFKOF9-xpOh8Y4f4Z3h378dy2iFa_RV1bs2QrfoEhYlCFaXA/s1600/2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjnXQ7JN3YtmtTPatef7uaYZ_b3yn_PutvhrCYFQvE7tzbQPjYkCG9jJdHcgjEoDxY9VLjmxyK8vBvi06OJ5hH31jmlKPeGFKOF9-xpOh8Y4f4Z3h378dy2iFa_RV1bs2QrfoEhYlCFaXA/s320/2.png" width="320" /></a></div>
<div style="text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiwrZd3xqZW6i9aIH3GjU4cc0FcDBW3OAY1wNn9PCwj8n7SktcKfFpDi3VSJXi57nzswqQijo7cXMx-4FOafZ_HbHz2JpOgoP-ynTzCZur7hyphenhyphenVIKpoNHNaSarXd7GOKj1-_FQKlhvHjJTQ/s1600/4.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiwrZd3xqZW6i9aIH3GjU4cc0FcDBW3OAY1wNn9PCwj8n7SktcKfFpDi3VSJXi57nzswqQijo7cXMx-4FOafZ_HbHz2JpOgoP-ynTzCZur7hyphenhyphenVIKpoNHNaSarXd7GOKj1-_FQKlhvHjJTQ/s320/4.png" width="320" /></a></div>
<div style="text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi8Hq8jnNgrnnfVoA7Y3ZEHgjA6hQbPBu-jRXpMs-UHFEP5lKnrIPx_Ibv_U-dvoCr2a7OjXdpMShHPJM-7HsSNpNey5fnc0g71a0NnmN2U0F0059ckteNnJk9cQ_uBBN0268S5OTCs4Xo/s1600/1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi8Hq8jnNgrnnfVoA7Y3ZEHgjA6hQbPBu-jRXpMs-UHFEP5lKnrIPx_Ibv_U-dvoCr2a7OjXdpMShHPJM-7HsSNpNey5fnc0g71a0NnmN2U0F0059ckteNnJk9cQ_uBBN0268S5OTCs4Xo/s320/1.png" width="320" /></a></div>
<div style="text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi5xTIoPD7RdYIUoex6JqaGY2taalAPpftwsQhpIGT1-JcCPmWY_qUo4cojVggLAEiBQTXi-zmKLMEMdWXizS0B0y7yW-3s9OD2JnUoFrb0DTwh1xoncpjUTVXM4anpVKSE1j9lfWQNgcA/s1600/3.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="239" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi5xTIoPD7RdYIUoex6JqaGY2taalAPpftwsQhpIGT1-JcCPmWY_qUo4cojVggLAEiBQTXi-zmKLMEMdWXizS0B0y7yW-3s9OD2JnUoFrb0DTwh1xoncpjUTVXM4anpVKSE1j9lfWQNgcA/s320/3.png" width="320" /></a></div>
<div dir="ltr" style="line-height: 1.15; margin-bottom: 10pt; margin-top: 0pt; text-align: center;">
<br /></div>
Peter Belanyihttp://www.blogger.com/profile/12575267258139359711noreply@blogger.com2tag:blogger.com,1999:blog-2622489999593841985.post-53592878086999464872012-09-17T10:25:00.000-07:002012-09-17T10:25:48.031-07:00Platformer - a bit more like a game<div style="text-align: justify;">There were quite lot of improvements made in my engine, the most important is that I have implemented the animation system, working as described in a <a href="http://proghappens.blogspot.hu/2012/03/my-experiments-with-2d-animation.html" target="_blank">previous article</a>. Most of the code was already written for the animation editor, so I 'just' had to port it to C++ from Java, and make the rendering work with OpenGL.</div><div style="text-align: justify;"><br />
</div><div style="text-align: justify;">A small change that turned out to be quite important was that I have exposed some keyboard handling functions to Lua, so now it is possible to handle key events from scripts. It is important because it makes it possible (and easy) to add new gameplay features from scripts, without modifying the engine. The wizard should throw a fireball? Just add some lines to the keyboard event handling logic in the Lua script, which creates a new entity, sets up its physical properties (size, position, speed) and appearance (add an image to it), and done, there flies the fireball! As the engine becomes more and more complete, the more code will be written in Lua, and less in C++.</div><div style="text-align: justify;"><br />
</div><div style="text-align: justify;">Now that the scripting part of the engine is capable of so much, I have added some mainly eye-candy features besides the projectiles: the camera follows the projectile and zooms on it; the camera target can be switched now, it follows either the wizard or the dog, but it could be any entity in the game; and the last new feature is shaking the camera after falling from great heights.</div><div style="text-align: justify;"><br />
</div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhAaRQsJBNUTmhGZvplXY_9OD-uoRp3ex0fnsxmyv-t-gnIesYf1lpcftaaRd7n55-5LWFtz0xMMjEVtSidwGOWQ44Kn8UEyQcP2fdxTdZetgrCcc2DXRfcztJsK6m62touM20lnAynvDE/s1600/platformer2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="256" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhAaRQsJBNUTmhGZvplXY_9OD-uoRp3ex0fnsxmyv-t-gnIesYf1lpcftaaRd7n55-5LWFtz0xMMjEVtSidwGOWQ44Kn8UEyQcP2fdxTdZetgrCcc2DXRfcztJsK6m62touM20lnAynvDE/s320/platformer2.png" width="320" /></a></div><div style="text-align: justify;"><br />
</div><div style="text-align: justify;">I have been using <a href="https://bitbucket.org/" target="_blank">Bitbucket</a> as an online backup for my projects for a while, and recently I have started to use it's issue tracker too, which is great. It helps me collect the tasks I plan to make in the engine, so when I decide to do some work, I just take a look at the issues, and I can easily decide what should be the next step. I don't have to remember all the possible improvements, and more importantly I don't forget my good ideas.</div><div style="text-align: justify;"><br />
</div><div style="text-align: justify;">Another awesome thing is that I tried to compile the engine on Linux, and after collecting the necessary libraries and setting up the build environment, the code compiled without any warnings, and it runs fine on Linux too. I developed the whole engine with platform independence in mind, but I was glad anyway to see it compile and run without any problems on Linux too, especially since it depends on several libraries.</div><div style="text-align: justify;"><br />
</div><div style="text-align: justify;">The engine will soon have enough features implemented to be sufficient for a simple game, so after some minor improvements my plan is to create some real artwork and a level, and make a short demo version of the game I have in my mind. Though it might be delayed a bit, because I am changing my job (even moving to another country), and I think it will keep me busy for a while.</div><div style="text-align: justify;"><br />
</div><div style="text-align: center;"><iframe allowfullscreen="allowfullscreen" frameborder="0" height="315" src="http://www.youtube.com/embed/VLXa5eVBFFc" width="420"></iframe><br />
</div>Peter Belanyihttp://www.blogger.com/profile/12575267258139359711noreply@blogger.com0tag:blogger.com,1999:blog-2622489999593841985.post-13821919439763708242012-06-11T07:43:00.000-07:002012-06-11T07:43:22.573-07:00Platformer - it's starting to look like a game<div style="text-align: justify;">In the last two months I was busy with lots of other things, but this weekend I had time to work on my game. It was surprisingly easy to continue the development after the break, I think this signs that the code quality is not that bad. Due to the entity-component system the code-base is well separated into largely independent units (components/subsystems), so it's not hard to understand.</div><br />
The new features:<br />
<ul><li>smooth camera system, the camera can follow the movement of any entity</li>
<li>improved scripting, more and more can be done from scrips </li>
<li>graphics layers, by using perspective projection instead of orthographic</li>
<li>lots of small things under the hood which enhance the engine, but are not directly visible</li>
</ul><div style="text-align: justify;"><br />
</div><div style="text-align: justify;">I have examined the Unity and Unreal3 engines and development environments, on the first hand to see if I should use them instead of building my own engine, and on the other hand to see how real, commercial, successful engines work. I decided to continue with my own engine, and my goal is to have a single engine that can be used for different games simply by using different scripts.</div><br />
The usual screenshot and video (please note that the graphics art is completely placeholder, I just drew the images in a few minutes; the game I am planning will have a completely different style):<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgGyt3Hm0KxRyCslBRBNH-7pNiYJhAE7E7vxgZH5vLuKS6mODUXic8g1Idjw4-K-wxFeL_y-bIYLXuoAiAcFrTraOG9Zq5esgdCeuoFRSwwTYTH9v2yWAA5M2vMX3PdVIoz4OkdVqYpaTQ/s1600/platformer.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="256" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgGyt3Hm0KxRyCslBRBNH-7pNiYJhAE7E7vxgZH5vLuKS6mODUXic8g1Idjw4-K-wxFeL_y-bIYLXuoAiAcFrTraOG9Zq5esgdCeuoFRSwwTYTH9v2yWAA5M2vMX3PdVIoz4OkdVqYpaTQ/s320/platformer.png" width="320" /></a></div><br />
<br />
<div class="separator" style="clear: both; text-align: center;"><iframe allowfullscreen="" frameborder="0" height="315" src="http://www.youtube.com/embed/LzxWuIVUW2c?rel=0" width="420"></iframe></div><br />
<div style="text-align: justify;">The next step in my plan is to implement animation, then handling physical events, and meanwhile generally improve the engine. Then, when the engine is good enough, I will start building a real game with it.</div><br />
<div style="text-align: justify;">BTW I have realized I love platformer games. I really enjoy jumping, shooting or solving problems in Trine 1 and 2, Limbo, Braid, American McGee's Alice and Alice: Madness Returns... I have even played Prince of Persia (<a href="http://en.wikipedia.org/wiki/Prince_of_Persia_%281989_video_game%29" target="_blank">the good old one</a>, not the new version) in DOSBox. I think I will have to invest into buying Rayman: Origins too, it looks quite good. Actually I took the fancy to continue developing my game while playing Braid and Limbo... somehow I felt I shouldn't just play games, I should create them if I can.<br />
<br />
Another thing I have realized is that how convenient it is to play games with a gamepad compared to controlling with the keyboard. It's much better leaning back in my chair or couch, resting my hands holding the controller in my laps, instead of leaning over the keyboard on my desk. So I will aim for supporting gamepads in my games.</div>Peter Belanyihttp://www.blogger.com/profile/12575267258139359711noreply@blogger.com0tag:blogger.com,1999:blog-2622489999593841985.post-89179019902891947592012-04-07T08:57:00.002-07:002012-04-07T14:52:37.731-07:00A basic platformer<div style="text-align: justify;">I have started to work on the 2d platformer game I mentioned in the previous article. As the first step I am developing the engine. It is in C++, using Box2D for physics, SFML for window handling, input and audio, OpenGL for rendering (currently just old style OpenGL, later I plan to use shaders), and Lua for scripting. Box2D, OpenGL and the C++ glue code will do the heavy lifting, while the game logic and events will be scripted in Lua.</div><br />
<div style="text-align: justify;">I use my own entity-component framework which is based on <a href="http://t-machine.org/index.php/2007/09/03/entity-systems-are-the-future-of-mmog-development-part-1/" target="_blank">this article</a> to organize the 'things' in the game. This is my first experiment with an EC system, so far it seems to work really well. It is quite different from object oriented design, it modified the way I think about structuring the code.</div><div style="text-align: justify;"><br />
</div><div style="text-align: justify;">Building a basic platformer with Box2D is not really hard. I chose boxes as the physical representation of entities. It might not be too accurate, but I think it will be sufficient for the game I plan. But later I can extend it anyway. Platforms that do not move have a static Box2D body, other things that should be able to move and react to forces have a dynamic body.</div><div style="text-align: justify;"><br />
</div><div style="text-align: justify;">As a platformer game, jumping has an important role in gameplay. The player should be able to jump, also enemies, but only when there is something they can jump from, that is, they are standing on something. My first approach to detect if an entity can jump was to check the forces effecting the body, and if the y component is greater than zero, then there is surely something pushing the body upwards and jumping should be allowed. I implemented this method, at first seemed to work, but then I noticed that when the player was standing on another dynamic body then sometimes it could not jump. After some examination it turned out that when two dynamic bodies are resting on each other then the value of y component varies inconsistently (at least as far as I can tell...), so this is not a good method.</div><div style="text-align: justify;"><br />
</div><div style="text-align: justify;">My next idea was to attach sensors to the lower parts of the bodies, and use them to detect if there is something under the body. Sensors are like ghost bodies, they go through other bodies (they do not generate collisions), but they detect if they are touching something. I implemented this method too, and it works like a charm. So from now on every living thing in the game will have a thin 'foot sensor' to decide whether it can jump.</div><div style="text-align: justify;"><br />
</div><div style="text-align: justify;">The 'living things' (the player, enemies...) have 0.0 friction to move easily, and fixed rotation because that's how they should behave in a platformer :) To move a body I just set it's velocity (e.g. v.y=30 to jump, v.x=20 to move right), and Box2D will take care of everything. Here is an image showing the simple sandbox environment I used for testing. It has 2 static platforms, 3 dynamic boxes and the player.</div><div style="text-align: justify;"><br />
</div><div class="separator" style="clear: both; text-align: center;"><a href="http://i.imgur.com/SRtFc.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="240" src="http://i.imgur.com/SRtFc.png" width="320" /></a></div><div style="text-align: justify;"><br />
</div><div style="text-align: justify;">A picture is worth a thousand words, but since this is a game a video might be worth a thousand pictures, so here is a short one:</div><div style="text-align: justify;"><br />
</div><div style="text-align: center;"><iframe allowfullscreen="" frameborder="0" height="315" src="http://www.youtube.com/embed/XhKthsph_Vw?rel=0" width="420"></iframe></div><div style="text-align: justify;"><br />
</div><div style="text-align: justify;">There is much work to do... implementing animation, particle systems, sound effects, camera... lot's of tangential stuff like menu system, starting a game, loading, saving... then programming the gameplay, creating content. So I will not be bored :)</div>Peter Belanyihttp://www.blogger.com/profile/12575267258139359711noreply@blogger.com1tag:blogger.com,1999:blog-2622489999593841985.post-39851439042101935972012-03-03T08:48:00.000-08:002012-03-03T08:48:47.966-08:00My experiments with 2d animation<div style="text-align: justify;">Recently I was playing with the thought to start developing a new game, now that the previous one is finished. One of my ideas is a 2d sidescroller platformer game, similar to the 2d mode of Alice: Madness Returns, with some inspirations from Trine. After considering different options I decided that I would develop my own game engine (I like programming, so that would be the funniest part anyway:), that would use Box2D for physics, Lua for scripting and OpenGL with shaders for rendering.</div><br />
<div style="text-align: justify;">While planning the game I was thinking much about animation. For <a href="http://proghappens.blogspot.com/p/silliness-of-lambs.html" target="_blank">The Silliness of the Lambs</a> I have done some basic animations, but they are quite ugly, and creating them was a bit tedious. I realized that drawing animations frame by frame is not my slice of bread, so I was looking for other ways to do it. I wanted something like drawing parts of a character (like body, head, arms, legs), and then putting them together in different poses to form an animation.</div><br />
<div style="text-align: justify;">Since skeletal animation is the most used method for 3d animations, as a first attempt I designed a 2d skeletal animation system. In this system every character would have:</div><ul><li>a skeleton: a hierarchical set of bones, defining the main structure of the character</li>
<li>a 'skin': a set of images; each bone would have an image</li>
<li>poses: a pose would define the position of each bone related to their parents</li>
<li>animations: a sequence of poses and the interpolation times between them would form an animation</li>
</ul><div style="text-align: justify;">The advantages of this system would be naturally looking animations, and that the skeleton could be used for ragdoll effects. Existing tools could also be used for this, the animations could be created in a 3d editor, and an engine like Ogre could play them. But I don't have much experience with 3d editors, and I thought that Ogre would be overkill for a simple 2d game, so on paper I designed an animation program that I could use to edit skeletons, skins, poses and animations. After that I realized that I did not really want to implement a such complex program just to create animations, and that this whole system was too complicated.</div><br />
<div style="text-align: justify;">So I started to think about a simpler method, and I realized that a skeleton is not really needed for an animation, so I designed a new system without a skeleton. In this system the basic structure is the 'animation'; different animations for a character are not related. An animation consists of a set of parts (images), several frames, and the interpolation times between the frames. A frame defines a transformation (translation, rotation and scale) for each image, and these transformations are interpolated between frames (by the way I have learned that interpolating angles is not just that simple...).</div><br />
<div style="text-align: justify;">This new system does not have the advantages of the previous one, but it was much more appealing for me, so I implemented a simple editor for it. I used Java , because that's what I like to use to create programs with GUIs.</div><br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj9PnS-rdDe5mEs95scd-8qjO2fPJNh4DMX6XTfsKlqj5e_8j89WnZPm0Zbl05rfwGHOTG4-HOIwpP2EWQoSdIMq_aXsuIpRl83HCep8yMxXYNhtskzrjx5Xs2YgkxPsGyaeVRwhW1UuuU/s1600/anim01.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="298" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj9PnS-rdDe5mEs95scd-8qjO2fPJNh4DMX6XTfsKlqj5e_8j89WnZPm0Zbl05rfwGHOTG4-HOIwpP2EWQoSdIMq_aXsuIpRl83HCep8yMxXYNhtskzrjx5Xs2YgkxPsGyaeVRwhW1UuuU/s400/anim01.png" width="400" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Adding the first part</td></tr>
</tbody></table><br />
<div style="text-align: justify;">The left area is for handling the parts. Parts can be added, deleted, named and put in order (the order is important when drawing the animation, it defines the drawing order). The upper panel is the palette. Parts can be selected from the list on the left, and the desired operation on them can be performed with the mouse.<br />
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiDH-4GhK9L-A2Pb9tJ7wksBEU8OqXnTX8mHJ6aXfIyKlW9j8kxvT4kzYwpSjlPJt4sRkIBvAuvLSqnBGYofV_QNScZfEhBNDZvDIh_kMDBbo_FWM1yfUjKl59WFi2-mHztckQhC2TtBAI/s1600/anim02.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="297" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiDH-4GhK9L-A2Pb9tJ7wksBEU8OqXnTX8mHJ6aXfIyKlW9j8kxvT4kzYwpSjlPJt4sRkIBvAuvLSqnBGYofV_QNScZfEhBNDZvDIh_kMDBbo_FWM1yfUjKl59WFi2-mHztckQhC2TtBAI/s400/anim02.png" width="400" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Some more parts, named, ordered, moved and rotated</td></tr>
</tbody></table><br />
<div style="text-align: justify;">The area below the drawing canvas is for handling frames (adding, removing them, and setting the duration between them). The transformation operations on the parts always modify the current frame.</div><div style="text-align: justify;"><br />
</div><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiu8EizCtUbkZMrsmw2-TgUEwWHbCPQWoUUjsQRC3lf13HxyJS-B26OmUQxTwyop5poz9Q4VXmE77__zvLuyv7sdCoU8oZE1rnNLsEwOC5FeB3KXfuvwaNESwgItngh0jY6hmuurfcRKB0/s1600/anim03.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="298" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiu8EizCtUbkZMrsmw2-TgUEwWHbCPQWoUUjsQRC3lf13HxyJS-B26OmUQxTwyop5poz9Q4VXmE77__zvLuyv7sdCoU8oZE1rnNLsEwOC5FeB3KXfuvwaNESwgItngh0jY6hmuurfcRKB0/s400/anim03.png" width="400" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Adding and editing frames</td></tr>
</tbody></table><div style="text-align: justify;"><br />
</div><div style="text-align: justify;">The most exciting part of the GUI is the Play button, if it is clicked, a new window is opened which plays the animation. I have recorded a short video of the animation of the wizard that you can see in the pictures:</div><div style="text-align: justify;"><br />
<div style="text-align: center;"><iframe allowfullscreen="" frameborder="0" height="315" src="http://www.youtube.com/embed/QE28IWrloo8?rel=0" width="420"></iframe></div><br />
</div><div style="text-align: justify;">Yeah, it's quite simple, not really naturally looking, but much easier to create than drawing each frame manually, and easier to use than the skeletal version.<br />
<br />
Hopefully one day you will see a game featuring animation created with this program :)</div></div>Peter Belanyihttp://www.blogger.com/profile/12575267258139359711noreply@blogger.com2tag:blogger.com,1999:blog-2622489999593841985.post-88655268145908579152012-01-08T07:40:00.000-08:002012-01-08T07:40:23.276-08:00The Silliness of the Lambs released!I have finished The Silliness of the Lambs and released it for completely free. It is available for download from the Android Market:<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="http://market.android.com/details?id=tsotl.game" style="margin-left: 1em; margin-right: 1em;"><br />
<img alt="Available in Android Market" src="http://www.android.com/images/brand/60_avail_market_logo2.png" /><br />
</a></div><br />
It features 20 levels, sound effects, and all good things that accumulated during the 4-5 months of development. Do not hesitate to try it :) All feedback is welcome.<br />
<br />
I used the following software to develop this game:<br />
<ul><li>Eclipse IDE + Android SDK for coding</li>
<li>Inkscape, Gimp and IrfanView for graphics</li>
<li>Git for version control</li>
<li>SheepEditor (my own custom editor) for creating levels </li>
</ul><br />
Now I can finally start working on new projects :)Peter Belanyihttp://www.blogger.com/profile/12575267258139359711noreply@blogger.com0tag:blogger.com,1999:blog-2622489999593841985.post-57637644156692032282011-12-02T11:45:00.000-08:002011-12-02T11:45:42.775-08:00The Silliness of the Lambs - DEMO 2I have added the missing features to The Silliness of the Lambs and I have improved some aspects of the game based on the feedback I received from different sources, so I am releasing a second (and hopefully last) demo. Thanks again for everyone who tried the previous demo and provided feedback :) I have digested the suggestions and chose the most important ones to be included in the game.<br />
<br />
<a href="http://dl.dropbox.com/u/26011474/proghappens/tsotl/TSotL_demo2.apk">Download.</a><br />
<br />
New features:<br />
<ul><li>Sound effects</li>
<li>Improved UI graphics (might need seed some more improvement...)</li>
<li>Gameplay improvements (e.g. the sheep don't get stuck in the corners)</li>
<li>Some minor bugixes</li>
</ul>Since the graphics hasn't changed much no screenshots this time.Peter Belanyihttp://www.blogger.com/profile/12575267258139359711noreply@blogger.com0tag:blogger.com,1999:blog-2622489999593841985.post-61603629824679086792011-11-20T10:48:00.000-08:002011-11-20T10:48:26.893-08:00The Silliness of the Lambs - DEMOI have finished the demo for the Android version of The Silliness of the Lambs. You are free to download it, all feedback is welcomed. It contains six levels, and it is fully (or hopefully) playable.<br />
<br />
To install the APK file you have to copy it to your device (or download it right there, it's only half MB) and after enabling Unknown Sources it is ready for installation.<br />
<br />
<a href="http://dl.dropbox.com/u/26011474/proghappens/tsotl/TSotL_demo.apk">Download.</a><br />
<br />
It features updated graphics and new levels. I have implemented a level selecting screen, font rendering, and lots of small things to make it a complete game.<br />
<br />
After finishing it (making a pile of levels, fixing possible bugs, implementing sound playback and adding sounds and music) I plan to release it on the Android market. Hopefully I can do it soon :)<br />
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgK2vpFiiLAXNBKCEaTjoY4SWqTDI4RLPRsZCpHuBsm6bBPbepkqQDMRYtze2iAuQ3zAtUgMXu6AS760_cYhK5x5SCbW2SHLN3qHuzMExa2K6mxURDjgND1i2oycHv4DXU5h6h6mnzZBDs/s1600/title.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="192" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgK2vpFiiLAXNBKCEaTjoY4SWqTDI4RLPRsZCpHuBsm6bBPbepkqQDMRYtze2iAuQ3zAtUgMXu6AS760_cYhK5x5SCbW2SHLN3qHuzMExa2K6mxURDjgND1i2oycHv4DXU5h6h6mnzZBDs/s320/title.png" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Title Screen</td></tr>
</tbody></table><br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhcQEle0jwCwnbGckK8Bl5567KlzrLDmmKT9z-dqxK-XKUW1_m_poU9cZvwUSWLTjRmkLNPwAKXifMP8mJvbXrbfZCuJu2vhvlYnBen0mdKzS5CBuPCXIwzVbY7n-GLXNjIfQdS5eBFiWE/s1600/level1.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="192" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhcQEle0jwCwnbGckK8Bl5567KlzrLDmmKT9z-dqxK-XKUW1_m_poU9cZvwUSWLTjRmkLNPwAKXifMP8mJvbXrbfZCuJu2vhvlYnBen0mdKzS5CBuPCXIwzVbY7n-GLXNjIfQdS5eBFiWE/s320/level1.png" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Sample level</td></tr>
</tbody></table><br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg1-k7zI7kLtWlojRBWSyaHt9neaZhg8snzCQ0RR95GDB7mKtVT3DjmraXgmasEjZZRqci_UrYElTsduGXEcGNJmUyDa4THH34Jocjl4G5XjpEaZ5qDg62BXtLnoXIgWYJUMsddEPGkfUw/s1600/level2.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="192" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg1-k7zI7kLtWlojRBWSyaHt9neaZhg8snzCQ0RR95GDB7mKtVT3DjmraXgmasEjZZRqci_UrYElTsduGXEcGNJmUyDa4THH34Jocjl4G5XjpEaZ5qDg62BXtLnoXIgWYJUMsddEPGkfUw/s320/level2.png" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">It's cold in here</td></tr>
</tbody></table><br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi-gaWr0wW9Z51avwWL_e-fq6g8NusMRz4XHuxilyFqajCDpCOa6I_Nvi9RgBdBUw3UX0Rq1gqsBa8pZ1Lff-BDPOUAXEp2KtuqEXzH8_klOMyR74rTCXEe8YZvojTcLS1kGLL_YEcPFuw/s1600/level3.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="192" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi-gaWr0wW9Z51avwWL_e-fq6g8NusMRz4XHuxilyFqajCDpCOa6I_Nvi9RgBdBUw3UX0Rq1gqsBa8pZ1Lff-BDPOUAXEp2KtuqEXzH8_klOMyR74rTCXEe8YZvojTcLS1kGLL_YEcPFuw/s320/level3.png" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Another level</td></tr>
</tbody></table>Peter Belanyihttp://www.blogger.com/profile/12575267258139359711noreply@blogger.com0tag:blogger.com,1999:blog-2622489999593841985.post-74688808022229581332011-11-03T04:44:00.000-07:002011-11-03T04:44:10.392-07:00The Silliness of the Lambs - Level Editor<div style="text-align: justify;">In the web based version of the game the levels were tile-maps and some additional objects (dog, sheep, bush...). Every level's data was inlined in the Processing source, the tile-maps were stored as arrays and the objects were added to the level instances. I designed the levels on paper, then based on the drawings I created the maps in a text editor and calculated the positions for every object - it was quite tedious.</div><div style="text-align: justify;"><br />
</div><div style="text-align: justify;">In the Android version I use an image for the background, and objects for everything else. I did not want to create the levels manually, so I quickly put together a simple level editor. I have finished it in one day and I think this time will come back soon when I'll start producing the levels for the game. Since I develop the game in Java I chose it as the language for implementing the editor. I recalled my memories of creating GUIs in Swing, designed it on paper and then manually coded it (I prefer creating simple user interfaces manually rather than using an editor). When most of the widgets were in place I implemented the event handlers and listeners, the editor was functioning. Creating new levels is now a piece of cake :)</div><div style="text-align: justify;"><br />
</div><div style="text-align: justify;">Using it is quite simple. After clicking the "New" button you can choose the background image from a file open dialog, and it is displayed in the editor. The logical dimensions of the level can be set in the text-boxes on the left. The dog, sheep and bushes can be added to the level by selecting them from the "palette" and clicking on the image. Walls (and generally every blocking areas) can be added by selecting the "Wall" tool and drawing a rectangle. Setting the fold is similar. This follows the logic of the game, since objects that could move have a circle shape, and blocking objects are represented by axis aligned boxes. The level can be saved as an XML file by clicking the "Save" button (surprisingly).</div><div style="text-align: justify;"><br />
</div><div style="text-align: justify;">Screenshots (as you can see it's not a WYSIWYG editor):</div><br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhtDjfQwON63NblwxJGAzkr2PH6gCeiUBZUdEtYZVEE1eTau2WXVaGEuOgcUYheLbZw-l1uC8qbOtOMuK7sjTUZKcJejxTqt4FTaxnBFxz1DPDAYDv4tiJdPSNd3wJUK85E5zKnW66Rfzk/s1600/editor1.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="200" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhtDjfQwON63NblwxJGAzkr2PH6gCeiUBZUdEtYZVEE1eTau2WXVaGEuOgcUYheLbZw-l1uC8qbOtOMuK7sjTUZKcJejxTqt4FTaxnBFxz1DPDAYDv4tiJdPSNd3wJUK85E5zKnW66Rfzk/s200/editor1.png" width="142" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Initial window</td></tr>
</tbody></table><br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgpPt-TFsM_oHI2YZkTV9miqSt78t58U6Ob1cILrGyd7Zz7pKXmrcnCf1aJgAR0D6HrY7jBOSNEnqLuw8Z4-xnUWCaRJcVMmXydPFcq5iS7kb__xe4_vwHSqBx6S0vgjpp2rchvpChnrAc/s1600/editor2.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="138" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgpPt-TFsM_oHI2YZkTV9miqSt78t58U6Ob1cILrGyd7Zz7pKXmrcnCf1aJgAR0D6HrY7jBOSNEnqLuw8Z4-xnUWCaRJcVMmXydPFcq5iS7kb__xe4_vwHSqBx6S0vgjpp2rchvpChnrAc/s320/editor2.png" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">After loading the background picture</td></tr>
</tbody></table><br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi8DGKmuvot81WJuIRw9CZoM4ud-KQmd0pZRTWFTknCDNYsM34NREe7yJnH2Xpz1Xq6GUHmiZJGqCb7HEffw4QNGN_Zw4c5jF89hpyyFujoC5_YOkKmljvunObWhT3wJ-mKsdiF_uD1kaM/s1600/editor3.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="139" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi8DGKmuvot81WJuIRw9CZoM4ud-KQmd0pZRTWFTknCDNYsM34NREe7yJnH2Xpz1Xq6GUHmiZJGqCb7HEffw4QNGN_Zw4c5jF89hpyyFujoC5_YOkKmljvunObWhT3wJ-mKsdiF_uD1kaM/s320/editor3.png" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Adding the dog (black circle)</td></tr>
</tbody></table><br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgz8OoeeK094XKfKlt1vlpuGyTkVOxPU4ObxKcS3cUPx0M81bkvgQ5BccD2oEgCI8Gcie8_4tmivkYjIK1ge_rJN5HErOJGyiVLdXfIU0yhAuQl249QU6ScOKeMPHUzcs4EPsVyfT7rVU8/s1600/editor4.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="139" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgz8OoeeK094XKfKlt1vlpuGyTkVOxPU4ObxKcS3cUPx0M81bkvgQ5BccD2oEgCI8Gcie8_4tmivkYjIK1ge_rJN5HErOJGyiVLdXfIU0yhAuQl249QU6ScOKeMPHUzcs4EPsVyfT7rVU8/s320/editor4.png" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Adding a few sheep (grey circles)</td></tr>
</tbody></table><br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgt7fAXPeCowQJlsh1hRcfjLzR8sw1y4EMpsi5yIjByEF5S8iUCkfPMxCDUuN5HFsKvGX9OX52l9jgpD5UigvAfpYrU0y528U0r8O6Lf6mOgkKusvJNFTLjNwTF3N8dBPkEAaW95fjLjcI/s1600/editor5.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="138" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgt7fAXPeCowQJlsh1hRcfjLzR8sw1y4EMpsi5yIjByEF5S8iUCkfPMxCDUuN5HFsKvGX9OX52l9jgpD5UigvAfpYrU0y528U0r8O6Lf6mOgkKusvJNFTLjNwTF3N8dBPkEAaW95fjLjcI/s320/editor5.png" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Some bushes... (green circles)</td></tr>
</tbody></table><br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjSfWC9kGK-F0EB1thV_gdp-2WK437KMsLAORnJm9e1s2ptrluiWzBUGvCHknnxDDrIWjB2T9ycVDYLui6_XF0VjbsYnbm8gtKfcoYrGFyGVNfz_RZxur83zVpSonF5r6xDlIjwbH_BPAk/s1600/editor6.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="139" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjSfWC9kGK-F0EB1thV_gdp-2WK437KMsLAORnJm9e1s2ptrluiWzBUGvCHknnxDDrIWjB2T9ycVDYLui6_XF0VjbsYnbm8gtKfcoYrGFyGVNfz_RZxur83zVpSonF5r6xDlIjwbH_BPAk/s320/editor6.png" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Setting the fold walls (red rectangles)</td></tr>
</tbody></table><br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhtv49AE467lTnaCtfA4TMTjVYGYC5CWshxkD_8j78beM7WZ9IHBRby4jaGgkTwWNXyYEEziN5ege3DlI_VP62-bZMS284_VJCX8-pSP9ZoLOttHB5AVp3ehY6U-PkRVqf2Ug7Zg-cnZLE/s1600/editor7.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="139" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhtv49AE467lTnaCtfA4TMTjVYGYC5CWshxkD_8j78beM7WZ9IHBRby4jaGgkTwWNXyYEEziN5ege3DlI_VP62-bZMS284_VJCX8-pSP9ZoLOttHB5AVp3ehY6U-PkRVqf2Ug7Zg-cnZLE/s320/editor7.png" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Setting the fold area (blue rectangle) </td></tr>
</tbody></table><br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjbiN-3g6LiEnJv6ShjeBawEDRoD_a1vk4ObjDmLD9i6mYJfdlCVDnZh_k2aF-zSRCaCCogp3T3tHI_hyphenhyphen6jg8SpGNlhQuxA_jrQ0XtHeluCO2mPo7yH74xBO3RDF8CXXHeEjwI479QdM1c/s1600/editor8.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="192" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjbiN-3g6LiEnJv6ShjeBawEDRoD_a1vk4ObjDmLD9i6mYJfdlCVDnZh_k2aF-zSRCaCCogp3T3tHI_hyphenhyphen6jg8SpGNlhQuxA_jrQ0XtHeluCO2mPo7yH74xBO3RDF8CXXHeEjwI479QdM1c/s320/editor8.png" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">In-game screenshot of the level</td></tr>
</tbody></table>Peter Belanyihttp://www.blogger.com/profile/12575267258139359711noreply@blogger.com0tag:blogger.com,1999:blog-2622489999593841985.post-4851080871349091582011-10-27T01:23:00.000-07:002011-10-27T01:23:45.959-07:00Do Androids Dream of Electric Sheep?<div style="text-align: justify;">Soon they will. I am porting (or rather rewriting) <i>The Silliness of the Lambs</i> to Android. The game doesn't need much processing power, the gameplay is quite casual, and it's control mechanics is ideal for touchscreen devices, so the idea to make a smartphone version came quite naturally. It is possible to play the original on a phone in the browser, but it's too slow, and I wanted to get into Android programming anyway.</div><br />
<div style="text-align: justify;">So I went to <a href="http://developer.android.com/">http://developer.android.com</a>, learned the basics of Android development, installed JDK + Eclipse + Android SDK, and started to discover the platform and tried to build up the basics for the game. I was surprised to find that developing for Android is as easy as stomping on kittens. My pessimist self expected that I would have to build the Java project, then manually convert it to an Android package, then somehow transfer it to my phone where I can finally run it. Instead of this I just have to click on the Run button, lean back in my chair, and all of the tasks is done automagically. If my phone is connected to the dev computer through USB then the program is run on it, otherwise the emulator is started and my program is run inside it. On a second thought this <i>is </i>what I really expect of a development environment.</div><br />
<div style="text-align: justify;">After discovering the possibilities I decided to use OpenGL ES for rendering. I have made a simple program which created an OpenGL display and drew a flat shaded triangle, and then extended it step-by-step, added handling of touch events, controlling fps, implemented texture loading and drawing of textured rectangles. At this point I had a basic engine with the functions I needed, so I could start porting the game source. Since Processing is quite similar to Java it did not seem to be too hard, though it wasn't easy. Java needs lots of "decoration" (public final static abstract...), classes go to separate files, the libraries have different functions, etc.</div><br />
<div style="text-align: justify;">During the porting/rewriting I could restructure the code, so it is organized better now. I have redesigned some aspects of the implementation of the game, e.g. instead of a tiled background (which determined both the graphical appearance of the level and the physical representation) I use one big background image (graphical appearance) and the physical objects (e.g. walls) are now stored independently. This modification speeded up both rendering and collision detection. The levels are not inlined in the code anymore but loaded at runtime from xml resources.</div><br />
<div style="text-align: justify;">So now I have a (gameplay-wise) mostly functional version for Android. This means that I am ready with the 90% of the project, now I just have to finish the remaining 90%. I have to implement font rendering, create a menu or level selecting screen, create levels and other contents, and I also plan to add sound effects and maybe music. After it's finished I would like to release it on Android market. I intend to release a demo soon so that you can try it if you are interested.</div><br />
Some images as usual (please note that some parts of the graphics are just placeholders :) <br />
<br />
In the emulator:<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh7k_BIzkd1hP2va_uyV3rBPgEZYNlfxvkzU2Kr9URYZuiKg8OOTz2CMyn5SBXTOemecPFn-lVGAWMMAaoR7Kx0pLWVk4Y1BhR8UURu5UoLwbx2ROL8pUpgyBCkGh1aGmlV4fuO6Qf2_0k/s1600/lambs_emu1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="200" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh7k_BIzkd1hP2va_uyV3rBPgEZYNlfxvkzU2Kr9URYZuiKg8OOTz2CMyn5SBXTOemecPFn-lVGAWMMAaoR7Kx0pLWVk4Y1BhR8UURu5UoLwbx2ROL8pUpgyBCkGh1aGmlV4fuO6Qf2_0k/s200/lambs_emu1.png" width="183" /></a></div><br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjx2J4JLUrpVXz4QoeTfrYUShEcf_8otkNroMIupQG05dyid8X7XgdkLYmbH1-iQRokIXOJB6gLUqxNg7XjJvaDzQ0hUw9shiuFzutAUNgDNfo4-yjYj3iShF-AggiOnM9axbMd8yehXx4/s1600/lambs_emu2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="200" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjx2J4JLUrpVXz4QoeTfrYUShEcf_8otkNroMIupQG05dyid8X7XgdkLYmbH1-iQRokIXOJB6gLUqxNg7XjJvaDzQ0hUw9shiuFzutAUNgDNfo4-yjYj3iShF-AggiOnM9axbMd8yehXx4/s200/lambs_emu2.png" width="183" /></a></div><br />
On my phone:<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhcOcmP0yGRvkIYWa1DzOmUjA88_70Yy4OWVMwJenPdTGLB8cg4ju_MeFI6ZnR81qK4eG9_7I_c4oRMYE7oJJYMpmMUVsPbaeyA9eR8OpmzEOITv1NY_Rg3pSdhtOTTTl14Ftf2toCNZ2U/s1600/lambs_zte1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="115" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhcOcmP0yGRvkIYWa1DzOmUjA88_70Yy4OWVMwJenPdTGLB8cg4ju_MeFI6ZnR81qK4eG9_7I_c4oRMYE7oJJYMpmMUVsPbaeyA9eR8OpmzEOITv1NY_Rg3pSdhtOTTTl14Ftf2toCNZ2U/s200/lambs_zte1.png" width="200" /></a></div><br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgnrbf4Rg30_KAJIIAoERM5Q1_R6lZu9a9fjjbDLo7XGJlNB3oYYA-9YZbNWa4Ou8oHNhfgm6P_gIGTJJfoAtQ-gv_nFO8GPzMiNOvLsa0p68KQR4UHAW9m-QjmKcPgvsQIkvHwwBMjJbY/s1600/lambs_zte2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="115" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgnrbf4Rg30_KAJIIAoERM5Q1_R6lZu9a9fjjbDLo7XGJlNB3oYYA-9YZbNWa4Ou8oHNhfgm6P_gIGTJJfoAtQ-gv_nFO8GPzMiNOvLsa0p68KQR4UHAW9m-QjmKcPgvsQIkvHwwBMjJbY/s200/lambs_zte2.png" width="200" /></a></div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgnrbf4Rg30_KAJIIAoERM5Q1_R6lZu9a9fjjbDLo7XGJlNB3oYYA-9YZbNWa4Ou8oHNhfgm6P_gIGTJJfoAtQ-gv_nFO8GPzMiNOvLsa0p68KQR4UHAW9m-QjmKcPgvsQIkvHwwBMjJbY/s1600/lambs_zte2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><br />
</a><br />
<br />
<br />
<i><span style="font-size: x-small;">P.S. I have watched Blade Runner to have some right to use this title :) I will also read the book.</span></i>Peter Belanyihttp://www.blogger.com/profile/12575267258139359711noreply@blogger.com0tag:blogger.com,1999:blog-2622489999593841985.post-21938594051415255812011-09-03T01:48:00.000-07:002011-09-03T01:48:39.934-07:00The Silliness of the Lambs<div style="text-align: justify;">As I've promised I'm presenting my new game: The Silliness of the Lambs. It's a simple browser based 2D game with a top-down perspective. You control a tireless shepherd dog and your task is to baffle the not-so-smart sheep into the fold.</div><br />
<div style="text-align: justify;">The game is implemented in Processing.js. The development took 2 weeks, with all the planning, designing, programming, producing the artwork, editing the levels and testing. It was all done by me, and I'm proud of the result. The graphics is authentic programmer art, so don't judge too strictly :) I plan to write some articles of the technologies used in the game.</div><br />
Some screenshots:<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjXxXIqsNxc2ckVQYqAceF62azkSna0Lv9pVntalSLSHse-jXHivY3dxy2aZqIbfMlQvI8OSzHJhksOVfuhQXVAj3ljb5nzL278XaGBCgJSFF1ba5S2DdRWihbgoBLBDsDuWUYOAAf89B4/s1600/lamb2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="200" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjXxXIqsNxc2ckVQYqAceF62azkSna0Lv9pVntalSLSHse-jXHivY3dxy2aZqIbfMlQvI8OSzHJhksOVfuhQXVAj3ljb5nzL278XaGBCgJSFF1ba5S2DdRWihbgoBLBDsDuWUYOAAf89B4/s200/lamb2.png" width="200" /></a></div><br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjAB2_yfE_XbQ6jGZ5XJn9MxHb8_CjbYK4shBPLIu4m1pXqCb_u1derz_KzVy1o8EVqu3krpMGMAinb_EusdOzvxkv6iB4e416wQRXOg-WLIGLhXlmO6zATDWNxdvXrBbn6zh3QzKFWO8I/s1600/lamb4.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="200" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjAB2_yfE_XbQ6jGZ5XJn9MxHb8_CjbYK4shBPLIu4m1pXqCb_u1derz_KzVy1o8EVqu3krpMGMAinb_EusdOzvxkv6iB4e416wQRXOg-WLIGLhXlmO6zATDWNxdvXrBbn6zh3QzKFWO8I/s200/lamb4.png" width="200" /></a></div><br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjRDfjprxUIB9hNxSU022YxU0Ptx9_wxxDkKQJNpn5QY0h6bCQ1PkpWAoOJblfyzsmWxxhUlIkbP2f1gBcp7P1e8x3oji415AY19-SQ86I6xM4W-KslTMAkQrV6JnQlsyjXalv7wlHCvWM/s1600/lamb3.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="200" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjRDfjprxUIB9hNxSU022YxU0Ptx9_wxxDkKQJNpn5QY0h6bCQ1PkpWAoOJblfyzsmWxxhUlIkbP2f1gBcp7P1e8x3oji415AY19-SQ86I6xM4W-KslTMAkQrV6JnQlsyjXalv7wlHCvWM/s200/lamb3.png" width="200" /></a></div><br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgGgIq76Zwa45pChU7BbFJdDW_MejUdZhs1JEtIMgQRdQlizdmzISbJTydHasOe8hWhQTs88RobUPidp-EIyNSk3d0AkCugxGtm0pOQitbqSRU44PuLqJ0GiIMOiQ7WTymlYPpc4fiY2ew/s1600/lamb1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="200" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgGgIq76Zwa45pChU7BbFJdDW_MejUdZhs1JEtIMgQRdQlizdmzISbJTydHasOe8hWhQTs88RobUPidp-EIyNSk3d0AkCugxGtm0pOQitbqSRU44PuLqJ0GiIMOiQ7WTymlYPpc4fiY2ew/s200/lamb1.png" width="200" /></a></div><br />
You can <a href="http://dl.dropbox.com/u/26011474/proghappens/lambgame/lamb.html">play it in your browser</a>.<br />
<br />
The source is available for download: <a href="http://dl.dropbox.com/u/26011474/proghappens/lambgame/lamb.zip">lamb.zip</a>Peter Belanyihttp://www.blogger.com/profile/12575267258139359711noreply@blogger.com0tag:blogger.com,1999:blog-2622489999593841985.post-56950350738562206462011-08-30T09:45:00.000-07:002011-08-30T09:45:28.438-07:00My new shirt<div style="text-align: justify;">
After the summer holiday and some unfinished projects I am back with new articles. This one will touch a lighter topic than the previous ones: there will be less programming, and a bit more art :) But don't be afraid, the next article will be about a game I've made and which needs only some polishing now.</div>
<br />
<div style="text-align: justify;">
My girlfriend has bought some textile paint recently, six different colors in little buckets. It aroused my creative self, it made me want to do something with it - especially when I saw how beautiful images she painted on the clothes she was making. So I decided I would use that textile paint to make a nice shirt for myself.</div>
<br />
<div style="text-align: justify;">
The paint was given, I needed a light colored shirt to paint on, and a "good motive" that I would gladly wear. I found an old plain white shirt in my wardrobe, it was perfect for my needs. I like the style of the clothes that <a href="http://shop.cyberdog.net/">Cyberdog</a> makes, so I browsed their site, found this design, and knew that I wanted to copy it:</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjKfhnBv2LOp5oYmewj5nmrPbrPKPXI8Ad4DpsoFYVa0bchuziXyRK3nzw2XFpk2yUR5rmgC8_97RY4FGbIqVMZpUWioAb1qEA41zJivHUXJO0N0rD0ommmhnDL9THG4pZ5ET6U8Ez0ego/s1600/prod_4589.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjKfhnBv2LOp5oYmewj5nmrPbrPKPXI8Ad4DpsoFYVa0bchuziXyRK3nzw2XFpk2yUR5rmgC8_97RY4FGbIqVMZpUWioAb1qEA41zJivHUXJO0N0rD0ommmhnDL9THG4pZ5ET6U8Ez0ego/s320/prod_4589.jpg" width="259" /></a></div>
<br />
I started to convert this image to include only the drawing. First I cut out the interesting part:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi9Cb9O77JOYGGRPALvaUeKu70tD6L6eRD4Ibb7WFM3dFVs72v5P-HoWZHKIagAZz42SnHtou4ef2d0TXE-tnau5l8M2Bq7S83Iw_dKveGGXdoR2aewOHlje9MLcRD_w2eFgV5sotRMl5U/s1600/prod_4589.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi9Cb9O77JOYGGRPALvaUeKu70tD6L6eRD4Ibb7WFM3dFVs72v5P-HoWZHKIagAZz42SnHtou4ef2d0TXE-tnau5l8M2Bq7S83Iw_dKveGGXdoR2aewOHlje9MLcRD_w2eFgV5sotRMl5U/s320/prod_4589.png" width="183" /></a></div>
<br />
<div style="text-align: justify;">
As you can see luckily the relief of the model girl did not distort the image considerably. My plan was to print this image to paper, then put it under the shirt, and follow the lines with my brush to get the best result. But before that I wanted to clear the background of the image to white. On the first hand it saves tint when printing, and on the other hand the image picture would be clearer under the textile. The white shirt is not fully transparent obviously, so I wanted to get rid of every misleading noise.</div>
<br />
<div style="text-align: justify;">
I was trying to somehow convert the grey-scale background to white, and leave the black shapes untouched. Converting to 2 color black-and-white was not a good solution, because the antialiased forms became too sharp, pixelized. I tried everything I could think of in Gimp, Photoshop, IrfanView, but I couldn't find a function or plugin that would do what I needed. Googling did not help either. I really did not want to clean it up by hand. At that point I thought that if I can not find a tool to solve my problem then I'll make one - I'm a programmer after all :)</div>
<br />
So at first I collected my expectations concerning the new tool:<br />
<ul>
<li>convert the grey background to white</li>
<li>leave the black shapes untouched</li>
<li>keep most of the edges antialiased</li>
<li>leave non-grey colours untouched (this was important because I was planning to convert other images which were coloured)</li>
</ul>
<br />
<div style="text-align: justify;">
The hard thing is to decide if a grey pixel is part of the background or it is part of an antialiased edge. I used a threshold value to decide the problem: if the pixel is grey, and it's darker than the threshold then keep it's original color, otherwise make it white. I used an other threshold parameter to decide if a pixel is grey or it's another color: if the difference between the RGB components of the pixel was lower than the threshold, it was considered grey and dealt with as described previously, otherwise it was considered to be another color. Maybe there is a plugin/program which does roughly this and I just could not find it - I would be glad to hear about it.</div>
<br />
<div style="text-align: justify;">
The implementation is a short Python script. I used <a href="http://www.sfml-dev.org/">PySFML</a> for loading, saving images and accessing their pixels. It is a bit overkill for this purpose, but I was already familiar with this library, it was easy to use, and it was already installed on my machine so I could start scripting immediately. I think the code will be easy to understand after the explanation:</div>
<br/>
<style type="text/css">
span {
font-family: 'Consolas';
font-size: 11pt;
color: #DCDCCC;
}
.sc0 {
}
.sc2 {
color: #8CD0D3;
}
.sc4 {
color: #DCA3A3;
}
.sc5 {
font-weight: bold;
color: #DFC47D;
}
.sc9 {
color: #CEDF99;
}
.sc10 {
font-weight: bold;
color: #9F9D6D;
}
.sc11 {
}
</style>
<div style="white-space: pre; line-height: 1; background: #3F3F3F; "><span class="sc5">from</span><span class="sc0"> </span><span class="sc11">sfml</span><span class="sc0"> </span><span class="sc5">import</span><span class="sc0"> </span><span class="sc11">sf</span><span class="sc0">
</span><span class="sc11">greyness</span><span class="sc0"> </span><span class="sc10">=</span><span class="sc0"> </span><span class="sc2">20</span><span class="sc0">
</span><span class="sc11">lightness</span><span class="sc0"> </span><span class="sc10">=</span><span class="sc0"> </span><span class="sc2">500</span><span class="sc0">
</span><span class="sc5">def</span><span class="sc0"> </span><span class="sc9">convert</span><span class="sc10">(</span><span class="sc11">pixel</span><span class="sc10">):</span><span class="sc0">
</span><span class="sc11">r</span><span class="sc0"> </span><span class="sc10">=</span><span class="sc0"> </span><span class="sc11">pixel</span><span class="sc10">.</span><span class="sc11">r</span><span class="sc0">
</span><span class="sc11">g</span><span class="sc0"> </span><span class="sc10">=</span><span class="sc0"> </span><span class="sc11">pixel</span><span class="sc10">.</span><span class="sc11">g</span><span class="sc0">
</span><span class="sc11">b</span><span class="sc0"> </span><span class="sc10">=</span><span class="sc0"> </span><span class="sc11">pixel</span><span class="sc10">.</span><span class="sc11">b</span><span class="sc0">
</span><span class="sc5">if</span><span class="sc0"> </span><span class="sc11">abs</span><span class="sc10">(</span><span class="sc11">r</span><span class="sc10">-</span><span class="sc11">g</span><span class="sc10">)</span><span class="sc0"> </span><span class="sc10">+</span><span class="sc0"> </span><span class="sc11">abs</span><span class="sc10">(</span><span class="sc11">r</span><span class="sc10">-</span><span class="sc11">b</span><span class="sc10">)</span><span class="sc0"> </span><span class="sc10">+</span><span class="sc0"> </span><span class="sc11">abs</span><span class="sc10">(</span><span class="sc11">g</span><span class="sc10">-</span><span class="sc11">b</span><span class="sc10">)</span><span class="sc0"> </span><span class="sc10"><</span><span class="sc0"> </span><span class="sc11">greyness</span><span class="sc0"> </span><span class="sc5">and</span><span class="sc0"> </span><span class="sc11">r</span><span class="sc10">+</span><span class="sc11">g</span><span class="sc10">+</span><span class="sc11">b</span><span class="sc0"> </span><span class="sc10">></span><span class="sc0"> </span><span class="sc11">lightness</span><span class="sc0"> </span><span class="sc10">:</span><span class="sc0">
</span><span class="sc5">return</span><span class="sc0"> </span><span class="sc11">sf</span><span class="sc10">.</span><span class="sc11">Color</span><span class="sc10">(</span><span class="sc2">255</span><span class="sc10">,</span><span class="sc2">255</span><span class="sc10">,</span><span class="sc2">255</span><span class="sc10">)</span><span class="sc0">
</span><span class="sc5">else</span><span class="sc10">:</span><span class="sc0">
</span><span class="sc5">return</span><span class="sc0"> </span><span class="sc11">pixel</span><span class="sc0">
</span><span class="sc11">img</span><span class="sc0"> </span><span class="sc10">=</span><span class="sc0"> </span><span class="sc11">sf</span><span class="sc10">.</span><span class="sc11">Image</span><span class="sc10">()</span><span class="sc0">
</span><span class="sc11">img</span><span class="sc10">.</span><span class="sc11">LoadFromFile</span><span class="sc10">(</span><span class="sc0"> </span><span class="sc4">'input.png'</span><span class="sc0"> </span><span class="sc10">)</span><span class="sc0">
</span><span class="sc11">w</span><span class="sc0"> </span><span class="sc10">=</span><span class="sc0"> </span><span class="sc11">img</span><span class="sc10">.</span><span class="sc11">GetWidth</span><span class="sc10">()</span><span class="sc0">
</span><span class="sc11">h</span><span class="sc0"> </span><span class="sc10">=</span><span class="sc0"> </span><span class="sc11">img</span><span class="sc10">.</span><span class="sc11">GetHeight</span><span class="sc10">()</span><span class="sc0">
</span><span class="sc5">for</span><span class="sc0"> </span><span class="sc11">j</span><span class="sc0"> </span><span class="sc5">in</span><span class="sc0"> </span><span class="sc11">range</span><span class="sc10">(</span><span class="sc11">h</span><span class="sc10">):</span><span class="sc0">
</span><span class="sc5">for</span><span class="sc0"> </span><span class="sc11">i</span><span class="sc0"> </span><span class="sc5">in</span><span class="sc0"> </span><span class="sc11">range</span><span class="sc10">(</span><span class="sc11">w</span><span class="sc10">):</span><span class="sc0">
</span><span class="sc11">pixel</span><span class="sc0"> </span><span class="sc10">=</span><span class="sc0"> </span><span class="sc11">img</span><span class="sc10">.</span><span class="sc11">GetPixel</span><span class="sc10">(</span><span class="sc11">i</span><span class="sc10">,</span><span class="sc11">j</span><span class="sc10">)</span><span class="sc0">
</span><span class="sc11">img</span><span class="sc10">.</span><span class="sc11">SetPixel</span><span class="sc10">(</span><span class="sc11">i</span><span class="sc10">,</span><span class="sc11">j</span><span class="sc10">,</span><span class="sc0"> </span><span class="sc11">convert</span><span class="sc10">(</span><span class="sc11">pixel</span><span class="sc10">))</span><span class="sc0">
</span><span class="sc11">img</span><span class="sc10">.</span><span class="sc11">SaveToFile</span><span class="sc10">(</span><span class="sc0"> </span><span class="sc4">'output.png'</span><span class="sc0"> </span><span class="sc10">)</span></div>
<br />
Here is the result of using the script on the previous image:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhg0KSlA1i7gWdFy_dvYZ0Umwi1IYOn_hh8QPHxFcS2jPSYe1MwASME-YqQ7bHKTMMbiXAXcnKuRgoShPyRZ8HMrJvF5uCMRz-jOHigWOp-IwmgDumR90jj2v1ZhBUnzdyeKPEcYa3EwYA/s1600/asdf.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhg0KSlA1i7gWdFy_dvYZ0Umwi1IYOn_hh8QPHxFcS2jPSYe1MwASME-YqQ7bHKTMMbiXAXcnKuRgoShPyRZ8HMrJvF5uCMRz-jOHigWOp-IwmgDumR90jj2v1ZhBUnzdyeKPEcYa3EwYA/s320/asdf.png" width="181" /></a></div>
<br />
<div style="text-align: justify;">
It's not "perfect", there are many grey pixels littered around in the background, but I was satisfied with the result, it's much better than the original after all. My expectations were more-or less accomplished, most of the background was converted to white, it was now economical to print and did not contain much distracting parts.</div>
<br />
<div style="text-align: justify;">
I printed the image in A4 size, realized it was too small, so printed it again on two A4 pages. I glued them together and onto a wooden panel. I put the whole stuff into the shirt and then smoothed and pinned the shirt onto it. The first A4 sized copy was good for reference. I covered a part of the floor with newspaper as a workplace, gathered the black paint, the brush, some test-cloth and a cushion for my knees - everything was ready to paint :)</div>
<br />
I took some photos as I progressed:<br />
<div style="text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjt4_FAathTZFoPmoKnPxijoWeEElYzKSrPo1VacYf-jKLOB1rtFfCeuMmfrOzQGqi8FVK45la0WlwpG1YgrZcEd-HYJWKibuKNOkcSKXQJNetVpPvT9wS-wn0fR8PZ9Zc_nawibLIDw_k/s1600/1.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="209" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjt4_FAathTZFoPmoKnPxijoWeEElYzKSrPo1VacYf-jKLOB1rtFfCeuMmfrOzQGqi8FVK45la0WlwpG1YgrZcEd-HYJWKibuKNOkcSKXQJNetVpPvT9wS-wn0fR8PZ9Zc_nawibLIDw_k/s320/1.jpg" width="320" /> </a></div>
<div style="text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiZP0_66UqvzjCtJFZLge4WseUxrVqPes8o0cwpFH9pXpXVWfLzQPPxWWpgoc0wCwt9QgP2XgCAr3uO_E3jFNMQqAHytw7PrHVH_dew838hKMca60jXUn7GpmHXerYzMGjDxudIlZi7dpM/s1600/2.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="206" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiZP0_66UqvzjCtJFZLge4WseUxrVqPes8o0cwpFH9pXpXVWfLzQPPxWWpgoc0wCwt9QgP2XgCAr3uO_E3jFNMQqAHytw7PrHVH_dew838hKMca60jXUn7GpmHXerYzMGjDxudIlZi7dpM/s320/2.jpg" width="320" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh_SwRE0_URB4wK-_qxQoN7z6w4Op4pBWT7KbGTsS6Kmx98Xom70hL573dd3FjCdqUseUsJx9p-uqeS4oUWVkVzVfwvUuxG8TwYyl9a1f-f8eKw0Wm4_D4IZ7Xo7j1y42gCugjZCLJYwfg/s1600/3.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="256" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh_SwRE0_URB4wK-_qxQoN7z6w4Op4pBWT7KbGTsS6Kmx98Xom70hL573dd3FjCdqUseUsJx9p-uqeS4oUWVkVzVfwvUuxG8TwYyl9a1f-f8eKw0Wm4_D4IZ7Xo7j1y42gCugjZCLJYwfg/s320/3.jpg" width="320" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgWNOX_yMHKxcTFgYWcuqPzp4iBxVI-AMYRKYissYbEsDM8hCBzhkKpCu8vabzXdputQnGhlsnorkz8lKp4P9p9Tadn2VqqirrJo86NgsFT3qnvp53K89NvCJ_qxOtZC8hfyemjOkjayJM/s1600/4.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="241" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgWNOX_yMHKxcTFgYWcuqPzp4iBxVI-AMYRKYissYbEsDM8hCBzhkKpCu8vabzXdputQnGhlsnorkz8lKp4P9p9Tadn2VqqirrJo86NgsFT3qnvp53K89NvCJ_qxOtZC8hfyemjOkjayJM/s320/4.jpg" width="320" /></a></div>
<br />
<br />
<br />
<div style="text-align: justify;">
I worked in two turns on two days, the whole process took about five hours. The paint was quite thick so I could only paint short dashes. When I finished painting I was tired as hell from kneeling on the ground for hours. My mind was tired too, since I had to concentrate hard to paint all those minute details as exactly as possible. But at the same time I was extremely satisfied and proud of my work, I haven't felt similarly for a long time. When I started I didn't really believe I could make it. It was not finished yet (it needed ironing to fix the paint and I planned to cut the sleeves off), but I was through the hardest part.</div>
<br />
Here is an image of the final product:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgSeaBAsQ20ecgljHgv51ziltlAC01SigfngoaXuC7IMKL3LpllOTbB8bQjAC5u4OtddBIrp7yykwIQjJpD3O8uz3JeURXut9O9USuwkpHMAWQmoONslzgAVk_woO1fzZbik2Fgq3t9C9M/s1600/hjavsdfjhvasdf.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgSeaBAsQ20ecgljHgv51ziltlAC01SigfngoaXuC7IMKL3LpllOTbB8bQjAC5u4OtddBIrp7yykwIQjJpD3O8uz3JeURXut9O9USuwkpHMAWQmoONslzgAVk_woO1fzZbik2Fgq3t9C9M/s320/hjavsdfjhvasdf.jpg" width="172" /></a></div>
<br />
<div style="text-align: justify;">
Ordering a shirt from Cyberdog would have been much less work. So was all this hard work worth it? Absolutely. I had much fun during the whole process; now I can enjoy the fruits of my work; and I have a nice shirt I can proudly wear, and tell everyone who asks about it that I made it myself with my two hands :)</div>
<br />
<div style="text-align: justify;">
This happens when fashion meets programming. I hope that this little multidisciplinar excursion was not too boring. As I have already said, next time I'll be back with a more hardcore topic.</div>
<br />
<i><span style="font-size: x-small;">P.S. I hope it's not a copyright infringement that I used the picture from Cyberdog.</span></i> Peter Belanyihttp://www.blogger.com/profile/12575267258139359711noreply@blogger.com0tag:blogger.com,1999:blog-2622489999593841985.post-65407575934954111362011-05-08T09:05:00.000-07:002011-05-08T09:07:14.664-07:00Random name generation continuedIn the previous post about random name generation (which can be found <a href="http://proghappens.blogspot.com/2011/05/random-name-generation.html">here</a>) I have mentioned an improvement of the described method, and now I have it implemented.<br />
<br />
I have modified the original implementation, so that it uses the last two letters for choosing the new letter. I also had to modify the first phase of the algorithm which makes the statistical representation of the "language", now it calculates the probabilities that a letter in a word follows two previous letters.<br />
<br />
The names generated with this modified method are more similar to the original sample names, and it happens more often, that it is one of the samples - though it can be helped by using more samples. The length of the generated names is also more close to the average length of the samples, so I have removed the part that generates a new name until the length is neither too short nor too long.<br />
<br />
The <a href="http://dl.dropbox.com/u/26011474/proghappens/namegen/namegen2.zip">source code</a> is available as before, and you can try it with the previous sample names for comparison:<br />
<script src="http://dl.dropbox.com/u/26011474/proghappens/namegen/namegen2.js" type="text/javascript">
</script><script type="text/javascript">
function generate_new_name2()
{
sampletext = document.getElementById("samples2").value
samples = sampletext.replace(/\s+/g," ").split(' ')
NameGenerator2.prepare(samples)
generated_name_element = document.getElementById("generated_name2")
generated_name_element.innerHTML = "Generated name: " + NameGenerator2.generate(5,10)
}
</script><br />
<textarea cols="40" id="samples2" rows="10">elrond elwing elladan elrohir earendil arwen aragorn celeborn celebrimbor cirdan elbereth legolas galadriel ecthelion gilthoniel luthien tinuviel</textarea><br />
<button onclick="generate_new_name2()" type="button">Generate new name</button><br />
<div id="generated_name2">Generated name:</div>Peter Belanyihttp://www.blogger.com/profile/12575267258139359711noreply@blogger.com0tag:blogger.com,1999:blog-2622489999593841985.post-33826006766426326692011-05-05T08:05:00.000-07:002011-05-05T12:49:42.233-07:00Random name generationProcedural content generation is usually used for making maps, terrains, plants, etc., but names can also be generated procedurally.<br />
<br />
Back in university I studied language technology among others, and during this course we were taught an interesting method for generating random words based on the statistical characteristics of a given language. These words looked similar to the real words of the language at first sight, but they did not necessarily belong to the language.<br />
<br />
This method consists of two phases. In the first phase we make a statistical representation of the words of the language. For this we need a sample set of words. We have to iterate through every word in the set, and calculate the probability that a letter in a word follows another letter. For example if we have only the word 'abacac' in the set, then the probabilities are:<br />
<ul><li>a word starts with letter 'a' with probability 1</li>
<li>letter 'a' is followed by 'b' with prob. 1/3 and by 'c' with prob. 2/3</li>
<li>letter 'b' is followed by 'a' with probability 1</li>
<li>letter 'c' is followed by 'a' with probability 1/2, and ends the world with probability 1/2</li>
</ul><br />
In the second phase we can generate words based on the probabilities. First we choose a starting letter, and then we repeatedly choose a letter that can follow the previous letter until we choose to end the word (if possible). Staying with the previous example:<br />
<ul><li>we have to chose 'a' as the first letter</li>
<li>the second letter can be 'b' with prob. 1/3 and by 'c' with prob. 2/3; if we throw a dice we choose 'b' if the number is 1 or 2, and 'c' otherwise; let's say we got 4, so our word so far is 'ac'</li>
<li>'c' can be followed by 'a' or end the word; 1 to 3 on the dice means we choose 'a', 4 to 6 means the word ends; let's say the number is 2, thus our word becomes 'aca'</li>
<li>we have to choose a letter that follows 'a' again, let's say we threw 6, so our word is 'acac' now</li>
<li>now a successor to 'c' is needed again, suppose our number is 5, so we are finished, our final word is 'acac'</li>
</ul><br />
This example does not show the power of this method, it's just to demonstrate the algorithm. With a large set of words much better results can be achieved.<br />
<br />
The method can be simply used to generate names, this can be really useful for games. For example we know lots of elven names, and with this algorithm we can generate similar random names that we can give to NPCs or help the player choose a name. It can also be used for names of cities, animal races, etc.<br />
<br />
Since sometimes the names can be too short or very long based on the samples, my implementation generates a new name until a name is found which is neither too short nor too long.<br />
<br />
An improvement of this method might choose a letter based not on the last generated character, but on the last 2, 3, ...N characters. This way the words are more similar to the original words, but more samples are needed to achieve good results.<br />
<br />
I have implemented this method in Javascript, so that it can be embedded into the blog. The source code is available for <a href="http://dl.dropbox.com/u/26011474/proghappens/namegen/namegen.zip">download</a>.<br />
<br />
You can also try it: enter the sample names into the textbox separated by spaces, and click 'Generate new name' to (surprisingly) generate a new name.<br />
<script src="http://dl.dropbox.com/u/26011474/proghappens/namegen/namegen.js" type="text/javascript">
</script><br />
<script type="text/javascript">
function generate_new_name()
{
sampletext = document.getElementById("samples").value
samples = sampletext.replace(/\s+/g," ").split(' ')
NameGenerator.prepare(samples)
generated_name_element = document.getElementById("generated_name")
generated_name_element.innerHTML = "Generated name: " + NameGenerator.generate(5,10)
}
</script><br />
<textarea cols="40" id="samples" rows="10">elrond elwing elladan elrohir earendil arwen aragorn celeborn celebrimbor cirdan elbereth legolas galadriel ecthelion gilthoniel luthien tinuviel</textarea><br />
<button onclick="generate_new_name()" type="button">Generate new name</button><br />
<div id="generated_name">Generated name:</div>Peter Belanyihttp://www.blogger.com/profile/12575267258139359711noreply@blogger.com0tag:blogger.com,1999:blog-2622489999593841985.post-88693742951337889292011-04-30T10:16:00.000-07:002011-04-30T10:16:45.565-07:00Simple procedural heightmap generationThere are already several methods for procedural terrain generation (perlin noise, fractals, diamond-square algorithm, etc.). All of them has it's advantages, disadvantages, I do not want to judge or compare them, I just want to describe yet another method I came up with. I think it's main advantage is it's simplicity, it is very easy to implement, yet produces interesting terrains.<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhcL8SuvY7hoedzNynx_JVrn2dw6KoTbDLXuZIvUK5uLId8UWjSk0jqq7mce5ncd7wyECQKR-OcCbjepWI3SVZmssJC4jHK0q-dpjpzOKvR6TIhDF9qsEoicJx7-1Yr7w2XRyhYcwEOm8Y/s1600/terragen4.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="200" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhcL8SuvY7hoedzNynx_JVrn2dw6KoTbDLXuZIvUK5uLId8UWjSk0jqq7mce5ncd7wyECQKR-OcCbjepWI3SVZmssJC4jHK0q-dpjpzOKvR6TIhDF9qsEoicJx7-1Yr7w2XRyhYcwEOm8Y/s200/terragen4.png" width="199" /></a></div><br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiO5YHtQyt2wZvSDzpm-k46JGHo_ZE9cpnxv6Y2FtykPZo1UZD7FP29LHvqerQJAMhyVRIc3frvSpSkOdP0qZungs4hNnhZLpKex8IZdW6jnaqkYFUnTL4ArQXTIVcBmKvq6iZUhXnGYnI/s1600/terragen1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="200" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiO5YHtQyt2wZvSDzpm-k46JGHo_ZE9cpnxv6Y2FtykPZo1UZD7FP29LHvqerQJAMhyVRIc3frvSpSkOdP0qZungs4hNnhZLpKex8IZdW6jnaqkYFUnTL4ArQXTIVcBmKvq6iZUhXnGYnI/s200/terragen1.png" width="199" /></a></div><br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgrY93TiMOEaC4ZjqUKR9rYdJOk68Kf7ym7Q-rVLCfJJ7UnpFP9rSQaAq_GrNz5moPWMacLrbRxyyp5IoIrUmeOi78BX-BS7WNLJcOsAWvwXO_rVO6OVsOxN3wruz24tMB3vLt-ZLkN-rU/s1600/terragen2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="200" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgrY93TiMOEaC4ZjqUKR9rYdJOk68Kf7ym7Q-rVLCfJJ7UnpFP9rSQaAq_GrNz5moPWMacLrbRxyyp5IoIrUmeOi78BX-BS7WNLJcOsAWvwXO_rVO6OVsOxN3wruz24tMB3vLt-ZLkN-rU/s200/terragen2.png" width="199" /></a></div><br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjMvSPzp2J1Ynj63DuabFm-J0jS3vw8_8Aw6cMBRt_epT12aNsbOcaySYFao4uxuSbkju1V7iuwiRfDEqX4S2W9x2HhzSGX7ImkkWOgGuYxs8UqsdWjKBsRm0br9vV_HeuOCz8oOpWHOx0/s1600/terragen3.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="199" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjMvSPzp2J1Ynj63DuabFm-J0jS3vw8_8Aw6cMBRt_epT12aNsbOcaySYFao4uxuSbkju1V7iuwiRfDEqX4S2W9x2HhzSGX7ImkkWOgGuYxs8UqsdWjKBsRm0br9vV_HeuOCz8oOpWHOx0/s200/terragen3.png" width="200" /></a></div><br />
The algorithm starts with a flat heightmap, i.e. every cell of the map has a height of 0. Then in a number of iterations it modifies the heightmap, creating the final terrain. In every iteration step a line is generated which crosses the map region, this is achieved by randomly choosing two defining points in the map area. Then the height of every cell of the map on one side of the line is increased by a given value (practically by 1). That is, we repeatedly cut the map into two halves randomly, and raise the level of one of them.<br />
<br />
After several iterations the heightmap has enough variation. The height values are between 0 and the number of iterations. After finding the minimum and maximum values we can interpolate the height values into any range we want. The number of iterations required to get a good looking terrain depends on the size of the map, larger maps usually require more iterations.<br />
<br />
Advantages of this algorithm:<br />
<ul><li>simplicity</li>
<li>works for any map size</li>
<li>scalable (the quality of the terrain can be controlled with the number of iterations)</li>
</ul>Disadvantages:<br />
<ul><li>high computational cost ( for an W*H sized map and N lines it is O(W*H*N) )</li>
<li>not "infinite" like perlin noise</li>
</ul>An online demo is available <a href="http://dl.dropbox.com/u/26011474/proghappens/terragen/terragen.html">here</a>, it is implemented in processing.js. It generates a 100*100 map with 256 iterations. Since it runs in the browser the calculation speed is quite slow, so be patient.<br />
The source code is also available: <a href="http://dl.dropbox.com/u/26011474/proghappens/terragen/terragen.zip">download</a>.<br />
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhTlYvOxadlCOVQKZ1xlAQBVtKTszL5LdOv7z2SPrkYvTyYaZXWh4ClEYCgEJr5K9h8DIgnqvVQisv-TIXmijEUnFaIsFFRepnOK937Gxct80wd5lzTrypGqwORuQ69Obm2DXjwtoWPk7Y/s1600/terragen_big.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhTlYvOxadlCOVQKZ1xlAQBVtKTszL5LdOv7z2SPrkYvTyYaZXWh4ClEYCgEJr5K9h8DIgnqvVQisv-TIXmijEUnFaIsFFRepnOK937Gxct80wd5lzTrypGqwORuQ69Obm2DXjwtoWPk7Y/s400/terragen_big.png" width="400" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">A 256x256 map generated with 1024 lines</td><td class="tr-caption" style="text-align: center;"><br />
</td></tr>
</tbody></table>Peter Belanyihttp://www.blogger.com/profile/12575267258139359711noreply@blogger.com1tag:blogger.com,1999:blog-2622489999593841985.post-509732062354742162011-04-26T10:32:00.000-07:002011-04-30T10:24:06.238-07:00Light propagation with CA<div style="text-align: justify;">I plan to make a 2d rpg. I have looked at several different variations of calculating field of view (<a href="https://roguecentral.org/libtcod/fov/fov.pdf">this</a> used to be a good summary, but seems to be unavailable at the moment), but I did not really like any of them. Somehow they seemed to be too sharp, too "digital" - something is either visible or not.</div><br />
<div style="text-align: justify;">I wanted a fov calculation that gave more natural results, and I thought that simulating light propagation would be a good candidate. Since the game world would be a 2d grid, the idea of using a cellular automaton to calculate light propagation came to my mind, and I started experimenting with it.</div><br />
<div style="text-align: justify;">After a few ours of planning and coding, I got the results that satisfied my need:<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiR7nqO1L_aExiG3nNmMdQqr9MoDWyQU9F1nJrZintb4L0Nu3sJJZZc4J4fBXtRa0ApS7doYTSqjLiYgULP4LcNeNpuEavf0TtfV1vC5dKus07aq5SOTA-R_djq8GMXwSE2Gi-Nb9vxMfs/s1600/light4.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="200" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiR7nqO1L_aExiG3nNmMdQqr9MoDWyQU9F1nJrZintb4L0Nu3sJJZZc4J4fBXtRa0ApS7doYTSqjLiYgULP4LcNeNpuEavf0TtfV1vC5dKus07aq5SOTA-R_djq8GMXwSE2Gi-Nb9vxMfs/s200/light4.png" width="200" /></a></div><br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgdcxmeoErpdfCnQqPbM6teF4XzUidYF9_X5BQpF182KLX-N_7-_n2Dt6lNAuZX08cc184_Fqu_zO0z79I7-wwZg501dGuGNkjMIzf38TwmQ2uqdddq7SjTz3l2MEfeK7Srf4caFANPREA/s1600/light2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="200" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgdcxmeoErpdfCnQqPbM6teF4XzUidYF9_X5BQpF182KLX-N_7-_n2Dt6lNAuZX08cc184_Fqu_zO0z79I7-wwZg501dGuGNkjMIzf38TwmQ2uqdddq7SjTz3l2MEfeK7Srf4caFANPREA/s200/light2.png" width="199" /></a></div><br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhHNjJyzbjQ_ozUUbk_2KmbPaB9u9kBFqa26TLqKY4UWX_M6ERGJH7a6fKROW2m3AIsKpapkP3tFIjU3mQNM1La5XqOSmHizbpw08lIJGCYFT0PXmTW78OEDIdDGYGuq1YTvOaxL5xIVfo/s1600/light1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="200" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhHNjJyzbjQ_ozUUbk_2KmbPaB9u9kBFqa26TLqKY4UWX_M6ERGJH7a6fKROW2m3AIsKpapkP3tFIjU3mQNM1La5XqOSmHizbpw08lIJGCYFT0PXmTW78OEDIdDGYGuq1YTvOaxL5xIVfo/s200/light1.png" width="200" /></a></div><div class="separator" style="clear: both; text-align: justify;"><span id="goog_226844810"></span><span id="goog_226844811"></span></div><br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgExOJBiY5F05f3u_lZvvlSWxPgFzc5CxP0aHHHbZFCZ0qqEkzmDP2iDub49j94UGfxffgv5syc8F5qE7lIEaa2Uub93cCcPWwHISsAItVcccmMzQqo1jIi2imLWZkg1oSHdexmYfgmfko/s1600/light3.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="200" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgExOJBiY5F05f3u_lZvvlSWxPgFzc5CxP0aHHHbZFCZ0qqEkzmDP2iDub49j94UGfxffgv5syc8F5qE7lIEaa2Uub93cCcPWwHISsAItVcccmMzQqo1jIi2imLWZkg1oSHdexmYfgmfko/s200/light3.png" width="200" /></a></div><div class="separator" style="clear: both; text-align: justify;"><span id="goog_226844810"></span><span id="goog_226844811"></span></div><div class="separator" style="clear: both; text-align: justify;"><span id="goog_226844810"></span><span id="goog_226844811"></span></div><br />
How does it work? Every cell in the grid has two attributes. The first attribute is transparency: if a cell is transparent, light can propagate through it, otherwise it can only receive light. This value represents wether the cell in the game world is blocking the light, it is not updated by the automaton.<br />
<br />
The second attribute is the strength of the light in that cell. In my implementation it is a floating point value between 0.0 and 1.0. This value is updated during every iteration, the new value is the average of the cell and the neighbouring cells. If the cell is blockling the light, it's value is not included in the averaging, so that they do not light other cells, even thought they can receive light.<br />
<br />
I have used 4 neighbours in my implementation. The drawback of this is that the corners are in shadow. This could be easily solved by using 8 neighbours, but that increases the computational costs. Another improvement could be using RGB colours instead of the simple light strength, this way more interesting effects could be achieved.<br />
<br />
Strictly speaking this might not count as a calculation of field of view, but it achieves a similar effect. I think this method could give a good atmosphere to a game, especially to games with stealth / horror elements. (Imagine walking down a corridor, when suddenly your torch goes out, and everything becomes totally dark... and then you hear a noise...)<br />
<br />
I have implemented this method in processing.js, it is available <a href="http://dl.dropbox.com/u/26011474/proghappens/lightca/ca.html">here</a>, you can experiment with it in the browser. The mouse cursor is the source of the light. In the beginning every cell is a wall, blocking the light. You can 'carve' empty cells into the grid by holding the left mouse button, or build back the walls with the right mouse button. The source code is available <a href="http://dl.dropbox.com/u/26011474/proghappens/lightca/lightca.zip">here</a>.</div>Peter Belanyihttp://www.blogger.com/profile/12575267258139359711noreply@blogger.com0tag:blogger.com,1999:blog-2622489999593841985.post-71588061321540635182011-04-22T01:30:00.000-07:002011-04-22T01:30:00.085-07:00HelloBlog created, expect posts.Peter Belanyihttp://www.blogger.com/profile/12575267258139359711noreply@blogger.com0