Showing posts with label ramble. Show all posts
Showing posts with label ramble. Show all posts

Thursday, 8 March 2012

Out With The Old...Part Two

Man am I not very good at keeping up with blog posts. Apologies. So here we go, part two of what I changed about a month ago, and case you've forgotten what this was all about here's part one to remind yourself.

What's Changed

Tiles and their interfaces
How It Was: Interfaces are great. They are C sharps answer to multiple inheritance (granted not a very good one). I used interfaces in order to define my tiles and create some commonality between them. This also means that I can deal with all tiles by just casting to their inherited interfaces and performing code based on the cast interface. An example would be an IAnimatable interface that is applied to all tiles that animate. By casting to this I could animate all animatable tiles.

The problem with this approach was that I was safe casting each tile (using the as keyword) in the level to my main interfaces and then performing interface logic to the tile if the cast was successful. However, this is a very expensive thing to do as I was casting each tile about 5 different times every frame. So what could I do to keep the greatness of interfaces but reduce the expensive calls.

How It Is Now: I have exactly the same interfaces that I had before (plus a few additional ones), but I now have some "cheat" properties on my base interface; ITile. These cheat properties tell me if the given tile implements my main interfaces (e.g. movable, interactable), which are set up during construction of each tile. This means that I no longer have to safe cast in my main game loop, but instead check the respective cheat property, which is just a boolean value and therefore much cheaper and has helped to improve frame rate.

Updating every tile every frame probably isn't the best idea
How It Was: On each update call in my tile engine, I checked collision between the player and each level tile and performed interface specific code on each level tile (using the old method). As you can probably see this can get quite costly, especially when most of the tiles aren't visible to the player because they are off the screen.

How It Is Now: Now whenever the player moves I update a global variable that stores the min and max X and Y co-ordinates. These co-ordinates specify the area of the level that needs updating and drawing. I've currently set this catchment area to two screen widths/heights surrounding the player. Ultimately, this could be further improved by reducing the catchment area for the tiles which are drawn, but as frame rates are holding up there's no need at the moment.

Reducing and refining collision detection checks
How It Was: I used to update the players location, first along the X axis and then along the Y performing AABB and PPC checks against each and every tile in the level for collisions with each change in the players location. Once I built a level of any size, I realised I needed to reduce these checks, so I reduced it down to only be done on the tiles that were visible.

How It Is Now: These checks, while not needing to be reduced due to the first AABB check, were still to much. So I have reduced the number of checks to only tiles that surround the player. However, because not all my tiles are the same size (but multiples of 64 pixels), I needed to increase these checks to surround the player of the greatest tile size on the level. For example if the maximum size of a tile was only 64 pixels, then the checks only need to be done one tile deep around the player. But if the maximum size is 128 pixels then the checks need to be two tiles deep. And this continues, but I'm not going to spell it out to you because you are all probably an intelligent bunch.

What's New!

Yes that's right, not only did I rewrite stuff, but I also produced some new stuff. Well, one new thing. Because I was getting to the point where I was adding new tiles all the time, I needed to update my level descriptions constantly. I also needed to create levels that produced different scenarios to squish a few bugs. My levels are structured as Xml documents, and while being readable were not a joy to edit. So until I've created an in game level editor, I needed an out of game editor. So I've developed a level editor using existing software (*cough* Excel *cough*) for which I then parse the document to create my needed Xml document.

My proposed level in my Excel spreadsheet

The resulting level

As you can see the level editor is very colourful, for which there is a reason behind this madness. Each colour represents a different tile and the contents of the cell describes certain characteristics of that tile (like texture). Considering this editor took my only a few hours to create and is easily updateable for when I create new tiles, I'm pleased. And who knows, maybe I'll get the community (whoever they are) to make levels using this so I can include the levels in future updates. But then again, maybe I'm getting ahead of myself...

Thursday, 9 February 2012

Out With The Old... Part One

As mentioned in my last post over the past month I have pretty much scrapped what I had developed for my platformer and re-designed and re-developed it into a code base that I'm much happier with. Of course, it's not all perfect as there are still some bugs to work out. But I'm at a stage where I'm much happier.

This following post will hopefully give a bit more insight into what's changed on the back end, so the experienced developers can see the pitfalls that I fell in originally and hopefully the new developers can see the pitfalls to avoid. So lets get started.

What's Changed

The Removal Of Individual Textures
How It Was: When I first started developing my plaformer, I was on a coding spree. I was developing new tiles that had different purposes in the game. I had ground tiles that the player walked on, sign post tiles that the player read, collectable tiles that the player, errr, collected. You get the idea.
Each of these tiles had an associated texture (or textures for some things like ground) and each of these textures were seperate files. Now the seasoned developers can see the problem here, and for those that don't you have to understand the way that the graphics device (or possible spritebatch) works. One of these components will batch all calls made with a given texture and process the work load. The fewer batch calls that have to be made, the less work the graphics processor has to do, which results in better frame rates (to a certain extent).

How It Is Now: Following advice that I saw countless times but ignored in the AppHub forums, I decided to put all of my tile textures into a massive texture, also referred to as a sprite sheet. This resulted in less batch calls to the graphics device and helped improve my frame rate problem. In order to achieve this I had to improve my internal base Sprite class to support displaying of areas of a larger texture (now referred to as TextureBoundingArea), but this was a small change. I also had to change the way my texture manager worked, but this was getting changed anyway due to the following problem...

Updating My TextureManager To Be More...Flexable
How It Was: One of the goals of mine was to have multiple textures for given tiles like the ground, but then to also have a number of effects I could apply to that texture to make it appear different but be the same texture. This was done via the texture manager and each tile had a number of different effect collections. These effects only consisted of the in-built SpriteEffects and rotations at 90 degree intervals. The problem came to how I was defining these effect collections. Originally I was defining them in code in a static constructor. While this isn't necessarily a problem, I was finding it one as the code was getting unmanageable the more tiles I added, so I decided to change it.

How It Is Now: My TextureManager has had a rewrite and now contains effect collection information (as well as texture locations) for each tile type in an Xml file. This meant that all initialsing data was seperate to the code (as it should be) and could be easily edited with help of an XML schema. This information is then loaded when a level loads and is stored against the type of each tile. This is done by having a node in the XML that is the name of the tile, for which I use the Type.GetType method passing in the value in the XML node.

Seperating Visual Texture Information From Collision Texture Information
How It Was: The collision system I use for the game is a combination of Axis-Aligned Bounding Boxes (AABB) and Pixel-Perfect-Collision (PPC). This is where collisions between the player and the suspecting tile are checked first against each other bouding boxes. If an intersection appears between them (i.e. where the two boxes cross), PPC is then performed when the overlapping of two texture pixels are checked. The reason this is done is because PPC is an expensive process and only needs to be done when we are 90% sure a collision has occurred. The code for this method was taken from the AppHub where they provide an excellent example (one I even believe has been stolen and made into a WP7 game). This resulted in me having a texture that represented the tile visually as well as being used for collision code. This presented some limitations in my tile design and meant I couldn't do nice visual things like having grass from a ground tile cover the players feet.

How It Is Now: I now have two sprite sheets in my game. One sprite sheet represents the visual-ness of the tiles (now with grass on the ground tile) which can have the visual effects mentioned earlier applied to them. The second sprite sheet represents the collision texture which is used for collision detection and is stored, like the effect collections, against each Tile type. The TextureBoundingAreas then match across both sprtesheets so I only have to define the area once in the XML document. The result of this is two fold; a) I can add visual flair to the visual textures like my wanted grass and b) I can increase the collision area of a tile so that a collision occurs before the player collides with the visual texture (like for an interactive item).

That's it for part one. I'll try and write up part two which will include more changes, some additions and a few things yet to be implmented. Have a good weekend.

Friday, 6 January 2012

New (Year) Update


Hello all! Happy belated new year. Hope your holidays were good. Sorry about the lack of posts, but I've been a bit busy what with going to london to see a comedian, Christmas and a lot of new games to play. While on my christmas break, I was also hoping to make a bit more headway with development, but alas that did not occur. You see, I was at my parents house for christmas. So I decided to grab all the code I needed off my desktop and put it on a pen stick so I could work on my laptop. However, I'm a bit stupid and instead copied the data over and then left the pen stick in the computer. Whoops!

However, before the holidays I did manage to track down what was causing the low framerates (as mentioned in my previous post). After downloading a few profiling tools I determined that none of my code should be causing significant slow down. So I searched the XNA forums for low framerate which brought up a post by Shawn Hargreaves that stated that IsFixedTimeStep should be set to false on the 360. I tried this and found out my game was in fact running at about 36 FPS (using my FrameRate counter). Which is a lot nicer than the 2 I was previously getting. Lesson Learnt. As for what is causing this framerate I do believe its my design by having lots of interface casting every frame, which means at some point in the future I may want to rethink this approach.

I've also learnt that Windows Phone will be included in the next Dream.Build.Play contest; a contest I have yet to enter. This has lead me to thinking about ideas that I may submit (if time permits), which I will share if they come into fruitation.

My objective for the weekend is to get Xbox 360 avatars implemented into the game with hopefully some animation (probably using the sample on the App Hub). I will also hopefully make some more headway on the promised code sample, which is being a bit more complicated to talk about than I thought (hard to describe my method of madness).