<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-797915066036126733</id><updated>2011-09-28T22:52:38.557-05:00</updated><category term='MUGD circle game'/><category term='ruby rails web'/><title type='text'>The world of a game development student</title><subtitle type='html'>Ramblings of a game development student at the University of Missouri</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://dev.chadgodsey.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/797915066036126733/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://dev.chadgodsey.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>ChadyG</name><uri>http://www.blogger.com/profile/08145056828075854965</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/_j16AFUG-s4M/S5iMDwC0CjI/AAAAAAAAA64/LOQ0XG-35Ow/S220/IMG_0160.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>20</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-797915066036126733.post-1286457881177562169</id><published>2010-03-13T16:12:00.001-06:00</published><updated>2010-03-14T23:06:21.487-05:00</updated><title type='text'>Character Physics</title><content type='html'>When I first started using a physics library to do collision detection/response I realized that character control wasn't really just handed to you on a plate. &amp;nbsp;I looked at how one would go about adding normal platformer controls using a physics set up and was a bit overwhelmed. &amp;nbsp;So instead of attempt it I took an easy route and made my characters rolling circles. &amp;nbsp;Granted that works for some game types but sometimes you need something a little more interesting. &amp;nbsp;I've been working on adding some platform-y controls to one of my games and figured I'd share what I learned. &lt;br /&gt;&lt;br /&gt;The following assumes you are creating controls for a 2D game with some physics library (I recommend &lt;a href="http://www.box2d.org/"&gt;Box2D&lt;/a&gt;&amp;nbsp;or &lt;a href="http://code.google.com/p/chipmunk-physics/"&gt;Chipmunk&lt;/a&gt;). &lt;br /&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;br /&gt;&lt;b&gt;Body Setup&lt;/b&gt;&lt;br /&gt;For most games it is important to be able to detect what portion of your character's body is receiving physics callbacks, for this reason we will need to set up a few shapes to attach to our body. &lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Torso&lt;/li&gt;&lt;ul&gt;&lt;li&gt;main collision shape (in my case a rectangle encompassing shoulders down to bottom of the feet)&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;Head&lt;/li&gt;&lt;ul&gt;&lt;li&gt;for movement purposes I just want a circle to help the character shrug off his cranial injuries (not get stuck on his head when falling)&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;Feet&lt;/li&gt;&lt;ul&gt;&lt;li&gt;a sensor shape simple to detect when the feet are touching something&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;Bounding&lt;/li&gt;&lt;ul&gt;&lt;li&gt;another sensor shape to help correct orientation when fallen over (not needed if fixed orientation)&lt;/li&gt;&lt;/ul&gt;&lt;/ul&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;a href="http://2.bp.blogspot.com/_j16AFUG-s4M/S5vyCrCWs2I/AAAAAAAAA7k/NPf938UEErY/s1600-h/physman.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://2.bp.blogspot.com/_j16AFUG-s4M/S5vyCrCWs2I/AAAAAAAAA7k/NPf938UEErY/s320/physman.png" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;From the picture we can see these four shapes. &amp;nbsp;I have colored the physically interacting shapes as green and the sensor shapes as blue. &amp;nbsp;It is important that the foot sensing shape go beyond the interactive portion of the character so that jump detection can work smoothly. &amp;nbsp;If you'd rather your character not be able to fall over, you can always lock the orientation and the bounding box I create here is no longer needed. &amp;nbsp;The next section will detail how I use this box to help orient my character.&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Standing Up&lt;/b&gt;&lt;br /&gt;If you can get away with locking your orientation you do not need to worry about re-orienting the character. &amp;nbsp;However, if you do want your character flipping about then please read on!&lt;br /&gt;&lt;br /&gt;Without any orientation correction, it is inevitable that your controllable character will fall over and potentially start walking with his belly or get stuck forever. &amp;nbsp;Neither of these are all that desirable for most games so we will work on helping the character stand back up. &amp;nbsp;The general idea here is that we know what orientation the body should be in and what orientation the body is in and we want to adjust the orientation to the desired one without breaking the physics simulation. &amp;nbsp;Let's look at some code.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: cpp"&gt;// desired angle&lt;br /&gt; float ang_desire = std::fmod( std::atan2(m_Gravity.y, m_Gravity.x), (float)Gosu::pi * 2.0f);&lt;br /&gt; //Current angle of body&lt;br /&gt; float ang = std::fmod(m_Body-&amp;gt;GetAngle(), 2.f * (float)Gosu::pi);&lt;br /&gt; //find difference to upright (-gravity)&lt;br /&gt; float spin = ang_desire - ang;&lt;br /&gt; if (spin &amp;gt; Gosu::pi) { // Angle wrapping stuff&lt;br /&gt;  spin = ang_desire - (ang + 2.0 * Gosu::pi);&lt;br /&gt; }&lt;br /&gt; if (spin &amp;lt; -Gosu::pi) {&lt;br /&gt;  spin = ang_desire - (ang - 2.0 * Gosu::pi);&lt;br /&gt; }&lt;br /&gt; //apply torque to correct&lt;br /&gt; spin = spin * m_SpinAccel; // Get our force&lt;br /&gt; spin = Gosu::clamp(spin, -m_MaxSpinVel, m_MaxSpinVel); // Clamp to min/max&lt;br /&gt; m_Body-&amp;gt;ApplyTorque(spin);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Here I wish to orient my character to my dynamic gravity vector, so I compute the angle and normalize it to be between 0 and 2*pi;. &amp;nbsp;I then find the difference angle and normalize that to be between -pi and pi. &amp;nbsp;Now I should have the closest difference angle to my desired orientation (no rotating over 180 degrees). &amp;nbsp;I then apply an&amp;nbsp;acceleration&amp;nbsp;magnitude to get a force out of the difference. &amp;nbsp;Here you may want to note that we want a time-sliced force so you might want to choose an acceleration and divide it by your tick speed. &amp;nbsp;Of course if you don't mind having your acceleration in terms of 1/20th of a second or whatever your update rate is, don't worry about it. &amp;nbsp;We then clamp this to some minimum and maximum force so that the character doesn't try and spin wildly about. &amp;nbsp;Finally we apply the force to our body through the ApplyTorque method.&lt;br /&gt;&lt;br /&gt;This can be run constantly, or maybe you want to fire it off only when necessary. &amp;nbsp;Either approach is fine, it will just affect how much torque you want to apply. &amp;nbsp;I have a little of both running in my version. &amp;nbsp;As you run around the character will try and orient himself automatically, but if you do fall over the bounding sensor is used to detect such a situation and allow the player to prop themselves up. &amp;nbsp;This is done by checking if the character is not touching the ground (foot sensor) but the bounding sensor is touching something. &amp;nbsp;The player can then press jump to apply a small impulse to the character allowing the re-orientation to take control. &lt;br /&gt;&lt;br /&gt;&lt;b&gt;Walking&lt;/b&gt;&lt;br /&gt;Walking is fairly simple compared to re-orientation. &amp;nbsp;We simply want to push our character in some direction. Now if we want to only walk while on the ground we need to implement callbacks and keep track of contacts between the character's foot and the ground. &amp;nbsp;I will probably cover this in a later post as doing this using Box2D's current stable interface is a bit involved. &amp;nbsp;For now we can just assume we know when the character is on the ground and move accordingly.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Running&lt;/b&gt;&lt;br /&gt;Sometimes walking just isn't fast enough and we need to get places faster but we don't have a car/airplane/trained ostrich. &amp;nbsp;So we make due with running. &amp;nbsp;For character control this usually just means a modifier key that signals your control code to up the velocity of the character. &amp;nbsp;Nothing too complicated here.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Jumping&lt;/b&gt;&lt;br /&gt;&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;Now what would a platformer be without jumping? &amp;nbsp;That's right, something else. &amp;nbsp;Jumping itself is pretty straight forward, we just need to push the character upward when given the signal. &amp;nbsp;Now what if we want something like Mario where the longer the button is held the higher he jumps? &amp;nbsp;Okay now we're talking! &lt;br /&gt;&lt;br /&gt;For this, we need to keep track of button states i.e. press/held/release etc.. &amp;nbsp;Let's assume we know these things (I will probably write a post on it later) and head on over to logic town. &amp;nbsp;When the jump button is first pressed we apply a large impulse to the character upward, this acts as our initial thrust and baseline jump. &amp;nbsp;We then set off a timer so we don't just let the player hold down jump and jetpack all over the level. &amp;nbsp;I usually set mine to 1/2 of a second. &amp;nbsp;Now, as long as that timer is not zero (don't forget to decrement it) and the jump key is held down we continually add a smaller thrust to the character. &amp;nbsp;I used a ratio of 1:10 for initial to sustained propulsion which seems to work fine for me. &amp;nbsp;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;b&gt;Extra&lt;/b&gt;&lt;br /&gt;&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;All this is fine and dandy but sometimes we want more, like say the ability to jump further based on current running speed or spinning around in the air or dynamically changing the animation speed with the running speed. &amp;nbsp;Really this is where you have a chance to shine and make your movement stand out. &amp;nbsp;With the basics down you should be able to add a number of things to help deepen your movement. &amp;nbsp;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;And just to see all of this in action, here is a little video of my implementation at work&lt;br /&gt;&lt;a href="http://www.youtube.com/watch?v=mvcJ9I_9oww"&gt;http://www.youtube.com/watch?v=mvcJ9I_9oww&lt;/a&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/797915066036126733-1286457881177562169?l=dev.chadgodsey.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dev.chadgodsey.com/feeds/1286457881177562169/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=797915066036126733&amp;postID=1286457881177562169' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/797915066036126733/posts/default/1286457881177562169'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/797915066036126733/posts/default/1286457881177562169'/><link rel='alternate' type='text/html' href='http://dev.chadgodsey.com/2010/03/character-physics.html' title='Character Physics'/><author><name>ChadyG</name><uri>http://www.blogger.com/profile/08145056828075854965</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/_j16AFUG-s4M/S5iMDwC0CjI/AAAAAAAAA64/LOQ0XG-35Ow/S220/IMG_0160.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_j16AFUG-s4M/S5vyCrCWs2I/AAAAAAAAA7k/NPf938UEErY/s72-c/physman.png' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-797915066036126733.post-4138031706886159235</id><published>2010-03-09T01:33:00.009-06:00</published><updated>2010-03-13T14:38:48.594-06:00</updated><title type='text'>What I've been up to</title><content type='html'>Alright, so maybe I'm not that great at blogging yet, or maybe I haven't felt like I've had anything to say for awhile.  At any rate, I've been busy and I need to start updating this thing again.  So without any more ado.&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;My Unnamed Game Engine&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt; &lt;/span&gt;I've been working on creating a number of extensions and systems that I've found a need for to use with &lt;a href="http://www.libgosu.org/"&gt;Gosu&lt;/a&gt;.  It is all C++ since I don't really want to mess with wrapping most of it for Ruby (there are semi-equivalent Ruby solutions available), but in working on this I have certainly accrued quite a bit more experience with C++ and learned a nice set of tricks.  The project can be found on &lt;a href="http://www.assembla.com/wiki/show/MUGE"&gt;Assembla &lt;/a&gt; where you will immediately be confronted with my unfinished stub documentation.  Until recently, the code base has gone through several dramatic changes which made documenting anything a fairly needless task.  However I will discuss a few of the major features here.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt; &lt;/span&gt;To start, I've built a simple game state system based on using a stack of states.  The topmost state in the stack is sent the normal callbacks of update, render, and button events.  In addition to these, there are also initialization, cleanup, pause and resume methods that are called on state transitions.  These exist mainly for memory management (something I have not yet fully needed to flesh out).  Just today, I added a pluggable factory implementation to aid the dynamic use of states.  With this, it is now easy to create a new state that does not have to interfere with the core classes (saving compile times).  It is also simple to dynamically create and push new states on at runtime, which eases my need for quick iteration through skipping titles and menus without recompiling (since I don't have hot asset loading yet).  Information on this set up can be found on &lt;a href="http://www.gamedev.net/reference/articles/article841.asp"&gt;gamedev.net&lt;/a&gt;.  The only problem I found with that particular example is that static member initialization order is undefined so in order to ensure that things work you must make your maker registry a pointer and create it in the registering function (this is detailed in the forum discussion).  &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt; &lt;/span&gt;Another large portion of the project are my graphics systems.  Gosu itself already has a great interface to do 2D rendering, however I wanted to make a nice parallax rendering setup which required a few tweaks.  In order to maintain a clean interface to rendering I needed to abstract the drawing code away from game objects.  Otherwise each object would need to know how to translate world space coordinates into the screen, which can easily become hairy.  I tried providing a translation function, but passing around a pointer to the translation module wasn't much nicer so I ended up pushing all rendering and sprite management into its own little unit.  Within that unit, you can create sprites and spritesheets.  Since the rendering itself is abstracted, each gameobject simply changes the state of the graphics objects to change how they are rendered within the manager.  The sprite objects themselves are merely classes wrapping up the many parameters passed to Gosu's draw calls, listed here:&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;&lt;/li&gt;&lt;li&gt;position (world space)&lt;/li&gt;&lt;li&gt;zoom factor &lt;/li&gt;&lt;li&gt;rotation angle&lt;/li&gt;&lt;li&gt;drawing layer&lt;/li&gt;&lt;li&gt;visible flag&lt;/li&gt;&lt;li&gt;scaling factors&lt;/li&gt;&lt;li&gt;image center&lt;/li&gt;&lt;li&gt;color modification&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div&gt;Spritesheets are a little more involved, since Gosu doesn't support them directly, but provides an interface to build sheets by returning a STL compliant container holding the Gosu::Image objects.  This functionality is contained within my SpriteSheet class which adds support for cycle speed and all the same parameter functionality of Sprite.  The parallax rendering is a full parallax implementation, meaning it supports the normal horizontal panning, but also vertical, zoom, and rotation.  A demo of this can be viewed on &lt;a href="http://www.youtube.com/watch?v=lIoXnHFg6Tg"&gt;YouTube&lt;/a&gt;.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;JSON Configuration&lt;/b&gt;&lt;/div&gt;&lt;div&gt;Normally, text based configuration in games is done through XML.  Personally I find XML to be bloated and goofy looking, despite its power and versatility.  Instead, I chose JSON which I find much more readable even though it does not support schemas nor are there many nice libraries that take care of parsing, modification and serialization.  The library I am using is TinyJSON, which seems to be disappearing from the Internet.  The benefit of this sort of parser is that it is lightweight (aside from requiring Boost::Spirit) and fairly easy to use.  It does not support serialization out of the box though it is easily implemented.  Because of the complicated data structures used it is quite a pain to modify the data model (the structure does make it rather easy to use normally, just a pain to modify).  However, both of these functionalities have been added within the project as well as a cleaner interface to obtain parsed data.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt; &lt;/span&gt;Using this, I have established a set of configuration files to direct the flow of the engine as well as tell it what assets to load and how to use them.  This ranges from establishing key bindings to window size properties to level environment arrangements.  At one point I added configuration support for menus, but for now I prefer to write custom menus in C++.  &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;UI Components&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt; &lt;/span&gt;This addition is a popular sort of Gosu Extension, though at the time I started making it there weren't many available (I think everyone started one at the same time).  Mine is fairly simple, you create a base object that represents your game window then add objects to that.  There is a draggable window component that also supports adding components, but the hierarchy doesn't go much further than that.  Alongside this scheme is functionality for what I call pages.  A page here is a context for the UI containers that allows the user to use a single container for multiple interface configurations that can be switched between.  This is not the most elaborate or feature rich UI system, but it suits me just fine.  &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Physics&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt; &lt;/span&gt;The final addition I will talk about here is the inclusion of &lt;a href="http://www.box2d.org/"&gt;box2D &lt;/a&gt;physics.  There aren't a great number of C++ 2D physics libraries around, but even if there were box2D is a fantastic one to choose.  It doesn't have too many frills which makes it easy to get started using.  Plus, it is actively developed on by a number of people who know game physics.  At this point, my inclusion of it within the engine is pretty minimal.  I have a few callback listeners set up to notify objects of collision events, but with the upcoming new version that API will change to simplify my implementation.  For the most part I haven't had too much need to wrap any particular functionality or build any crazy contraptions.  So I'm going to just let those things build up over time as I need specific things.  I will probably be creating a particle emission system at some point that will make use of box2D, but for now I don't really need it.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Game Projects&lt;/b&gt;&lt;/div&gt;&lt;div&gt;Now, obviously there isn't much point in building all of this if I weren't creating some games.  At this moment I'm working on two projects in my spare time.  The first is a reincarnation of my "Circle Game" or &lt;i&gt;Hamsterball Galaxy&lt;/i&gt;.  The point of doing this is that originally I wanted to open up level creation to the users and add several graphical tweaks to the game.  These additions were limited to my implementation however since I built my levels as static arrays (holy crap) and didn't spend much time working on the graphics code.  This time around, using the engine should make these things much more feasible and hopefully allow me to take the project to a higher level where I'd be more comfortable with attaching a price to it.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt; &lt;/span&gt;The other game project is just now coming out of prototype phase and into a formal birth.  Sometime last year I toyed around with doing Mario Galaxy style movement in 2D and found a nice starting point to accomplish it using box2D.  With that, and more brainstorming I've come to believe that this style of movement would work amazing within a Metroid style run 'n gun - dungeon crawler game.  There are still some tweaks that need to be done with movement to make it squeaky clean, but things are still looking promising.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Wrap Up&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt; &lt;/span&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;This is but one side of my current status, next week-ish I will try to write a post about my graduate work.  &lt;/span&gt;&lt;/b&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/797915066036126733-4138031706886159235?l=dev.chadgodsey.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dev.chadgodsey.com/feeds/4138031706886159235/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=797915066036126733&amp;postID=4138031706886159235' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/797915066036126733/posts/default/4138031706886159235'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/797915066036126733/posts/default/4138031706886159235'/><link rel='alternate' type='text/html' href='http://dev.chadgodsey.com/2010/03/what-ive-been-up-to.html' title='What I&apos;ve been up to'/><author><name>ChadyG</name><uri>http://www.blogger.com/profile/08145056828075854965</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/_j16AFUG-s4M/S5iMDwC0CjI/AAAAAAAAA64/LOQ0XG-35Ow/S220/IMG_0160.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-797915066036126733.post-4674136341939832884</id><published>2009-04-19T20:00:00.006-05:00</published><updated>2009-04-21T21:35:49.060-05:00</updated><title type='text'>Walla Zombies!</title><content type='html'>So I've finished my game for the Ludum Dare contest.  Today I spent a few hours fixing my graphics to not be so shoddy.&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_j16AFUG-s4M/SevJh3aYnNI/AAAAAAAAASQ/Pfb_4CJQkbI/s1600-h/progress9.png"&gt;&lt;img style="cursor: pointer; width: 320px; height: 240px;" src="http://1.bp.blogspot.com/_j16AFUG-s4M/SevJh3aYnNI/AAAAAAAAASQ/Pfb_4CJQkbI/s320/progress9.png" alt="" id="BLOGGER_PHOTO_ID_5326572567943224530" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;The buildings don't really match up to the scale of the characters, though I'm not really worried about that.  As for code changes, I gave both the zombies and player simple momentum for knockback when being hit.  For the zombies, this also helped smooth out their movement.  I've also put in some simple particle effects on damage.  The effect shoots out 10 colored balls which fly out in a random direction and slightly up.  They have basic gravity and will bounce when hitting the ground (z=0).  For the zombies, I colored them a stale red-near brown.  Donuts emit brown, and the player red.  This gives a nice effect and really does make the game more interesting.  Another small graphical change is that characters turn more red as their health goes down.  This is more visually stimulating than modifying the alpha.&lt;br /&gt;&lt;br /&gt;A larger update added today is a melee attack.  You can see from the screenshot that the character is holding a rolling pin.  If zombies get too close to the character, he/she can right click the mouse to swing which will hit surrounding zombies and push them back a bit.  This is nerfed to reduce players' attempts to rely on it though, by limiting the speed to 1/5 of a second and only hitting ten zombies(this also reduces some sound effects clutter as I didn't build a sound manager of any sort so sounds are played for every action).&lt;br /&gt;&lt;br /&gt;As for optimization, I gave the zombies a timer to stall updating the field which is staggered among all of them.  After the initial delay, it will reset to 5 ticks on each count down.  This way, with 50 zombies on screen only 10 or so will attempt to update the field at any tick.  Adding this did not seem to harm the zombie behavior, and the game no longer crawls after throwing many donuts.  The targeting has also been optimized, before they would attempt to update the field for each available target that was close.  Now they find the nearest object and update the vector field based on that object only.&lt;br /&gt;&lt;br /&gt;All  in all, I believe the game is a success.  It started as a quirky game with some interesting developmental elements, i.e. vector fields for AI movement.&lt;br /&gt;&lt;br /&gt;Almost forgot links to the game.&lt;br /&gt;&lt;a href="https://dl.getdropbox.com/u/6366/Walla%20Zombies.zip"&gt;OS X application&lt;/a&gt;&lt;br /&gt;&lt;a href="https://dl.getdropbox.com/u/6366/r2se%20WallaZombies.zip"&gt;Windows executable&lt;/a&gt;&lt;br /&gt;&lt;a href="https://dl.getdropbox.com/u/6366/WallaZombies%20src.zip"&gt;Source&lt;/a&gt;&lt;br /&gt;For linux, grab the source and install Ruby+Gosu as per the README (unless you already have it)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/797915066036126733-4674136341939832884?l=dev.chadgodsey.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dev.chadgodsey.com/feeds/4674136341939832884/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=797915066036126733&amp;postID=4674136341939832884' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/797915066036126733/posts/default/4674136341939832884'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/797915066036126733/posts/default/4674136341939832884'/><link rel='alternate' type='text/html' href='http://dev.chadgodsey.com/2009/04/walla-zombies.html' title='Walla Zombies!'/><author><name>ChadyG</name><uri>http://www.blogger.com/profile/08145056828075854965</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/_j16AFUG-s4M/S5iMDwC0CjI/AAAAAAAAA64/LOQ0XG-35Ow/S220/IMG_0160.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_j16AFUG-s4M/SevJh3aYnNI/AAAAAAAAASQ/Pfb_4CJQkbI/s72-c/progress9.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-797915066036126733.post-5255357666895543487</id><published>2009-04-18T21:38:00.004-05:00</published><updated>2009-04-18T23:05:47.584-05:00</updated><title type='text'>Ludum Dare</title><content type='html'>So I found out yesterday that the Ludum Dare competition was Internet based (hooray for making assumptions!) and now I'm participating with the Ruby/Gosu crowd.  If you are not familiar with the contest, it is a solo contest where you basically get a theme (Advancing Wall of Doom this time) then build a game from scratch (outside of several accepted frameworks for code).  My idea is a combination of word play and sleep induced story.&lt;br /&gt;&lt;br /&gt;A friend of mine jokingly said something about "walla" which turns out is a word, and a city.  As a word, it means the incoherent rumble of voice that comes from a group of people.  It is also a city in Washington (Walla Walla).  From that, my game is a "walla" zombies in Walla Walla.  The point of the game is to survive a horde of zombies by running and tossing donuts (y'know cause zombies like donuts).  Don't ask why donuts, I don't know.  I was half-asleep when that idea came to mind.  Now, the main character is a baker and that just happens to be all that he has on hand.&lt;br /&gt;&lt;br /&gt;For mechanics, the zombies move according to a vector field, ala Ronald C. Arkin's paper "Motor Scheme - Based Mobile Robot Navigation".  The map is split into 10x10 pixel cells, with randomly initialized vectors pointing where to go.  On each update, the zombies pick up this vector and move in that direction.  There is a three in ten chance that they will just move randomly, adding noise to the field in case they get stuck, and to make their movement more erratic.  If they are close to a target, they will build a local vector map pointing towards the target and update the map.  If they are touching (very close) they will "hit" that object, which will either return 1 or -1 if that target is the player or a donut.  This way they can gain health from players and lose from donuts.  Over time, they will die on their own (starvation) which is the objective of the game.&lt;br /&gt;&lt;br /&gt;Because I like making things difficult, I decided on using a simple array based collision map.  Normally, this is a fair idea but instead of storing this data in an image or something convenient I just used text.  This is mainly because I don't have the RMagick gem installed and don't really want to install it.  I would also rather keep my Ruby dependencies to a minimum as I don't want to make it difficult for any judges to run my game.  My window is 640x480 pixels, which works nicely with a 10 pixel unit space.  This leaves me to author a 64x48 array of ones and zeros.  To keep from driving myself mad, I'm just going to limit my game to one map and design that map so that most of the space is solidly open or blocking.  From the screenshots below, you can see that the horizontal middle of the map is where most of the action is. &lt;br /&gt;&lt;br /&gt;The engine for the game is built on top of Gosu, with a minimal state stack to separate the logic of title sequence, gameplay and credits.  Using a nifty trick from another Gosu enthusiast, I've extended the core Array class to catch undefined method calls and feed them into the array elements.  This makes it simple to do things such as @objects.draw&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;class Array&lt;br /&gt;def method_missing(method, *arg)&lt;br /&gt;  self.each { |item| item.send(method, *arg) }&lt;br /&gt;end&lt;br /&gt;end&lt;/blockquote&gt;I've also extended the Image class in Gosu just to simplify calling draw with a bunch of re-used parameters, and also to enable simple animations for rotations and alpha changes.&lt;br /&gt;&lt;br /&gt;On my laptop (1.6 GHz Pentium M, 2GB RAM, ATI x300 radeon mobility) I can easily have fifty zombies running around.  Though this slows down pretty significantly with the vector field updates when you toss out several donuts.  There isn't a whole lot I can do about this, as the work is being done in Ruby and I don't really have time to write some C code to fix such a specific thing.&lt;br /&gt;&lt;br /&gt;For graphics and sound, I was initially going to use the sprites from &lt;a href="http://lostgarden.com/2007/05/dancs-miraculously-flexible-game.html"&gt;lostgarden.com&lt;/a&gt;.  However, using graphics not made by yourself is against the competition's rules.  To cover this, I just traced over my background.  Not really a good solution, but I'm fairly handicapped when it comes to art.  Sound was built using GarageBand and &lt;a href="http://www.cyd.liu.se/%7Etompe573/hp/project_sfxr.html"&gt;sfxr&lt;/a&gt; both incredibly useful for projects like this.&lt;br /&gt;&lt;br /&gt;To introduce the game, I created a title sequence that shows a few screens giving the backstory (the little that exists).  After that there is a sequence zooming into Walla Walla starting from a view from space.  To do this in 2D, I found several images starting with a picture of Earth, a colored map of the United States, a map of Washington's counties, then a map showing Walla Walla within the Walla Walla county (I'm not making this name up, I swear).&lt;br /&gt;&lt;br /&gt;Without any further ado, here are some screenshots.&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_j16AFUG-s4M/SeqVtMz0cjI/AAAAAAAAARo/25YxvpkPHXA/s1600-h/progress1.png"&gt;&lt;img style="cursor: pointer; width: 320px; height: 240px;" src="http://1.bp.blogspot.com/_j16AFUG-s4M/SeqVtMz0cjI/AAAAAAAAARo/25YxvpkPHXA/s320/progress1.png" alt="" id="BLOGGER_PHOTO_ID_5326234113084256818" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_j16AFUG-s4M/SeqVtBKLr3I/AAAAAAAAARw/mLIXx8S6q5I/s1600-h/progress2.png"&gt;&lt;img style="cursor: pointer; width: 320px; height: 240px;" src="http://4.bp.blogspot.com/_j16AFUG-s4M/SeqVtBKLr3I/AAAAAAAAARw/mLIXx8S6q5I/s320/progress2.png" alt="" id="BLOGGER_PHOTO_ID_5326234109956829042" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_j16AFUG-s4M/SeqVtQBF3bI/AAAAAAAAAR4/o0hvcOu3BDE/s1600-h/progress3.png"&gt;&lt;img style="cursor: pointer; width: 320px; height: 240px;" src="http://3.bp.blogspot.com/_j16AFUG-s4M/SeqVtQBF3bI/AAAAAAAAAR4/o0hvcOu3BDE/s320/progress3.png" alt="" id="BLOGGER_PHOTO_ID_5326234113945230770" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_j16AFUG-s4M/SeqVtigU9KI/AAAAAAAAASA/Yx7T3OKBwiI/s1600-h/progress4.png"&gt;&lt;img style="cursor: pointer; width: 320px; height: 240px;" src="http://3.bp.blogspot.com/_j16AFUG-s4M/SeqVtigU9KI/AAAAAAAAASA/Yx7T3OKBwiI/s320/progress4.png" alt="" id="BLOGGER_PHOTO_ID_5326234118908081314" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a aiotarget="false" aiotitle="" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_j16AFUG-s4M/SeqVtxfgV2I/AAAAAAAAASI/GngKeu9kLAw/s1600-h/progress5.png"&gt;&lt;img style="cursor: pointer; width: 320px; height: 240px;" src="http://4.bp.blogspot.com/_j16AFUG-s4M/SeqVtxfgV2I/AAAAAAAAASI/GngKeu9kLAw/s320/progress5.png" alt="" id="BLOGGER_PHOTO_ID_5326234122931165026" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;/blockquote&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/797915066036126733-5255357666895543487?l=dev.chadgodsey.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dev.chadgodsey.com/feeds/5255357666895543487/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=797915066036126733&amp;postID=5255357666895543487' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/797915066036126733/posts/default/5255357666895543487'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/797915066036126733/posts/default/5255357666895543487'/><link rel='alternate' type='text/html' href='http://dev.chadgodsey.com/2009/04/ludum-dare.html' title='Ludum Dare'/><author><name>ChadyG</name><uri>http://www.blogger.com/profile/08145056828075854965</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/_j16AFUG-s4M/S5iMDwC0CjI/AAAAAAAAA64/LOQ0XG-35Ow/S220/IMG_0160.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_j16AFUG-s4M/SeqVtMz0cjI/AAAAAAAAARo/25YxvpkPHXA/s72-c/progress1.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-797915066036126733.post-2872530943864924790</id><published>2009-04-05T21:49:00.002-05:00</published><updated>2009-04-05T21:51:53.684-05:00</updated><title type='text'>shapes and crap</title><content type='html'>After seeing some animation of circles spawning with random colors and growing, I started making something similar with Gosu in Ruby.  After showing some friends it quickly snowballed into supporting multiple shapes, rotations, random selection and cycling selection. &lt;br /&gt;&lt;br /&gt;Basically, you need to try it to see what the hell it does.&lt;br /&gt;Number keys change shape,&lt;br /&gt;R turns on/off rotations,&lt;br /&gt;O randomly selects shape, and&lt;br /&gt;C cycles through shapes&lt;br /&gt;&lt;br /&gt;&lt;a href="file:///Z:/Ruby%20Projects/Circles/Circles.exe"&gt;file:///Z:/Ruby%20Projects/Circles/Circles.exe&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/797915066036126733-2872530943864924790?l=dev.chadgodsey.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dev.chadgodsey.com/feeds/2872530943864924790/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=797915066036126733&amp;postID=2872530943864924790' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/797915066036126733/posts/default/2872530943864924790'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/797915066036126733/posts/default/2872530943864924790'/><link rel='alternate' type='text/html' href='http://dev.chadgodsey.com/2009/04/shapes-and-crap.html' title='shapes and crap'/><author><name>ChadyG</name><uri>http://www.blogger.com/profile/08145056828075854965</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/_j16AFUG-s4M/S5iMDwC0CjI/AAAAAAAAA64/LOQ0XG-35Ow/S220/IMG_0160.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-797915066036126733.post-6608038006867472169</id><published>2009-04-02T12:25:00.005-05:00</published><updated>2009-04-02T13:27:35.306-05:00</updated><title type='text'>SDL ain't dead yet!</title><content type='html'>So I've been working on a clunky 3D OpenGL engine for my OpenGL class any for myself.  As far as I'm concerned the class is just there to give me time to work on actually using all this graphics stuff I've already learned.  Anyway, I'm planning on having it do a bunch of basic things;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;load and render an obj file with a single UV mapped texture&lt;/li&gt;&lt;li&gt;load a series of images and render as a skybox without seams&lt;/li&gt;&lt;li&gt;use a grayscale image to build a terrain, and render with some texture&lt;/li&gt;&lt;li&gt;support point and directional lights&lt;/li&gt;&lt;li&gt;tie into Bullet for physics&lt;br /&gt;&lt;/li&gt;&lt;li&gt;use SDL for various bindings&lt;/li&gt;&lt;/ul&gt;So far I have most of these things set up, I just need some game objects and start using the core of Bullet.&lt;br /&gt;&lt;br /&gt;However, I did hit a few snags along the way.  Some are just shortcomings of my current implementations, others a bit odder.&lt;br /&gt;&lt;br /&gt;Like most of my current projects, I'm attempting to keep my code cross platform by continually building in XCode and Visual Studio and using subversion hosted at Assembla.com.  Earlier this week I hit a large snag while using XCode.  I had cleaned my project to get rid of several mislinked libraries and unused resources when I discovered that I was getting an EXC_BAD_ACCESS runtime error in some code that had been working just fine for a while.  It was in my obj loading phase where I was attempting to push some UV data on a std::vector (like I said, this is a clunky engine).  But for some reason this was failing.  Oddly enough, I was using other vectors alongside this one in similar ways and they seemed to work just fine.&lt;br /&gt;At first, I figured I just needed to claim some memory before using the vector just to be safe.  Of course, reserving and even adding some padding data before-hand just caused the application to crash on those operations.  After fondling the debugger a bit I found that the type pointer was either null, missing (what) or otherwise ill-defined.  This caused some serious head to wall banging as I couldn't understand how the code even existed without knowing what type it was.  I convinced myself that there was a problem with initialization of my data member, so I tried putting a constructor into the initializer list (note, I'm doing all this inside my containing class' constructor and not using a pointer to a vector so this shouldn't be a problem), but to no avail. Finally, I decided to stick this thing in Visual Studio and see what happens.  Once I got the solution set up and linking to the libraries right, I compiled and.. it ran.  No problems, aside from a few small differences in rendering output due to different graphics cards.  So either VS was just being nice to me, or XCode wasn't compiling my code right.  I gave the problem some time, and when coming back to it I started trying silly things like changing my order of declarations in the class header.  Putting the vector declarations first did nothing, putting some declarations in the middle did nothing, but changing the order of the vectors themselves did something.  Turns out, whichever vector was declared last would throw this runtime error.  What this means I have no clue, I'm not even sure how to Google for that to find a solution.  So I ended up "solving" the problem by adding one more vector member aptly named "fuckme".&lt;br /&gt;&lt;br /&gt;Oh, here are some screenshots of the current build showing off a cube of boxmen, a skybox and working terrain.  If you look closely, you might notice that the terrain texture doesn't completely match up to the terrain itself.  Don't worry, this is just a proof of concept and that image wasn't intended for this use.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_j16AFUG-s4M/SdUDKsCBepI/AAAAAAAAALw/5QbxBxZTyyE/s1600-h/Picture+3.png"&gt;&lt;img style="cursor: pointer; width: 320px; height: 258px;" src="http://3.bp.blogspot.com/_j16AFUG-s4M/SdUDKsCBepI/AAAAAAAAALw/5QbxBxZTyyE/s320/Picture+3.png" alt="" id="BLOGGER_PHOTO_ID_5320162016961329810" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_j16AFUG-s4M/SdUDKCZ1JVI/AAAAAAAAALo/mvH37NwT204/s1600-h/Picture+2.png"&gt;&lt;img style="cursor: pointer; width: 320px; height: 258px;" src="http://1.bp.blogspot.com/_j16AFUG-s4M/SdUDKCZ1JVI/AAAAAAAAALo/mvH37NwT204/s320/Picture+2.png" alt="" id="BLOGGER_PHOTO_ID_5320162005786895698" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_j16AFUG-s4M/SdUDJ6j3EcI/AAAAAAAAALg/jkdAmmL6_Aw/s1600-h/Picture+1.png"&gt;&lt;img style="cursor: pointer; width: 320px; height: 258px;" src="http://2.bp.blogspot.com/_j16AFUG-s4M/SdUDJ6j3EcI/AAAAAAAAALg/jkdAmmL6_Aw/s320/Picture+1.png" alt="" id="BLOGGER_PHOTO_ID_5320162003681481154" border="0" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/797915066036126733-6608038006867472169?l=dev.chadgodsey.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dev.chadgodsey.com/feeds/6608038006867472169/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=797915066036126733&amp;postID=6608038006867472169' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/797915066036126733/posts/default/6608038006867472169'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/797915066036126733/posts/default/6608038006867472169'/><link rel='alternate' type='text/html' href='http://dev.chadgodsey.com/2009/04/sdl-aint-dead-yet.html' title='SDL ain&apos;t dead yet!'/><author><name>ChadyG</name><uri>http://www.blogger.com/profile/08145056828075854965</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/_j16AFUG-s4M/S5iMDwC0CjI/AAAAAAAAA64/LOQ0XG-35Ow/S220/IMG_0160.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_j16AFUG-s4M/SdUDKsCBepI/AAAAAAAAALw/5QbxBxZTyyE/s72-c/Picture+3.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-797915066036126733.post-907477089165204646</id><published>2009-02-01T00:32:00.003-06:00</published><updated>2009-03-30T22:53:32.789-05:00</updated><title type='text'>Simple AI design</title><content type='html'>Because I have several C++ projects that I'm going to need to develop AI for, I might as well begin working through some code design.&lt;br /&gt;&lt;br /&gt;As far as game engines go, the singleton manager paradigm is pretty useful (though only in specific scenarios).  With an AI system, this manager needs to keep track of all scene objects using AI, the AI itself, and information used by each agent.  To me, this means that I can create some grouping for particular sets of AI functions and for each scene object requiring AI control I just need to know what set of functions I'm using.  The information, or knowledge base, for each AI/object pair doesn't need to be anything fancy, so a struct will do fine.  This leaves me with three components; the AI Manager, the AI Controllers, and a knowledge struct.&lt;br /&gt;&lt;br /&gt; The manager is a singleton (no need for several managers in one running engine) that allows adding/removing of AI to scene objects, and provides a means to update all objects in batch.  Keeping track of these mappings is sufficient to be a linked list of structs containing a pointer to the object, some identifier for type of AI used, and a knowledge object.  More functionality may be needed, but for now this is all I should have to worry about.&lt;br /&gt;&lt;br /&gt;The AI Controller types need to be able to support multiple AI paradigms.  Initially I was thinking about keeping the knowledge separate from the controllers.  Though this forced me to limit the types of AI that I would be using.  It would either have to deal with complete information or incomplete, fuzzy or crisp, etc..  Instead of that, I'm better off keeping the knowledge within each controller.  Though I'll still define a struct for the different types of data that I'll deal with.&lt;br /&gt;&lt;br /&gt;As a base for the knowledge struct I'm including the following;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;player position&lt;/li&gt;&lt;li&gt;player health&lt;/li&gt;&lt;li&gt;own position&lt;/li&gt;&lt;li&gt;own health&lt;br /&gt;&lt;/li&gt;&lt;li&gt;# proximal friendlies&lt;/li&gt;&lt;li&gt;list of identified projectiles and percieved tragectories (more intelligent agents)&lt;/li&gt;&lt;/ul&gt;I have listed two fields that are redundant as each controller would have access to it's object's health and position.  Though this data may not be in some particular format which the AI functionality would prefer.  So I'm listing them here anyway.&lt;br /&gt;&lt;br /&gt;Put together, I have a manager which will create an AI control object when given a new scene object to manage.  The control object will construct a knowledge set updated by perceptional utilities on the scene object and use this to make decisions for that scene object.&lt;br /&gt;&lt;br /&gt;This design is incomplete, but I'm listing it now as an initial design.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/797915066036126733-907477089165204646?l=dev.chadgodsey.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dev.chadgodsey.com/feeds/907477089165204646/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=797915066036126733&amp;postID=907477089165204646' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/797915066036126733/posts/default/907477089165204646'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/797915066036126733/posts/default/907477089165204646'/><link rel='alternate' type='text/html' href='http://dev.chadgodsey.com/2009/02/simple-ai-design.html' title='Simple AI design'/><author><name>ChadyG</name><uri>http://www.blogger.com/profile/08145056828075854965</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/_j16AFUG-s4M/S5iMDwC0CjI/AAAAAAAAA64/LOQ0XG-35Ow/S220/IMG_0160.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-797915066036126733.post-2114433543756534647</id><published>2008-10-25T15:15:00.004-05:00</published><updated>2009-03-14T01:09:41.218-05:00</updated><title type='text'>Ghosts and Goblins</title><content type='html'>&lt;p&gt;Since I've been using Ruby to prototype games, I'm starting to find that it is a good idea to build a minimal framework for certain types of game (catch, platformer, driving, etc.) so that I can very easily make simple games out of them.  For Halloween, I took my catch game and turned it into a simple platformer about trick or treating.  (you can get to the download for it from my &lt;a href="http://portfolio.chadgodsey.com/"&gt;portfolio&lt;/a&gt;)&lt;/p&gt;&lt;p&gt;To keep this game simple, I imposed a two day limit on development.  It wasn't hard since I already made a nice little system for sprite animations and collisions between rectangles so all I needed to do was build up some finite state automata to drive the items, make some images and figure out some simple gameplay mechanics.  &lt;/p&gt;&lt;p&gt;To overcome the difficulty of distributing Ruby projects to friends, I used &lt;a href="http://www.erikveen.dds.nl/rubyscript2exe/"&gt;RubyScript2exe&lt;/a&gt; to bundle up Ruby, necessary libraries, scripts and media.  This works great with the given variables to help give full path when you need to open files at runtime.  &lt;/p&gt;&lt;p&gt;Since I can't really draw, I figured I'd use Inkscape to create the artwork.  It turned out pretty well.  I realized that I can draw using vector programs when I made a tiny vector drawing script on Graal, of course I still can't draw well but it works when the style is relevant.&lt;/p&gt;&lt;p&gt;&lt;img style="cursor: pointer; width: 320px; height: 244px;" src="http://1.bp.blogspot.com/_j16AFUG-s4M/SQOAoE2TyPI/AAAAAAAAAH4/anBvj7WRVZY/s320/House_closed.png" alt="" id="BLOGGER_PHOTO_ID_5261190215683524850" border="0" /&gt;&lt;/p&gt;&lt;p&gt;Next time I might try Flash so that I can build some animations, but we'll see how that works out.  &lt;/p&gt;&lt;p&gt;For sound, I used a track from &lt;a href="http://www.last.fm/music/Colugo"&gt;Colugo - Music For People&lt;/a&gt;.  I've been wanting to use some of his stuff since it all sounds like great game music.  Obviously I'll have to get permission if I use it for a larger game.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/797915066036126733-2114433543756534647?l=dev.chadgodsey.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dev.chadgodsey.com/feeds/2114433543756534647/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=797915066036126733&amp;postID=2114433543756534647' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/797915066036126733/posts/default/2114433543756534647'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/797915066036126733/posts/default/2114433543756534647'/><link rel='alternate' type='text/html' href='http://dev.chadgodsey.com/2008/10/ghosts-and-goblins.html' title='Ghosts and Goblins'/><author><name>ChadyG</name><uri>http://www.blogger.com/profile/08145056828075854965</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/_j16AFUG-s4M/S5iMDwC0CjI/AAAAAAAAA64/LOQ0XG-35Ow/S220/IMG_0160.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_j16AFUG-s4M/SQOAoE2TyPI/AAAAAAAAAH4/anBvj7WRVZY/s72-c/House_closed.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-797915066036126733.post-954780929480623045</id><published>2008-08-28T21:45:00.007-05:00</published><updated>2008-10-11T02:27:23.987-05:00</updated><title type='text'>prototyping with Ruby and Gosu</title><content type='html'>&lt;p&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_j16AFUG-s4M/SPBPEemgJgI/AAAAAAAAAHY/f_xGVUzs24c/s1600-h/Boxman_Chron1.png"&gt;&lt;img style="cursor:pointer; cursor:hand;" src="http://4.bp.blogspot.com/_j16AFUG-s4M/SPBPEemgJgI/AAAAAAAAAHY/f_xGVUzs24c/s320/Boxman_Chron1.png" border="0" alt="" id="BLOGGER_PHOTO_ID_5255787703493993986" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Now that summer is over and classes are starting again (except now I'm in graduate school) I've decided to become productive again.  Go figure.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;I'm using Ruby with Gosu to quickly develop prototypes to test out gameplay mechanics.  The first image above is a simple catch game using my boxman character I used in a TGEA game.  Nothing special, just some sprite animation and makeshift rectangle intersection stuff really.  I recently finished developing a cellular automata engine for the Ruby programming language.  You can find the project on GitHub here (I'm still more of an SVN kind of guy, but we'll see how this turns out).  I made this for two reasons: for one I haven't written a C.A. engine before, and two I needed something to test complex rules with for our game idea.  &lt;/p&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_j16AFUG-s4M/SPBPEvn6lzI/AAAAAAAAAHg/qf9T5n-7sPU/s1600-h/virus.png"&gt;&lt;img style="cursor:pointer; cursor:hand;" src="http://3.bp.blogspot.com/_j16AFUG-s4M/SPBPEvn6lzI/AAAAAAAAAHg/qf9T5n-7sPU/s320/virus.png" border="0" alt="" id="BLOGGER_PHOTO_ID_5255787708063323954" /&gt;&lt;/a&gt;&lt;p&gt;The game itself is fairly interesting itself in terms of design.  Basically you build a "virus" out of cellular patterns to compete in some pairing with another player to see who's pattern spreads the fastest.  If we go with the iPhone or some other mobile device as the platform for this, then we can bring in another level of viral spread.  Battles can occur in some peer to peer fashion based on locality.  I.E. you can battle people at whatever public area you hang out in.  If we add a server to this mix, then we can track different data on people's virii such as wins, longevity (duration of winning record), spread (real-life spatial), whatever and display this in some form.  &lt;/p&gt;&lt;p&gt;In developing this library with Ruby, I ended up learning a few things along the way.  Mostly getting to know the inner workings of Ruby itself, such as how &lt;/p&gt;&lt;p&gt;Array.new(N, Array.new(K) {|i| i})  &lt;/p&gt;&lt;p&gt;only evaluates the inner block once.  Since I took a course last semester that dealt with functional programming, I can now make use of really cool language tools like lambda functions.  It just so happens that Ruby's functional features are quite robust. &lt;br /&gt;&lt;/p&gt;&lt;p&gt;For my graduate research I am developing a simulation to mimic human behavior in an environment with several different types of sensor networks.  This is to help with an &lt;a href="http://www.tigerplace.net/"&gt;eldercare project&lt;/a&gt; meant to bring computational intelligense into automated systems that can detect urgent needs or various lifestyle needs of people living in eldercare facilities.  &lt;/p&gt;&lt;p&gt;By providing formal input describing daily behavior, my system will be able to simulate days, months, or even years worth of data collection by the sensor networks used by the eldercare system.  By doing this, other research that attempts to understand that data can use the input for supervised learning.  &lt;/p&gt;&lt;p&gt;At any rate, so far it has allowed me to start using JSON/YAML parsers such as &lt;a href="http://blog.beef.de/projects/tinyjson/"&gt;TinyJSON&lt;/a&gt; and Ruby's built in YAML parser.  TinyJSON is interesting since it makes use of &lt;a href="http://www.boost.org/"&gt;Boost's&lt;/a&gt; Spirit library to provide a lightweight but powerful JSON parser.  Unfortunately there is a slight lack of documentation for the parser, but with a little elbow grease it's not hard to figure out.&lt;/p&gt;&lt;pre&gt;&lt;br /&gt;&lt;char&gt;level = boost::any_cast&lt;&gt;::object &gt;::object &gt;(*v);&lt;br /&gt;m_iUnits =  boost::any_cast&lt;&gt;(*level["unitpixel"]);&lt;br /&gt;&lt;/char&gt;&lt;p&gt;&lt;/pre&gt;&lt;char&gt;Turns out that the json::grammar::object is a std::map which works perfect for JSON data.  v above is a variant type that is used to hold the entire JSON object, which you can see on the given documentation.  The real trick is pulling data out of array types.  Luckily there are iterators provided and you can cast them similarly as the variant type if you're like me and create arrays of objects often.  &lt;br /&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;Figuring this out was interesting for me since I haven't had a chance to really dive deep into template programming in C++, so debugging my code was a real treat with that incessant type syntax.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/797915066036126733-954780929480623045?l=dev.chadgodsey.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dev.chadgodsey.com/feeds/954780929480623045/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=797915066036126733&amp;postID=954780929480623045' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/797915066036126733/posts/default/954780929480623045'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/797915066036126733/posts/default/954780929480623045'/><link rel='alternate' type='text/html' href='http://dev.chadgodsey.com/2008/08/prototyping-with-ruby-and-gosu.html' title='prototyping with Ruby and Gosu'/><author><name>ChadyG</name><uri>http://www.blogger.com/profile/08145056828075854965</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/_j16AFUG-s4M/S5iMDwC0CjI/AAAAAAAAA64/LOQ0XG-35Ow/S220/IMG_0160.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_j16AFUG-s4M/SPBPEemgJgI/AAAAAAAAAHY/f_xGVUzs24c/s72-c/Boxman_Chron1.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-797915066036126733.post-3447682429413375357</id><published>2008-04-26T19:48:00.003-05:00</published><updated>2008-04-26T20:04:32.447-05:00</updated><title type='text'>Mark of the 1.0</title><content type='html'>I am finally prepared to call my current build of "Circle Game" (now "Spherical Prison") version 1.  For some reason, I'm a fan of giving the major numbers to the major releases.  This release is the one that I will call "done". &lt;br /&gt;&lt;br /&gt;After taking the time to fix a few hack solutions with proper solutions (i.e. using a boolean to determine if the player has entered the editor to invalidate scores instead of making the score infinity, using a list to buffer the collision callbacks instead of just using the first, etc.), and committing to a decision on what levels I should include, I'm happy with the result.  As far as the level editor goes, it is not viable for community sharing.  I found that even with making my scene dynamic, it would still be quite a bit more work to add methods of filtering keys from walls for deleting and rotating objects.  There are member data fields inside the box2D objects that fit this need, but even with that I don't feel that the implementation would be clean in the end.  The design I chose did not account for sufficient separation of actions pertaining to modification of objects in the scene. &lt;br /&gt;&lt;br /&gt;Today I've also completed my configuration for the Xcode project, so I have a fully functional Mac version that is a duplicate of the Windows version.  Aside from this, a good friend of mine (who would wish to be reffered to as "Z-Dawg") wrote up a makefile for the project for easy building in Linux.  So, fortunately, I'm able to say that using cross-platform libraries has enabled me to build my first totally cross-platform windowed application. &lt;br /&gt;&lt;br /&gt;For now, I must begin channeling my game through the library communities (at first) and then see what else I want to do when I get a web page up for it.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/797915066036126733-3447682429413375357?l=dev.chadgodsey.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dev.chadgodsey.com/feeds/3447682429413375357/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=797915066036126733&amp;postID=3447682429413375357' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/797915066036126733/posts/default/3447682429413375357'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/797915066036126733/posts/default/3447682429413375357'/><link rel='alternate' type='text/html' href='http://dev.chadgodsey.com/2008/04/mark-of-10.html' title='Mark of the 1.0'/><author><name>ChadyG</name><uri>http://www.blogger.com/profile/08145056828075854965</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/_j16AFUG-s4M/S5iMDwC0CjI/AAAAAAAAA64/LOQ0XG-35Ow/S220/IMG_0160.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-797915066036126733.post-190277218147514922</id><published>2008-04-06T22:21:00.005-05:00</published><updated>2008-04-07T07:32:45.056-05:00</updated><title type='text'>Onward to level design!</title><content type='html'>Okay, maybe not quite so energetic.&lt;br /&gt;This weekend let me get a number of things done.  Now the menus are about 95% complete, and I have the first three levels pretty well set.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_j16AFUG-s4M/R_mULrp3N_I/AAAAAAAAAC8/sM2ivGoA8j4/s1600-h/Lev1_SS.png"&gt;&lt;img style="cursor: pointer;" src="http://1.bp.blogspot.com/_j16AFUG-s4M/R_mULrp3N_I/AAAAAAAAAC8/sM2ivGoA8j4/s320/Lev1_SS.png" alt="" id="BLOGGER_PHOTO_ID_5186339374311618546" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;The first level gives the player a chance to get a feel for the movement.  Just rolling around and letting the physics do the rest.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_j16AFUG-s4M/R_mUL7p3OAI/AAAAAAAAADE/HGQVYTSNJV8/s1600-h/Lev2_SS.png"&gt;&lt;img style="cursor: pointer;" src="http://2.bp.blogspot.com/_j16AFUG-s4M/R_mUL7p3OAI/AAAAAAAAADE/HGQVYTSNJV8/s320/Lev2_SS.png" alt="" id="BLOGGER_PHOTO_ID_5186339378606585858" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;The second introduces the bounce and sticky walls.  By changing your speed you'll hit the wall at a different angle and thus be shot off at different angles.  So far everyone that's played the level has figured it out, so I'm definitely keeping the design.  The only problem with this one is that hitting the walls just right takes a bit of practice.  When you shoot up to the top, you can only get back down by pressing up to shoot your self off of the stage, which adds ten seconds to your score.  So the strategy is to get the lower one first.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_j16AFUG-s4M/R_mUMLp3OBI/AAAAAAAAADM/aTbgSbQgkWk/s1600-h/Lev3_SS.png"&gt;&lt;img style="cursor: pointer;" src="http://3.bp.blogspot.com/_j16AFUG-s4M/R_mUMLp3OBI/AAAAAAAAADM/aTbgSbQgkWk/s320/Lev3_SS.png" alt="" id="BLOGGER_PHOTO_ID_5186339382901553170" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;The third introduces the magnet wall.  It's a pretty simple concept, but the design of the level gives a number of options for shortening your time. &lt;br /&gt;&lt;br /&gt;Through some testing with my friends, I'm pretty happy with the designs.  I'm still not entirely sure of the difficulty of the second, but I think I can overcome this with some sort of message shown to the player during gameplay.  Of course, with levels I needed to finish the logic for "winning" the game.  So now I have a place for credits and high scores.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_j16AFUG-s4M/R_mY8Lp3OEI/AAAAAAAAADk/q9A-aQBIX04/s1600-h/HS_SS.png"&gt;&lt;img style="cursor: pointer;" src="http://3.bp.blogspot.com/_j16AFUG-s4M/R_mY8Lp3OEI/AAAAAAAAADk/q9A-aQBIX04/s320/HS_SS.png" alt="" id="BLOGGER_PHOTO_ID_5186344605581785154" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;The high score list shows the top ten total scores, and lists the player's initials and score per level.  This is stored in a binary file (which is just a struct written out and back in) so it will persist.&lt;br /&gt;&lt;br /&gt;Something worth mentioning is that I used &lt;a href="https://www.getdropbox.com/"&gt;DropBox&lt;/a&gt; to share the executable with my online friends.  Doing this introduced an interesting type of concurrency to the game.  As the files shared are synchronized across computers, each player was logically using the same files to play.  This meant that the scores data file was shared too.  Because of this, I could no longer leave a pointer to the file open while the game was running (bad design anyway).  After fixing my design, however we still noticed that if enough people were playing, and finishing the levels quick enough, the files may not sync fast enough to prevent overwriting.  There's not really much I can do about that, but it was still interesting to try and compete with each other.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_j16AFUG-s4M/R_mUMbp3OCI/AAAAAAAAADU/u9m9ssaSwqM/s1600-h/Creds_SS.png"&gt;&lt;img style="cursor: pointer;" src="http://4.bp.blogspot.com/_j16AFUG-s4M/R_mUMbp3OCI/AAAAAAAAADU/u9m9ssaSwqM/s320/Creds_SS.png" alt="" id="BLOGGER_PHOTO_ID_5186339387196520482" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Things still left to do are:&lt;br /&gt;build an in-game level editor (extend the lifetime of the game)&lt;br /&gt;finish the rest of the hardcoded levels&lt;br /&gt;animations for the man, and likely the walls&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/797915066036126733-190277218147514922?l=dev.chadgodsey.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dev.chadgodsey.com/feeds/190277218147514922/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=797915066036126733&amp;postID=190277218147514922' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/797915066036126733/posts/default/190277218147514922'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/797915066036126733/posts/default/190277218147514922'/><link rel='alternate' type='text/html' href='http://dev.chadgodsey.com/2008/04/onward-to-level-design.html' title='Onward to level design!'/><author><name>ChadyG</name><uri>http://www.blogger.com/profile/08145056828075854965</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/_j16AFUG-s4M/S5iMDwC0CjI/AAAAAAAAA64/LOQ0XG-35Ow/S220/IMG_0160.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_j16AFUG-s4M/R_mULrp3N_I/AAAAAAAAAC8/sM2ivGoA8j4/s72-c/Lev1_SS.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-797915066036126733.post-3956011717229418689</id><published>2008-04-01T02:23:00.006-05:00</published><updated>2008-05-05T07:43:25.249-05:00</updated><title type='text'>Refactoring, and moving towards level design</title><content type='html'>Even though classes are back in session, right now all I want to do is build my game.  It beckons me when away, and teases me when I play...  (this is why I don't blab in these things...)&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_j16AFUG-s4M/R_Hkl7p3N9I/AAAAAAAAACs/ehLNMBqxoRc/s1600-h/CircleManTitle.png"&gt;&lt;img style="cursor: pointer;" src="http://2.bp.blogspot.com/_j16AFUG-s4M/R_Hkl7p3N9I/AAAAAAAAACs/ehLNMBqxoRc/s320/CircleManTitle.png" alt="" id="BLOGGER_PHOTO_ID_5184175986399721426" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;I just finished some refactoring, I had let myself put the world and player management inside the main class instead of the scene.  Now they are where they belong, and I have legitimately separated collision callbacks from distance checks for the walls' interactions with the player.  As it stands now, every wall type except sticky is near complete.  After I take the time to create some animations, they should be good.  I'll have to check my color choices to see if they work alright with common color blindness, or if I need worry with the choice of animations.  I figure that this project ought to be as polished as possible, since the complexity of it gives me that option.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_j16AFUG-s4M/R_HkzLp3N-I/AAAAAAAAAC0/YMVE39P3kd4/s1600-h/CircleManTestLevel.png"&gt;&lt;img style="cursor: pointer;" src="http://3.bp.blogspot.com/_j16AFUG-s4M/R_HkzLp3N-I/AAAAAAAAAC0/YMVE39P3kd4/s320/CircleManTestLevel.png" alt="" id="BLOGGER_PHOTO_ID_5184176214032988130" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Shown here is my little test level.  The absense of a clear cut or even sensible strategy should be a dead giveaway.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/797915066036126733-3956011717229418689?l=dev.chadgodsey.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dev.chadgodsey.com/feeds/3956011717229418689/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=797915066036126733&amp;postID=3956011717229418689' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/797915066036126733/posts/default/3956011717229418689'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/797915066036126733/posts/default/3956011717229418689'/><link rel='alternate' type='text/html' href='http://dev.chadgodsey.com/2008/04/refactoring-and-moving-towards-level.html' title='Refactoring, and moving towards level design'/><author><name>ChadyG</name><uri>http://www.blogger.com/profile/08145056828075854965</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/_j16AFUG-s4M/S5iMDwC0CjI/AAAAAAAAA64/LOQ0XG-35Ow/S220/IMG_0160.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_j16AFUG-s4M/R_Hkl7p3N9I/AAAAAAAAACs/ehLNMBqxoRc/s72-c/CircleManTitle.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-797915066036126733.post-2470555693113084281</id><published>2008-03-25T21:42:00.010-05:00</published><updated>2008-04-05T21:42:09.055-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='MUGD circle game'/><title type='text'>Circle Man</title><content type='html'>Finally, spring break is here and I can devote some time to game development!&lt;br /&gt;&lt;br /&gt;This semester has me fairly busy with web development, fuzzy inference output analysis, and so on.  Which is why I'm excited to start working with &lt;a href="http://code.google.com/p/gosu/"&gt;Gosu&lt;/a&gt; to build some quick PC games.  This project is also going to use Erin Catto's &lt;a href="http://www.box2d.org/"&gt;Box2D&lt;/a&gt; library.  If you are not familiar with either of these, you owe it to yourself to take a look.  Myself and Mike Daly (who worked with me on the DS homebrew 2d physics project) are the only ones working on this project.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_j16AFUG-s4M/R-m-Lrp3N8I/AAAAAAAAACk/LtBaT4GfweY/s1600-h/CircleGameMenu.png"&gt;&lt;img style="cursor: pointer;" src="http://1.bp.blogspot.com/_j16AFUG-s4M/R-m-Lrp3N8I/AAAAAAAAACk/LtBaT4GfweY/s320/CircleGameMenu.png" alt="" id="BLOGGER_PHOTO_ID_5181881954172614594" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;The premise of this game is that you are this stick man stuck in some sort of bubble.  You are able to roll it around, and are for some reason in these environments with wall portions ("interactives") that physically alter your movement.  As of now, there are four types of interactives:&lt;br /&gt;Bounce - propels the player away from the wall&lt;br /&gt;Magnet - alters gravity to pull player toward wall while against it&lt;br /&gt;Push - keeps the player from touching it&lt;br /&gt;Sticky - player will stick to these, and be able to swing from them to access certain areas&lt;br /&gt;With these, we hope to create an interesting play experience.  The goal of the game is to find all of the "keys" (right now I don't care what they are, just that you collect something) to escape from your spherical prison.&lt;br /&gt;&lt;br /&gt;With this project, we finally get to use C++ and test our previously inactive knowledge of the language.  So far, I've established a simple class hierarchy for our levels, player, walls, and "key" objects.  From a brief standpoint, these classes have four main member functions: the constructor, update, render, and destructor.  I'm hoping to keep the high level logic very clean, and keep all the actual play logic inside the classes.  This entails that the level objects handle any and all wall object logic (all physical operations that do not operate on callbacks, and rendering).  There will likely be some helper functions created, and some variants established during the optimization phase of development.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/797915066036126733-2470555693113084281?l=dev.chadgodsey.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dev.chadgodsey.com/feeds/2470555693113084281/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=797915066036126733&amp;postID=2470555693113084281' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/797915066036126733/posts/default/2470555693113084281'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/797915066036126733/posts/default/2470555693113084281'/><link rel='alternate' type='text/html' href='http://dev.chadgodsey.com/2008/03/circle-man.html' title='Circle Man'/><author><name>ChadyG</name><uri>http://www.blogger.com/profile/08145056828075854965</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/_j16AFUG-s4M/S5iMDwC0CjI/AAAAAAAAA64/LOQ0XG-35Ow/S220/IMG_0160.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_j16AFUG-s4M/R-m-Lrp3N8I/AAAAAAAAACk/LtBaT4GfweY/s72-c/CircleGameMenu.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-797915066036126733.post-5301306375964088300</id><published>2008-03-04T22:03:00.003-06:00</published><updated>2008-03-04T22:21:04.467-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby rails web'/><title type='text'>the Web, and its desire to be useful</title><content type='html'>It turns out that this semester is a busy one, leaving me with no time to persue game development (thus far).  In the meantime, I might as well document some of my web development.&lt;br /&gt;Currently, I am working at the &lt;a href="http://www.e-researchcenter.org/"&gt;Center for eResearch&lt;/a&gt; here at Mizzou.  I am basically an intern hired to develop a video sharing web application for the University that will soon go beta.  So far,  I've written Ruby scripts making use of ffmpeg to automate encoding of submitted videos into FLV, MPEG, MP3 and iPod compatable MP4 formats, and a fully functional web application to facilitate sharing.  Here is a quick rundown of the requirements for this application:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Students and Faculty are allowed access and can be granted administration to channels for upload of videos.  Channels are delegated to schools, departments, student groups, major events, among other things.  Only through owning or being a contributor to a channel can you upload video.  Anyone can register an account to subscribe to channels.  A subscription lets you keep up to date with a channel so you know when new videos are uploaded, new events are scheduled and the like.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_j16AFUG-s4M/R84fb3snkkI/AAAAAAAAACU/lmVYfgfXtz4/s1600-h/MUTube.png"&gt;&lt;img style="cursor: pointer;" src="http://3.bp.blogspot.com/_j16AFUG-s4M/R84fb3snkkI/AAAAAAAAACU/lmVYfgfXtz4/s320/MUTube.png" alt="" id="BLOGGER_PHOTO_ID_5174107585563300418" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;As far as technical details, I will briefly discuss those here.  This project is a &lt;a href="http://www.rubyonrails.com/"&gt;Ruby on Rails&lt;/a&gt; project, effectively this means that it is a rapid development, rapid prototyping, web 2.0 eager application.  The one problem with the use of "rapid" here is that this is my first Rails project, so it has taken me six months to build it up this far.  Albeit, I could not have done so much in PHP given my student work schedule (10 hrs/week).  Aside from Rails, we are using MySQL and of course the &lt;a href="http://www.prototypejs.org/"&gt;Prototype&lt;/a&gt; and &lt;a href="http://script.aculo.us/"&gt;Script.aculou.us&lt;/a&gt; Javascript libraries as these are included in Rails.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/797915066036126733-5301306375964088300?l=dev.chadgodsey.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dev.chadgodsey.com/feeds/5301306375964088300/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=797915066036126733&amp;postID=5301306375964088300' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/797915066036126733/posts/default/5301306375964088300'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/797915066036126733/posts/default/5301306375964088300'/><link rel='alternate' type='text/html' href='http://dev.chadgodsey.com/2008/03/web-and-its-desire-to-be-useful.html' title='the Web, and its desire to be useful'/><author><name>ChadyG</name><uri>http://www.blogger.com/profile/08145056828075854965</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/_j16AFUG-s4M/S5iMDwC0CjI/AAAAAAAAA64/LOQ0XG-35Ow/S220/IMG_0160.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_j16AFUG-s4M/R84fb3snkkI/AAAAAAAAACU/lmVYfgfXtz4/s72-c/MUTube.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-797915066036126733.post-6258146356901081045</id><published>2007-12-13T00:38:00.001-06:00</published><updated>2008-04-28T22:31:01.488-05:00</updated><title type='text'></title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_j16AFUG-s4M/R2DWfYIN5iI/AAAAAAAAABU/L9QZHWCldVM/s1600-h/CardboardLandAI1.png"&gt;&lt;img style="cursor: pointer;" src="http://1.bp.blogspot.com/_j16AFUG-s4M/R2DWfYIN5iI/AAAAAAAAABU/L9QZHWCldVM/s320/CardboardLandAI1.png" alt="" id="BLOGGER_PHOTO_ID_5143346608998311458" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;   After some "deliberation", my scissor creatures are now 3 times as large, and 10 times as few.  Doing this allowed me to involve more complex sense and think routines as many many little scissors quickly bogged down the engine.&lt;br /&gt;&lt;br /&gt;   The perception function, only searching for the player, implements a distance check, uses the dot product to determine if the player is in front, and a ray cast to see if the player is not obstructed to determine if we can actually see the player.  While this works very well for initial perception of the player, it can be easy to deceive the AI by running behind it.  To overcome this, I crafted the logic so that when we have been following the player, and they run out of the field of view, we simply check the distance again and maintain pursuit if the player is close enough (most of the time).&lt;br /&gt;&lt;br /&gt;   When the AI is not chasing down the player, it will follow predetermined paths.  Currently, I have 4 of these paths, with two AI spawned on each.  Because of this, and the way that the AI move (quick, but slow to stop) they seem to race around some invisible track.  In a way, this comes across as a game that the scissors play normally.  The screen shot below shows one of these paths with the AI running about.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_j16AFUG-s4M/R2DWgYIN5jI/AAAAAAAAABc/uAUMZyUU8Nw/s1600-h/CardboardLandAI2.png"&gt;&lt;img style="cursor: pointer;" src="http://1.bp.blogspot.com/_j16AFUG-s4M/R2DWgYIN5jI/AAAAAAAAABc/uAUMZyUU8Nw/s320/CardboardLandAI2.png" alt="" id="BLOGGER_PHOTO_ID_5143346626178180658" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Within the AI, I have 4 important functions.&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;The first, "think", is a scheduled routine that calls the sensory "checkFOVPlayer", then carries out the simple finite state automata.  The FSA has two states, following the player, and not following the player.  The states are guided simply by whether or not the AI can "see" the player (or if it has "forgotten" where the player is, see above).  &lt;/li&gt;&lt;br /&gt;&lt;li&gt;The second, "checkFOVPlayer", determines if the player is in the field of view of the AI.  It is explained in some detail above, and is included below.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;The "onCollision" callback event is being used for attacking the player.  When the AI rams into the player, it will push them both apart and damage the player.  Very simple response, but it is effective.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;The last, "onReachDestination", is another callback which is triggered when the engine finishes moving the object to its destination.  When this occurs, and the AI is not following the player (running the track), it will iterate to the next node and let the engine move us to the next node.&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;function scissorbody::checkFOVPlayer(%this,%obj) {&lt;br /&gt; %line = VectorSub(%obj.player.getPosition(),%obj.getPosition());&lt;br /&gt; //%dist = VectorLen(%line);&lt;br /&gt; %dist = manhattanDistance(%line);&lt;br /&gt; %cantsee = true;&lt;br /&gt; if (%dist &lt; dot =" VectorDot(%obj.getEyeVector(),%line);"&gt; 0.0) {&lt;br /&gt;     %typemask = %TypeMasks::TerrainObjectType &amp;amp; $TypeMasks::StaticShapeObjectType;&lt;br /&gt;     if (ContainerRayCast(%obj.getPosition(),%obj.player.getPosition(),%typemask) $= 0) {&lt;br /&gt;       %obj.setMoveDestination(%obj.player.getPosition(),true);&lt;br /&gt;       %obj.followPlayer = true;&lt;br /&gt;       %cantsee = false;&lt;br /&gt;     }&lt;br /&gt;   }&lt;br /&gt; }&lt;br /&gt; if (%cantsee &amp;amp;&amp;amp; ($dist &gt; 30)) {&lt;br /&gt;   %obj.followPlayer = false;&lt;br /&gt;   %obj.stop();  &lt;br /&gt; }&lt;br /&gt;}&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/797915066036126733-6258146356901081045?l=dev.chadgodsey.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dev.chadgodsey.com/feeds/6258146356901081045/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=797915066036126733&amp;postID=6258146356901081045' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/797915066036126733/posts/default/6258146356901081045'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/797915066036126733/posts/default/6258146356901081045'/><link rel='alternate' type='text/html' href='http://dev.chadgodsey.com/2007/12/after-some-deliberation-my-scissor.html' title=''/><author><name>ChadyG</name><uri>http://www.blogger.com/profile/08145056828075854965</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/_j16AFUG-s4M/S5iMDwC0CjI/AAAAAAAAA64/LOQ0XG-35Ow/S220/IMG_0160.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_j16AFUG-s4M/R2DWfYIN5iI/AAAAAAAAABU/L9QZHWCldVM/s72-c/CardboardLandAI1.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-797915066036126733.post-7927307283349030087</id><published>2007-12-03T14:27:00.001-06:00</published><updated>2007-12-03T14:52:15.262-06:00</updated><title type='text'>Scissor AI</title><content type='html'>Before I talk about AI and my current progress, I'll say that I made myself a nice little function to warp my character around the map by right clicking on it.  Nothing big, but it sure is helpful.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_j16AFUG-s4M/R1Rpe4IN5ZI/AAAAAAAAAAM/YYQHOhGPgSg/s1600-R/ImpendingDoom.png"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://3.bp.blogspot.com/_j16AFUG-s4M/R1Rpe4IN5ZI/AAAAAAAAAAM/9glPiZJ7o0o/s320/ImpendingDoom.png" alt="" id="BLOGGER_PHOTO_ID_5139849053920421266" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Alright, so the main antagonist to the boxman character is a race of scissor people.  Fitting, right?  Now, they don't need to be all that intelligent, basically just chase the player out of their area and chop him up.  Ancillary behaviour is to just roam around (with some range of speed to establish different amounts of "determination") and probably have them sometimes fight amongst themselves, as they are vicious scissors.  I would also like them to have a very simple learning scheme where they are capable of mapping limited states to good or bad outcomes (mostly just to learn that walking into water is bad, and possibly that a player carrying a rock is bad).  I figure I can establish this by having limited state knowledge (where am I? is the player nearby? does the player have a weapon?), then by examining immediate outcomes, downplay states with negative outcome for a short time.&lt;br /&gt;&lt;br /&gt;As it stands now, I've got some simple reflex agents that will watch for the player and charge them when they show up in the line of sight.  The problem is that I'm using built in functions that set the aim object, which just happens to cause the AI to literally stare at the player no matter where they are.  This is not the behaviour I want, they cannot be aware of the player at all times, they must happen to see the player then charge.  To do this, I will have to build my own sight sensor function.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_j16AFUG-s4M/R1RqyIIN5aI/AAAAAAAAAAU/sKPAkI-43tM/s1600-R/Cluster02.png"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://4.bp.blogspot.com/_j16AFUG-s4M/R1RqyIIN5aI/AAAAAAAAAAU/iBJYuL6Dk2U/s320/Cluster02.png" alt="" id="BLOGGER_PHOTO_ID_5139850484144530850" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;This morning, I was toying around with placement of the scissor race.  I placed a marker out in the field and randomly placed n(100 now) scissor people around this marker.  I soon found that when I let them all come at me, an interesting cluster pattern appears due to the collision amongst them.  While this looks pretty cool, the collision also causes the player to become stuck.  Immediately I thought I could overcome this by removing the collision between player objects.  Of course, this caused the AI to combine on the field.  It also did something crazy to the dynamic shadows produced for the AI shapes.  You can see in the image that there is a yellow glow on the shadow.  This is certainly not a desired effect, so I believe I will have to do something else to fix the sticking of the player.  I'm thinking to just have the scissor people bounce off of the player, or the player from the AI or both.  &lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_j16AFUG-s4M/R1RrmYIN5bI/AAAAAAAAAAc/6NmE2M--I0I/s1600-R/Shadow03.png"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://1.bp.blogspot.com/_j16AFUG-s4M/R1RrmYIN5bI/AAAAAAAAAAc/ayBCC9G39aE/s320/Shadow03.png" alt="" id="BLOGGER_PHOTO_ID_5139851381792695730" border="0" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/797915066036126733-7927307283349030087?l=dev.chadgodsey.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dev.chadgodsey.com/feeds/7927307283349030087/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=797915066036126733&amp;postID=7927307283349030087' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/797915066036126733/posts/default/7927307283349030087'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/797915066036126733/posts/default/7927307283349030087'/><link rel='alternate' type='text/html' href='http://dev.chadgodsey.com/2007/12/scissor-ai.html' title='Scissor AI'/><author><name>ChadyG</name><uri>http://www.blogger.com/profile/08145056828075854965</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/_j16AFUG-s4M/S5iMDwC0CjI/AAAAAAAAA64/LOQ0XG-35Ow/S220/IMG_0160.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_j16AFUG-s4M/R1Rpe4IN5ZI/AAAAAAAAAAM/9glPiZJ7o0o/s72-c/ImpendingDoom.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-797915066036126733.post-3735511430069301517</id><published>2007-11-08T21:52:00.000-06:00</published><updated>2007-12-03T14:54:28.897-06:00</updated><title type='text'>Main menu</title><content type='html'>Ok, so this isn't a huge update, but there's some interesting things to say.&lt;br /&gt;&lt;br /&gt;I changed my main menu from using plain old buttons to shiny bitmap buttons, and then had the brilliant idea to add a sprite animation just because I could.  I made some little sprites of my box man walking (from the side, flipped horizontally instead of rendering twice for each step) and standing still (facing forward), so I could make him walk to the button you were hovering over.&lt;br /&gt;&lt;br /&gt;Actually, I started out wanting to make an animated cursor.  So that he would "walk" as you moved left and right.  But the only way I could get the mouse position was to place a GuiMouseEventCtrl over the entire gui, which effectively blocks all other items.  That's when I decide to just have him walk at the bottom by the buttons.&lt;br /&gt;&lt;br /&gt;To do this, I needed some of those GuiMouseEventCtrls to tell me when I moused over the buttons (the buttons themselves don't lend you any events).  I found that if I nested the buttons inside the controls, I could get them both to work just fine.  So, I used the controls to set the desired x position of the boxman (it's relative to the screensize, so it won't go nuts if you use a different resolution).&lt;br /&gt;&lt;br /&gt;For the animation, I have a scheduled function that runs every 50 miliseconds (shown below) that checks the sprite's x position (held in a global variable, oh my!) to the desired x position and decides whether he should be walking somewhere or not.  The animation is done via numbered sprites and string concatenation, and a counter.  Since I only have 4 sprites per animation, I crafted another counter so that the sprite step would occur every 10 times this function runs.&lt;br /&gt;&lt;br /&gt;Anyway, here's the code and a picture.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;$mouseAnim = 1;&lt;br /&gt;$mouseXPos = 60;&lt;br /&gt;$animCounter = 10;&lt;br /&gt;&lt;br /&gt;function mouseUpdate() {&lt;br /&gt;if ($mouseXPos &gt; 0) {&lt;br /&gt;%boxPos = GetWord(BoxManBitmap.position,0);&lt;br /&gt;%boxYPos = GetWord(BoxManBitmap.position,1);&lt;br /&gt;if (mAbs(%boxPos - $mouseXPos) &lt; position =" SetWord(BoxManBitmap.position,0,%boxPos+5);"&gt; $mouseXPos) {&lt;br /&gt;  BoxManBitmap.position = SetWord(BoxManBitmap.position,0,%boxPos-5);&lt;br /&gt;  BoxManBitmap.setBitmap("ChadGame/client/ui/gfx/BoxManWalk_L"@$mouseAnim@".png",false);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;$animCounter -= 1;&lt;br /&gt;if ($animCounter &lt; animcounter =" 10;" mouseanim =" ($mouseAnim-1)%4+1;" mousexpos =" 60;" mousexpos =" -1;" pos =" VectorAdd(playArea.position,VectorScale(playArea.extent,.5));" mousexpos =" GetWord(%Pos,0)-60;" pos =" VectorAdd(optionArea.position,VectorScale(optionArea.extent,.5));" mousexpos =" GetWord(%Pos,0)-55;" pos =" VectorAdd(quitArea.position,VectorScale(quitArea.extent,.5));" mousexpos =" GetWord(%Pos,0)-40;"&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_j16AFUG-s4M/R1Rs6oIN5cI/AAAAAAAAAAk/JFPe1YFkEbs/s1600-R/CardboardMenu.png"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://2.bp.blogspot.com/_j16AFUG-s4M/R1Rs6oIN5cI/AAAAAAAAAAk/Vk0K5EKS464/s320/CardboardMenu.png" alt="" id="BLOGGER_PHOTO_ID_5139852829196674498" border="0" /&gt;&lt;/a&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/797915066036126733-3735511430069301517?l=dev.chadgodsey.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dev.chadgodsey.com/feeds/3735511430069301517/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=797915066036126733&amp;postID=3735511430069301517' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/797915066036126733/posts/default/3735511430069301517'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/797915066036126733/posts/default/3735511430069301517'/><link rel='alternate' type='text/html' href='http://dev.chadgodsey.com/2007/11/main-menu.html' title='Main menu'/><author><name>ChadyG</name><uri>http://www.blogger.com/profile/08145056828075854965</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/_j16AFUG-s4M/S5iMDwC0CjI/AAAAAAAAA64/LOQ0XG-35Ow/S220/IMG_0160.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_j16AFUG-s4M/R1Rs6oIN5cI/AAAAAAAAAAk/Vk0K5EKS464/s72-c/CardboardMenu.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-797915066036126733.post-3704516564916264446</id><published>2007-10-25T16:46:00.000-05:00</published><updated>2007-12-03T14:59:24.078-06:00</updated><title type='text'>Catching up on Cardboard Land</title><content type='html'>It might be useful to explain this project for anyone trying to figure out what my various mind dumps are all about.&lt;br /&gt;&lt;br /&gt;Cardboard Land is a simple game where you are a cardboard man living in a world of cardboard.  It is up to you to venture out from the safety of your village to find supplies.  You must find as many as possible across the lands.  These supplies are objects such as; glue, staplers, tape, paper clips, etc..  On your adventure you will encounter disastrous adversaries, such as; scissor people, water, tornados, huge piles of chewed gum, and possibly fire people.&lt;br /&gt;&lt;br /&gt;Simple enough, I suppose.  Here are some of my favorite screenshots so far.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_j16AFUG-s4M/R1RtOIIN5dI/AAAAAAAAAAs/ifvx8-Q5uQE/s1600-R/CardboardNew1.png"&gt;&lt;img style="cursor: pointer;" src="http://4.bp.blogspot.com/_j16AFUG-s4M/R1RtOIIN5dI/AAAAAAAAAAs/cZVwH3yU0E4/s320/CardboardNew1.png" alt="" id="BLOGGER_PHOTO_ID_5139853164204123602" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_j16AFUG-s4M/R1Rth4IN5fI/AAAAAAAAAA8/QJIR8LIudw8/s1600-R/CardboardNew3.png"&gt;&lt;img style="cursor: pointer;" src="http://3.bp.blogspot.com/_j16AFUG-s4M/R1Rth4IN5fI/AAAAAAAAAA8/mu9nj8Gxg2Y/s320/CardboardNew3.png" alt="" id="BLOGGER_PHOTO_ID_5139853503506540018" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_j16AFUG-s4M/R1RtXoIN5eI/AAAAAAAAAA0/GB_ilVjI694/s1600-R/CardboardNew2.png"&gt;&lt;img style="cursor: pointer;" src="http://2.bp.blogspot.com/_j16AFUG-s4M/R1RtXoIN5eI/AAAAAAAAAA0/sDb4GUiEYvs/s320/CardboardNew2.png" alt="" id="BLOGGER_PHOTO_ID_5139853327412880866" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_j16AFUG-s4M/R1Rt4IIN5gI/AAAAAAAAABE/ggzkqhn05bY/s1600-R/CardboardNew4.png"&gt;&lt;img style="cursor: pointer;" src="http://4.bp.blogspot.com/_j16AFUG-s4M/R1Rt4IIN5gI/AAAAAAAAABE/xzp-f3QEty0/s320/CardboardNew4.png" alt="" id="BLOGGER_PHOTO_ID_5139853885758629378" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_j16AFUG-s4M/R1RuFoIN5hI/AAAAAAAAABM/hff71stbrjI/s1600-R/CardboardNew5.png"&gt;&lt;img style="cursor:pointer; cursor:hand;" src="http://2.bp.blogspot.com/_j16AFUG-s4M/R1RuFoIN5hI/AAAAAAAAABM/Dwr3yDOe2YU/s320/CardboardNew5.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5139854117686863378" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Stay tuned for more real information as it occurs.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/797915066036126733-3704516564916264446?l=dev.chadgodsey.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dev.chadgodsey.com/feeds/3704516564916264446/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=797915066036126733&amp;postID=3704516564916264446' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/797915066036126733/posts/default/3704516564916264446'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/797915066036126733/posts/default/3704516564916264446'/><link rel='alternate' type='text/html' href='http://dev.chadgodsey.com/2007/10/catching-up-on-cardboard-land.html' title='Catching up on Cardboard Land'/><author><name>ChadyG</name><uri>http://www.blogger.com/profile/08145056828075854965</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/_j16AFUG-s4M/S5iMDwC0CjI/AAAAAAAAA64/LOQ0XG-35Ow/S220/IMG_0160.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_j16AFUG-s4M/R1RtOIIN5dI/AAAAAAAAAAs/cZVwH3yU0E4/s72-c/CardboardNew1.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-797915066036126733.post-8860796405078113212</id><published>2007-10-23T23:22:00.000-05:00</published><updated>2007-10-23T23:35:59.053-05:00</updated><title type='text'>Tornados in Cardboard Land</title><content type='html'>I started working on a wind area trigger within torquescript, and ended up creating a tornado because that is a fairly interesting effect to recreate.  As this is a fairly short script, I'll just paste it here with all my comments and possibly add some stuff. &lt;br /&gt;    The flow is this: I create a trigger of my defined type, which should call the onAdd callback to initialise my tornado shape and particle emitter.  However, somehow the onAdd isn't being called, so I'm just doing it explicitly.  There are two main features of this script, a loop that runs every 50 ms when a player is intersecting my trigger, which takes the difference in positions between the player and trigger, then uses that information to build up some impulse vectors to pull the player in, and spin him around the z axis of my trigger.  The second loop is independent of intersection, and is used to move the object around in a random manner.  I created a momentum vector for the XY plane to keep the thing from just jumping around, and devised an "adjustment" vector to pull it towards the initial position if we stray too far from there. &lt;br /&gt;&lt;br /&gt;Here are the two important functions:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;function WindTrigger::onTickTrigger(%this,%trigger) {&lt;br /&gt;  %max = %trigger.getNumObjects();&lt;br /&gt;  for (%n=0;%n&lt;%max;%n++) {&lt;br /&gt;    %obj = %trigger.getObject(%n);&lt;br /&gt;    if (%obj.getClassName() $= "Player") {&lt;br /&gt;      //find XY distance to player&lt;br /&gt;      %pos = VectorSub(%obj.getPosition(),%trigger.getWorldBoxCenter());&lt;br /&gt;      %posX = getWord(%pos,0);&lt;br /&gt;      %posY = getWord(%pos,1);&lt;br /&gt;      %dist = VectorLen(VectorNormalize(setWord(%pos, 2, "0.0")));&lt;br /&gt;      //calculate circular tangent vector and apply centripetal force to maintain circular movement&lt;br /&gt;      %windX = -%posY - 5*%posX;//mSin(%posX)*mCos(%posY);&lt;br /&gt;      %windY = %posX - 5*%posY;//mSin(%posY)*mCos(%posZ);&lt;br /&gt;      %windZ = 10;//mSin(%posZ)*mCos(%posX);&lt;br /&gt;      %obj.applyImpulse(%obj.getPosition(),VectorScale(%windX SPC %windY SPC %windZ,100*(1.5-%dist)));&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;  Parent::onTickTrigger(%this,%trigger);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;function WindTrigger::moveMe(%this,%trigger) {&lt;br /&gt;  //get our scale&lt;br /&gt;  %scale = %trigger.getScale();&lt;br /&gt;  %scaleX = getWord(%scale,0);&lt;br /&gt;  %scaleY = getWord(%scale,1);&lt;br /&gt; &lt;br /&gt;  //compute an adjustment vector to apply on top of&lt;br /&gt;  //our movement to keep within some distance of original position&lt;br /&gt;  %pos = %trigger.getPosition();&lt;br /&gt;  %adjustment = VectorSub(%trigger.startPos,%pos);&lt;br /&gt;  %adjDist = VectorLen(%adjustment);&lt;br /&gt;  %adjustment = VectorNormalize(%adjustment);&lt;br /&gt;  %adjX = 0;&lt;br /&gt;  %adjY = 0;&lt;br /&gt;  //stay within 25 units of original position (or try to)&lt;br /&gt;  if (%adjDist &gt; 25) {&lt;br /&gt;    %adjX = getWord(%adjustment,0);&lt;br /&gt;    %adjY = getWord(%adjustment,1);&lt;br /&gt;  }&lt;br /&gt; &lt;br /&gt;  //random(-.25,.25) with a step of .01&lt;br /&gt;  %trigger.mvX += getRandom(-25,25)/100.0 + %adjX;&lt;br /&gt;  %trigger.mvY += getRandom(-25,25)/100.0 + %adjY;&lt;br /&gt;  //cap movement to [-1,1]&lt;br /&gt;  if (%trigger.mvX &lt;= -1)&lt;br /&gt;    %trigger.mvX = -1;&lt;br /&gt;  if (%trigger.mvX &gt;= 1)&lt;br /&gt;    %trigger.mvX = 1;&lt;br /&gt;   &lt;br /&gt;  if (%trigger.mvY &lt;= -1)&lt;br /&gt;    %trigger.mvY = -1;&lt;br /&gt;  if (%trigger.mvY &gt;= 1)&lt;br /&gt;    %trigger.mvY = 1;&lt;br /&gt;   &lt;br /&gt;  //find our new position&lt;br /&gt;  %posX = getWord(%pos,0)+%trigger.mvX;&lt;br /&gt;  %posY = getWord(%pos,1)+%trigger.mvY;&lt;br /&gt;  %posZ = getTerrainHeight(%posX+5 SPC %posY-5);&lt;br /&gt; &lt;br /&gt;  //move trigger&lt;br /&gt;  %trigger.position = (%posX) SPC (%posY) SPC %posZ;&lt;br /&gt;  %trigger.setScale(%trigger.getScale());&lt;br /&gt; &lt;br /&gt;  //adjust to center for inner objects&lt;br /&gt;  %posX += %scaleX/2;&lt;br /&gt;  %posY -= %scaleY/2;&lt;br /&gt;  %pos = %posX SPC %posY SPC %posZ;&lt;br /&gt; &lt;br /&gt;  //update StaticShape and ParticleEmitter positions&lt;br /&gt;  %trigger.myTornado.position = %pos;&lt;br /&gt;  %trigger.myTornado.setScale(%trigger.myTornado.getScale());&lt;br /&gt;  %trigger.myParticles.position = %pos;&lt;br /&gt;  %trigger.myParticles.setScale(%trigger.myParticles.getScale());&lt;br /&gt; &lt;br /&gt;  //make sure we get called again&lt;br /&gt;  %this.schedule(100,"moveMe",%trigger);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;It works pretty well, but I haven't added anything to turn off all this simulation when the player is not near the tornado area.  I think I may just put a large trigger around the area to enable/disable the tornado set when the player enters and leaves the area.  I'll have to play around with this to see if it is sufficiently useable, otherwise I might need to turn down the delays so it doesn't use up as much resources.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/797915066036126733-8860796405078113212?l=dev.chadgodsey.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dev.chadgodsey.com/feeds/8860796405078113212/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=797915066036126733&amp;postID=8860796405078113212' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/797915066036126733/posts/default/8860796405078113212'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/797915066036126733/posts/default/8860796405078113212'/><link rel='alternate' type='text/html' href='http://dev.chadgodsey.com/2007/10/tornados-in-cardboard-land.html' title='Tornados in Cardboard Land'/><author><name>ChadyG</name><uri>http://www.blogger.com/profile/08145056828075854965</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/_j16AFUG-s4M/S5iMDwC0CjI/AAAAAAAAA64/LOQ0XG-35Ow/S220/IMG_0160.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-797915066036126733.post-5958922209408986759</id><published>2007-10-23T23:04:00.000-05:00</published><updated>2007-10-23T23:06:58.506-05:00</updated><title type='text'>Primer</title><content type='html'>Well, I guess I should start documenting my development in ways other than filling up my desk with post-it notes.  So, this place is as good as any.  I believe I will start with my Cardboard Land game, and just go from there instead of trying to catch up (and remember various thoughts that have slipped through the cracks).  So stay tuned, listeners (haha, radio) for information will establish itself right here.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/797915066036126733-5958922209408986759?l=dev.chadgodsey.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dev.chadgodsey.com/feeds/5958922209408986759/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=797915066036126733&amp;postID=5958922209408986759' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/797915066036126733/posts/default/5958922209408986759'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/797915066036126733/posts/default/5958922209408986759'/><link rel='alternate' type='text/html' href='http://dev.chadgodsey.com/2007/10/primer.html' title='Primer'/><author><name>ChadyG</name><uri>http://www.blogger.com/profile/08145056828075854965</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/_j16AFUG-s4M/S5iMDwC0CjI/AAAAAAAAA64/LOQ0XG-35Ow/S220/IMG_0160.jpg'/></author><thr:total>0</thr:total></entry></feed>
