Unfortunately, I didn’t think of it in time for the competition, but either way, I just had to make this once I thought of it
You are the Yeti is a “just for fun” entry in to LD48 #25 – You Are The Villian. It is quite clearly inspired by the classic game SkiFree.
It is playable at the following page
Ninjah is now available for $2.99 via the Ubuntu Software Centre! Version 1.1.2 is current version on there, but I will look to update it soon. $2.99 is the minimum price I could select, so that's the reasoning there.
If I am honest, I wasn't expecting it to be accepted! I assumed some issues would appear and the more experienced Linux users who perform the QA process would find something or other that was wrong, but they didn't!
So here you go, Ninjah on the Ubuntu Software Centre.
A new version of Ninjah is available from the download page featuring the following minor changes...
25/10/2012 - v1.1.4
Bug Fix / Feature
Music playback now uses memory based streaming of oggs
which should result no more 2 second pauses between tracks!
23/10/2012 - v1.1.3
Arrow keys can be used for movement (instead of just WASD)
Credits screen behaving badly
Just unzip the contents over your current Ninjah installation directory
I have released Ninjah for Windows ( XP / Vista / 7 ) and it is available for purchase at the Ninjah Mini Site for $0.99 via paypal!
Wow, three months since my last post. That's bad.
Three months a go I was deep in to working on Perling and things were going really well! But...I think I must've burnt out though because by the end of July I had very little motivation and even less energy. To an extent I've always tried to force myself to make progress, but I broke. I broke big time! I went back to my parents for a few days with the hope of making lots of progress, but I did nothing at all and in all honestly I probably needed it!
So since July 11th I've actually not done much game development, that is until a couple of weeks ago. "So you've made lots of progress with Perling right???" no, barely any I am afraid, but I have been working on getting Ninjah ready for Windows, OSX and Linux.
Ninjah was originally created for XNA with the Xbox 360 in mind and while it was possible to distribute for PC, I wasn't entirely comfortable with the installation process or the way it handles media, specifically licensed music. Anyway, a group of people who were generous enough to give their time and talented enough to get it working have almost entirely ported Monkey so it can build for the Blitz Max programming language (brilliant for Windows, OSX and Linux games!). The project is called MonkeyMax and as far as Ninjah is concerned it runs flawlessly
I had always hoped the BlitzMax target would appear, but never really knew when it'd happen so didn't think about it too much. The great thing about it is, you can bundle everything in to a single executable file which is perfect for me, especially as I am hoping to distribute it myself.
I will be selling Ninjah for Windows (and soon to be OSX and Linux too) for $0.99 via paypal. More information is available via the Ninjah Mini Site. You buy once and you get it for all three platforms as they become available. I feel like I am in some sort of limbo at the moment where I know deep down Ninjah for Windows is ready, but because I am selling it directly from my site and there's no peer review system like there is for XBLIG I feel a bit more vulnerable about releasing a product that might not work for some people (not that I actually think it won't work!).
I'm all ready to go, I have press releases written, contacts listed and media ready, I guess I just need to man up and release it! ... but maybe I will wait to hear back from a few more testers before I go... :S
OSX and Linux
I don't own a Mac, but a friend who also has BlitzMax (and more importantly a Mac) has been able to build and test it for me and everything appears smooth and fine. I need some clarification on where I should be storing save data, but apart from that I am happy. For Linux I have got it built just fine and have even created a debian package for proper distribution, but I dunno... with Linux I never quite know how confident I am about it working for people. I think I will have to release it and hope people are understanding if something's not quite right.
I'd rather not fire fight issues with 3 OS's at a time, so I will release the Windows version first, give it a while to settle, then concentrate on the Linux release and finally the OSX release. I'm leaving the OSX release until last because I am less able to fix things for it (I can't justify buying a Mac just yet) so I will hope that any problems surface for Windows and Linux first.
Thanks for reading
if you do 2d sprite work I can't recommend enough that you give ASEPRITE a look. It's a feature rich but easy to use pixel editor which caters for multiple layers as well as animations.
I really don't enjoy doing graphics. 1) Because I am not very good at it and 2) because it's always fiddly work, especially if you're doing pixel based sprites (which I am with Perling). Aseprite seems to remove most, if not all of the pain. To me, it's to graphics as Notepad++ is to text; a really well made app that does exactly what I need. Once you get to grips with the key shortcuts ( Aseprite Reference PDF ) you're away! It has it's own file format but can export to PNG based sprite sheets as well.
Best of all is, it's open source and free! Give it a try, and if you find it useful, be sure to leave a donation (which you can do from the download page).
I've got it installed in my Dropbox, which is great for doing little bits during my lunch break at work.
That is all!
I am really happy with the new map format. I had expected it to make things easier but didn't really know what that'd translate to in practice. Well having been able to use the new changes this weekend, I can safely say that it translates very well.
I've only added two layers so far. Mud which will be found in marsh areas and pathways which can go throughout the whole level. The important part (in my opinion) is that adding each layer look around 30 minutes, and most of that time went towards editing the map tileset (which always takes me ages...). I was also very quickly able to implement an alternative MapUnitTile (MapUnitTileAnimated) which allowed me to quickly add some basic animations to certain layers. In my test example I could randomly trigger a ripple effect in the deep water layer.
I hadn't thought of it until now, but I can use this system to very quickly add a designated shadow layer which can draw the shadows to add a bit of depth. I've got plenty of idea for other layers I am yet to implement too, but figure I now need to do some more actual game play stuff.
So, the game play... I've been neglecting it recently and spending a lot of time getting the bare minimum code/graphics in place for the in game items. Feeling quite content with my map progress I decided I better make a decent effort to get the quest generation process going and it turns out it is as complicated as I had expected.
I want each level to have a series of randomly generated quests. These quests are optional, but the more quests completed when leaving a level, the higher your XP multiplier is (XP will be used to unlock more features in game). Quests are generated based on three things..
- The world features (does it have much water? Are all areas easily accessible)
- The items available at the start of the level (e.g. quests involving coins can only happen if there are coins at the start)
- What the available items are capable of (e.g. a squirrel can be burned / drowned / confused / loved / hit / captured etc)
Items 1 and 2 are obviously decided during the generation process but I've opted to manually do the third part via a CSV file. This is simply because I imagine it's much easier for me to just decide what these items can do instead of trying to get clever about it.
I am at a stage where I can check specifically if a quest is possible (e.g. Collect at least 50 coins) but I am yet to decide how the system will go about selecting the quests. I've not thought about it too much, but I guess I need to randomly select some possible quests and then give them a difficultly rating some how! It sounds like it could get quite complicated, but I really want to guarantee that as many levels as possible are a lot of fun to play (funnily enough though, I almost think it's important that some of the levels are a bit pants as well, to help with the sense of satisfaction of finding a good level).
Right now I am specifically setting the quests at the start, but even then it at last allows me to make use of the wonderful voice work that Wiggly has kindly recorded for me
It needs some tweaking, but it's getting there.
Yesterday I posted about the first real time I've felt out of control of something while coding Perling. Luckily it wasn't for long and I am now very much in control of what's going on again. Below I will describe the issues raised in the previous post and what the new system does to rectify them.
The new system which is new and great and not old and rubbish
Issue 1 : Unnecessary instance creation
The world is no longer a 3d array but a 2d one which houses a MapUnit class. The MapUnit class can draw 1 or more sub tiles and again, this is calculated to mean as few tiles are drawn as required. The only areas of the map where more than one sub tile draw is needed, is at a boundary (e.g. grass changing to sand). Normally the tile will be a solid 16x16 square without any gaps, and so, there is no need to draw or even check behind this tile. The MapUnit holds a list of MapUnitTiles and a list is a very simple and efficient way of storing information. There is no iteration through unnecessary instances so there is no per instance testing required, I can just assume all items added to this list are required.
So this change means I go from 640,000 instances on a 400x200 map, to around 88,000 (obviously this can change on a per map basis).
Issue 2 : Unnecessary variables per MapTile
I was storing all sorts of crap in the MapTile class because I thought it'd be useful but in reality the only thing I was making use of was the IsVisible:Bool and the drawing coordinates. I say drawing coordinates, but really I was storing variables that were used to calculate the drawing coordinates each and every frame... even though they won't ever change. I guess it seemed like a good idea at the time, but really it's a bit amateur when I think about it now.
The new system stores two variables per MapUnitTile, DX:Int and DY:Int. These describe which part of the sprite atlas to draw. As all tiles are 16x16 I do not need to store this information. To future proof myself, when and if I need to do more complicated drawing commands (e.g. animated shore line), I will extend the MapUnitTile object with a MapUnitTileAnimiated class. As long as both classes have a Draw() method, it will have no implication to the parent MapUnit. This is a better way of doing things because I am not saying "each tile could potentially be animated, so I will store animation variables in each of them" I am very specifically saying "this tile is animated, so make it so, else make it a standard 2 variable Map Tile).
At this stage then, I am storing many fewer instances, as well as storing much less information on a per instance basis. Saying that an integer is 4 bytes and a float is 8 bytes (plucking out of the air here but still...) and saying the old system has 15 ints and 3 floats per instance (I'll ignore the bools because I assume they are one bit), the estimated comparison of memory usage is...
Old: ( 400 x 200 x 8 ) x ( ( 15 x 4 ) + ( 3 x 8 )) = 53,760,000 bytes (around 52Mb of memory)
New: ( 400 x 200 x 4*) + ((400 x 200 x 1.1** ) x ( 2 x 4 )) = 1,024,000 bytes (1Mb of memory )***
- * These 4 bytes are for an integer stored in the parent MapUnit object at each map location. It describes the main type of tile on that particular cell (e.g. the upper most one)
- ** As an over cautious calculations I will say on average there are 1.1 MapUnitTiles per MapUnit (probably less though)
- ***The new system does have some memory overhead because of the lists used for the MapUnitTiles but I believe it to be negligible.
Now 52Mb of memory isn't a lot on a PC/Laptop, but on a low end phone it is (and this is ignoring all of the media that gets loaded in to memory!).
Issue 3 : Unnecessary calculations required during generation process and in game
Making a one off calculation process more efficient (e.g. generating the level at the start), isn't as important as one at run time (e.g. interactions between items in game). However from a development perspective, the more simple it is, the better. Because there was no topological summary of each X/Y coordinate, I had to do lots of calculations that probably weren't necessary with a bit of planning. Having a MapUnit at each X/Y coordinate now lets me store some general information.
I store whether the X/Y coordinate in question is an obstacle or not and I store the main type of terrain on that specific MapTile. IsObstacle:Bool is self-explanatory but the MainType:Int lets me state on a per coordinate basis what the tile is. So it could be WATER_DEEP, SAND, LIGHT_GRASS or any of the other terrain types. Doing this allows me to easily check whether a specific item is overlapping a certain type of terrain. A simple example would be "If Item.OnFire = True and Item.IsOver(WATER) = True Then Item.OnFire = false" which extinquishes an item that's on fire, if it's over water. The IsOver() function checks the item against the map to see what it's current on.
Before, I had to go in to each layer of an MData[y][x] coordinate and work out what the tile actually was. Because this now gets done once during the generation process, I save an awful lot of time at the start as well as during run time.
Issue 4 : Not easily extendible
Before, adding a new type of tile (e.g. a desert) would've been a lot of hassle because I had backed myself in to a corner with how things worked. Now though I can easily extend whatever parts are required without having to completely change every existing element. I can extend MapUnits and MapUnitTiles when and if required and the significance in the order of the layers (e.g. Deep water > water > shallow water > sand ...) is, well, insignificant now. It get's worked out during the generation and that's that. I believe the new system will allow me to add things I am not yet aware of... which leads me on to Issue 5.
Issue 5 : It worked so became established
I guess this is still as much of an issue now as it was before. Everything could be just fine for months and then one day I will think "oh... I can't really do this" for a specific feature and be in the same boat. I am yet to have a fully locked down plan for what Perling needs yet, so while I don't know exactly what will be happening, I guess I can't really do anything about this issue and so just ignore it! I've definitely thought more about allowing for the unexpected, but who knows if I have thought about it enough yet?
There we have it. I guess in retrospect this was a good thing. The code is more efficient, the memory usage is WAY more efficient and the framework is now more extendible and generally easier to use. I am a better coder for it and am now better equipped to make Perling as good as possible
Even though "blip" is a pretty pathetic word (even more so when surrounded by quote marks), "blip" is probably too strong of a word for what I've been up to. Regardless it left me with the first strong feeling of "I am losing control of this" with regards to Perling.
So recently I got Perling running on Android via my HTC Desire. I am yet to compress sound files for each target platform and as the game loads them all straight away, I found myself getting out of memory errors. I assumed I had some sort of memory leak, but it wasn't at all, I was literally just trying to cram too much in to memory at one go. It got me thinking about how I store the level data and while I had deemed it OK before, all of a sudden I was extremely unhappy with how wasteful it was.
Oh and before I carry on, I realise I've not actually posted any videos or screen shots here even though I have done elsewhere (usually via ScreenshotSaturday, or my Youtube channel) anyway, here's a photo of Perling running on my HTC Desire. And I will make more of an effort to post media here as well.
Anyway... so I got thinking about the way I store the level data and I wasn't happy with it at all. At this stage I am literally talking the terrain.
Hi there, right...
while I have always been making Perling with it in mind that it will be on multiple platforms, I've not really tried it other than running it as HTML5 or XNA (for Xbox). HTML5 is quite slow (expectedly) but it functions completely as expected.
When Monkey started supporting the PS Vita I very quickly tried it and got the game running with literally no changes required which is amazing. Unfortunately while on the most part the Vita SDK is good, the support for joypads is poor. "Out of the box" you cannot emulate the analogue sticks of the Vita system unless you are testing on an actual PS Vita. Some clever chap over on the PS forums has made a Pad Server that lets you stream in the state of a PC joypad and go from there, but really this shouldn't be necessary and the sooner Sony sort this out the better. That said, once the Pad Server is running, the game runs perfectly, so that's reassuring when/if I get a PS Vita.
Before I had even started Perling, I had planned for it to be playable with touch screen controls. While I don't actually like touch screen "virtual stick" like controls, realistically, it's what I have to aim for if I want any chance of releasing Perling on mobile devices. So I implemented some great Virtual Stick code for Monkey and got the game working very easily again. It stutters a bit (especially when using the SetColor() command) but it works entirely without intervention. Monkey makes it very easy for you to say "For this platform do this... but for Android, do something else". This is great for scaling between different targets. So I can basically say a particle explosion has 50 particles for all platforms, unless it's Android, in which case only make 10. I have a global "Control" class that handles all of the input and it's been made to handle the various platforms without the main game logic needing to be aware of it. Until I attempted running this on Android it was just sat there doing nothing, but I am actually quite proud of myself for having the foresight to implement it in the way I did, I know it has saved me a lot of grief now!
PC / Mac / Linux
While I know I can get Perling working on a PC using XNA, I've not actively made any effort to get the game running on Mac or Linux. I was aware the GLFW target would allow for these platforms, but because GLFW runs like a dog on my PC, I've not really pursued it. I had hoped that someone would make a BlitzMax target and then I would just use that (I want to use BlitzMax for Ninjah as well). In the past week MonkeyMax has become a feature complete BlitzMax target for Monkey This is great news because it gives me confidence in distributing games for PC, Mac and Linux now. I love that I won't need to rely on any .NET or XNA frameworks for the game to run and I can bundle all of the assets in to the executable as well.
Last night as a trial I installed the MonkeyMax target and successfully got one of the included demos running. I have Linux installed on my PC, so I will have to give that a go and I am currently attempting to get OSX running in virtual box, but I am not having so much luck just yet!
I was going to write about "finding a theme" as well, but this post is too long as it is