Welcome, Guest. Please login or register.

Login with username, password and session length

 
Advanced search

1411512 Posts in 69376 Topics- by 58430 Members - Latest Member: Jesse Webb

April 26, 2024, 08:04:50 PM

Need hosting? Check out Digital Ocean
(more details in this thread)
TIGSource ForumsCommunityDevLogsJetboard Joust Has Just Launched On Switch, Atari VCS and Steam!
Pages: 1 2 [3] 4 5 ... 10
Print
Author Topic: Jetboard Joust Has Just Launched On Switch, Atari VCS and Steam!  (Read 35778 times)
Hephep
Level 1
*



View Profile WWW
« Reply #40 on: April 05, 2016, 03:50:12 AM »

The ingame spinning crate look amazing, very smooth animation!
Logged

bitbulldotcom
Level 2
**


#indiedev since the #zxspectrum days


View Profile WWW
« Reply #41 on: April 05, 2016, 06:33:08 AM »

Thanks! It took ages but I was really pleased with how it finally turned out.
Logged

bitbulldotcom
Level 2
**


#indiedev since the #zxspectrum days


View Profile WWW
« Reply #42 on: April 07, 2016, 05:58:49 AM »

I want to have enemies on jetboards.

I didn’t really think about this at first – I thought that the enemies would be your usual SHMUP fare, different types of robots/spaceships and the like. But as the game’s called ‘Jetboard Joust’ it makes more sense to have at least some of the enemies riding jetboards like the player.

I’d also been thinking about the rpg-lite elements to the game. There’s going to be different ways to arm your jetboard and a weapon upgrade system – if I treated the enemies and jetboards differently I’d end up with far more combinations of opponent which would make things much more interesting. I guess its been Dark Souls (again) making me mull over this – the way the same basic enemy can present a very different challenge depending what weapon they’re armed with and what armour they’re wearing.

So I’ve been pulling apart my class structure to get something that’s much more flexible. First step was to create a generic ‘Board’ and ‘Rider’ class that represent, at the most basic level, a board and something that rides it. I then created the (somewhat randomly named) Surfer class which defines a Rider that animates in a similar way to the main player character (based on a 3×3 grid as described here). I split out a separate Jetboard class which extends Board – this contains the code for the ‘jetboard as weapon’ functionality which will probably only be available to the main character (as I think having enemies jumping off their jetboards will become too visually complex and confusing). There’s also a separate Weapon class which represents the base level weapon attachment for a board.



The fly in the ointment was with the enemy classes. There’s a bunch of generic ‘enemy’ code that deals with things like player collisions and collisions with projectiles. I couldn’t find a way to share this between enemies that were subclasses of Surfer and those that weren’t (ie won’t be riding jetboards) so I’ve had to (annoyingly) duplicate some of this in the EnemySurfer and GenericEnemy classes. There’s an IEnemy interface that allows both of these to be treated generically by various methods. Not having multiple inheritance is both a blessing and a curse sometimes.

Oh yeah, the base level Character class defines something that has health and can collide with the player and/or projectiles.

This all took some time – I hate retrofitting class hierarchies – but I took it slowly and carefully and once I was all done everything (amazingly) worked fine apart from one minor bug which was fairly easily quashed.

I’ve also designed my first jetboarding enemy – calling him ‘Skullhead’ for now.



Next step will be to add some basic enemy AI and get weapon attachments working.

Dev Time: 1.5 days
Total Dev Time: approx 26 days
Logged

bitbulldotcom
Level 2
**


#indiedev since the #zxspectrum days


View Profile WWW
« Reply #43 on: April 12, 2016, 03:42:55 AM »

Now I have my basic jetboarding enemies in place it’s time to start turning them into something that actually constitutes opposition – that means AI.
Fortunately we’re not talking neural networks here. To quote Spinal Tap (again) ‘It’s such a fine line between stupid and… clever’ and we just need something that operates well enough to track the player reliably and reasonably realistically.

 



So I started with a basic premise – at preset intervals (call it ‘reaction time’) the enemy would make a decision as to whether to operate their horizontal and/or vertical thrusters based on what the player was doing. There would be a configurable horizontal and vertical reaction time for different enemy types, as well as a configurable ‘aggro distance’ outside of which the enemy would just idle rather than attempting to attack.

The first and most basic decision making I tried was extremely simple, just move in the direction of the player and hope for the best. I tried this with a reaction time of 1/10th of a second and it actually worked surprisingly well. There were a few key problems however.

1. The Kamikaze Effect



A result of this super-simple decision making is that the enemy just charges headlong into the player. This might be appropriate for certain enemies but most should really hang back at a reasonably safe distance. In order to resolve this I added a ‘range’ parameter to the jetboard weapon attachment – now if the enemy is within weapon range of the player they don’t attempt to move any closer.

2. World Wrap Confusion (He’s Behind You)!



Dealing with a wrapping scrolling world can be a pain at the point the world wraps. Say my world is 1000 units wide, player is at x location 950 and the enemy is at x location 50 – onscreen this appears as if the player is to the enemy’s left though as far as the coordinates are concerned he’s way off to the right! The solution here is to offset everything by the player’s x location (ie treat player x as zero) and then ‘wrap’ the resulting enemy x location (if it is less than world.width/2 add world.width, if greater than world.width/2 subtract world width).

3. Getting Over It



This one’s a slightly trickier problem. Making the enemy fly over obstacles instead of getting blocked by them is straightforward (if the path is blocked, activate vertical thrusters – job done) but the issue is complicated when also trying to maintain a safe distance (weapon range) from the player. Maintaining a safe distance is pointless if we do not have a clear line of sight to the player in order to fire a weapon. The solution here is to draw a rectangle between the enemy and the player – if this rectangle intersects any obstacles that are higher than the player then we need to get past them (activate horizontal thrusters), if these obstacles are higher than the current enemy position we also need to get over them (activate vertical thrusters).



By this point the AI was performing pretty well – enemies would chase the player down (even across the world wrap), not get stuck on obstacles and (most of the time) maintain a reasonably safe distance from the player from which they would be able to fire weapons. There were a couple of things still niggling me though…

4. Not So Fast!
Up to this point I had been treating the use of the horizontal thrusters as pretty binary, ie just on or off depending on the position of the player and obstacles. Whilst this worked most of the time it meant enemies had a tendency to accelerate extremely rapidly and then not have enough time to slow down, therefore overshooting or colliding into the player. I have tweaked this so that enemies only accelerate when close to the player if below a certain speed or if the player is moving away from them. This results in much better tracking and also and apparent ‘feathering’ of the thrusters which looks more realistic.

5. Getting Away From It
Even with the all the above there were still instances in which the enemy would end up aligned with the player on the horizontal axis and, unless the player moved away, just attempt to collide with him. I needed to extend my concept of a ‘safe zone’ so that, not only did the enemy stop moving towards the player when it entered the safe zone, it actively moved towards the edges of the safe zone when too close to the player. I implemented this with the additional constraint that, when too close to the player, the enemy moves away from the player in the direction of the furthest obstacle from the player. This seems to work fine.



No doubt I will refine aspects of the above but for now I think I have a pretty convincing AI controlled jetboarder. Next step is to create the first basic weapon..

Dev Time: 1.5 days
Total Dev Time: approx 27.5 days
Logged

bitbulldotcom
Level 2
**


#indiedev since the #zxspectrum days


View Profile WWW
« Reply #44 on: April 19, 2016, 08:29:58 AM »

Not really a 'proper' DevLog post here - been working on the first weapon (pistol) but I've also done some more on the AI. It was annoying me that when the enemy tried to move to a safe distance from the player it just charged headlong through them - I've now made it fly over or under instead. Particularly please with the little 'duck under' he does in the second GIF just after they collide...



Logged

bitbulldotcom
Level 2
**


#indiedev since the #zxspectrum days


View Profile WWW
« Reply #45 on: April 20, 2016, 08:45:21 AM »

So - with the AI now looking respectable it's time to get the first basic weapon in there!

The most basic weapon, other than the jetboard jump, is the pistol (has to be). Implementing a simple pistol shot should be easy but it took me rather a long time as, as ever, I started obsessing over the details. I started with a simple two pixel square as the bullet (that's all the room I have to play with really) but wasn't very happy with it so began using a simple particle effect to create a type of trail instead. This looked much better but when the entire trail disappeared at the end of the bullet's range it looked rather odd so I had to implement a way to have the trail carry on moving and disappear at the same place as the 'main' bullet. Doing this in an efficient manner (ie not by creating loads of separate sprite objects) was a bit of a pain in the arse - I also had to think about what would happen when the bullet collided with an obstacle too.

Got there in the end though - and added a simple particle effect for when the bullet disappears or explodes. When everything slotted together it looked quite satisfying - like fireworks. I also spent far too long on the 'muzzle flash' effect - ending up going with something pretty simple.



I also added a bunch of generic parameters that will apply to every weapon and affect the speed at which a weapon can be fired - these are:

Automatic
Whether the weapon auto-fires when FIRE is held.

Repeat Rate
The quickest speed at which a weapon can be fired in succession.

Clip Size
The amount of ammo that can be fired before the weapon needs reloading.

Reload Time
The time the weapon takes to reload (doh)!

I think that should give me enough configurations to play with - reloading will happen automatically if enough time is left between shots.

Once all this was sorted getting the enemy AI to fire was pretty straightforward as all the board/weapon code is the same for both player and enemies. At the moment it just pumps FIRE when within a certain range of the player so I need to add some kind of reaction time parameters but it's pretty effective.



Maybe rather too effective - an unexpected accident was the way the enemy keeps pumping the player full of bullets even after they're dead 'just to make sure'. I actually think this is pretty funny so will probably leave it in there - makes the enemies seem ultra vindictive and evil!



I need to tweak this a bit and iron out some other bugs that are annoying me next - then it'll be on to creating 'cash' pickups when enemies are destroyed.

ps I often post more regular updates and 'work in progress' GIFs on Twitter so please follow me if interested.

Dev Time: 1.5 days
Total Dev Time: approx 29 days
Logged

bitbulldotcom
Level 2
**


#indiedev since the #zxspectrum days


View Profile WWW
« Reply #46 on: April 28, 2016, 07:52:24 AM »

Bit of a ‘clearing the decks’ session today as I get rid of a few bugs that have been irritating me. There were problems with the teleport sequence that I needed to fix (the jetboard weapon attachment not getting displayed correctly), the ‘lost the jetboard’ sequence was annoying me (as the main character carried on waving his arm all gung-ho even when it was obvious he was heading for certain death) and I needed some kind of explosion/disintegration effect for a destroyed jetboard.



None of these proved particularly heinous to sort thankfully so I could move on pretty quickly to tweaking the enemy explosions which I wasn’t entirely happy with. I wanted something a bit more dramatic but not too OTT and think I got there in the end – though my first attempts were way to extreme. Took a fair bit of tweaking though.



I tried adding a velocity deviation to the particles in the enemy explosion but I think I prefer it with the particles moving at a more uniform velocity. It’s not ‘realistic’ but it seems to fit with the visual feel to me, slightly more glitchy and geometric in quality.





Dev Time: 0.5 days
Total Dev Time: approx 29.5 days
Logged

bitbulldotcom
Level 2
**


#indiedev since the #zxspectrum days


View Profile WWW
« Reply #47 on: May 05, 2016, 07:36:47 AM »

So, with those annoying bugs out the way it’s time to start on what will probably be the last pickup – cash!
I want to have some kind of in-game currency for upgrading weapons and the like and I can’t see any point in getting too clever about it so I’m just going to stick with cold, hard cash. Plus I like the retro feel of having big spinning coins that get scattered all over the place – having an enemy dissolve into spinning coins is something of a videogame archetype after all.

The spinning coin wasn’t too hard too get right (at least compared to the spinning crate) but still took me a good couple of hours tweaking. I may well have different sizes of coin so this one, at 12px square, will either be the small or medium. I’m pretty pleased with it though I’m in two minds about whether the way some of the middle pixels flash a bit looks like light reflecting or just looks crap!



Once the coin was done the rest was pretty straightforward implementational stuff – the thing that took the longest was tweaking the particles etc for the ‘got coin’ effect. I also had to add a ‘cash’ element to the HUD.



So now I think I have all core gameplay elements in place really – now I need to start adding some enemies properly and get working on a first playable level. This is also the point where I need to decide if I’m going to do my main gameplay testing on mobile/touchscreen or PC/controller. Or both!

Dev Time: 1 day
Total Dev Time: approx 30.5 days
Logged

bitbulldotcom
Level 2
**


#indiedev since the #zxspectrum days


View Profile WWW
« Reply #48 on: May 16, 2016, 04:59:38 AM »

I hate ‘to do’ lists so usually I decide I can’t be arsed ‘to do’ them. There’s something about them that makes me feel like I’m working for ‘the man’ even though I’m sitting in my home office surrounded by synths and guitars with King Gizzard & The Lizard Wizard cranked up to an antisocial volume.
They are useful sometimes though so I do resort to them when I’ve got a lot of boring, fiddly stuff to finish and am having motivation issues. There is something mildly satisfying about crossing items off one by one which is why I always do them on paper – digital ‘to do’ lists are even worse.

So anyway, here’s what’s been on my ‘to do’ list and is now ‘done’. It’s pretty dull but then game development is a lot of the time I’m afraid (sorry to burst your bubble kids, Santa isn’t real either).

Add ‘Brake’ Functionality To Enemy AI
The jetboarding enemies were still kamikaze-ing into the player too often as I was relying on air friction to slow them down which just wasn’t slowing them down quick enough. I’ve given them the ability to air-brake – it’s a bit of a cheat as the player can’t do this without turning round but it looks a lot better.



Make Enemies Drop Ammo
I’m pretty sure it’s going to be too easy to run out of ammo so I’ve added the ability for enemies to drop a small ammo cache when destroyed. Unlike the larger ammo pickup (which completely recharges the current weapon) this one just adds one ‘clip’ of ammo.



Add Pickups And Warp Gates To Scanner
Self explanatory – needed to be done and involved a bit of messing around with class hierarchies.

Improve Rider vs Board Collisions
I felt the way this was working was inconsistent so I’ve added a separate collision check for the rider and the board. A Rider vs rider collision won’t cause any damage the bulk of the time, health is mainly lost when a rider collides with an opposing jetboard.

Add ‘Teleport In’ Effect For Enemies
I was presuming all enemies would be there at the start of each level but after playing ‘Defender’ some more I’ve decided I’m going to need batches of enemies that appear as a level progresses which means I’m going to need some kind of ‘teleport in’ effect. I’m using the same effect I used for the player and wanted to duplicate as little code as possible so, again, needed to mess with the class hierarchies a fair bit to get this to work.

Remove Permanent Enemy Health Displays
I thought this looked a bit dumb when there were lots on enemies on screen so now the enemy health bars automatically show/hide as they take damage. Thankfully this code was already shared with the player and it was just a matter of turning the ‘auto-hide’ feature on.

Add Scanner To HUD
In the code scanner and HUD they were separate which resulted in some stupid duplication of code when switching shaders for the level teleport effect. This is structured much better now.

Fix Scanner Wrap Bugs
Items on the scanner were getting cropped when they crossed the wrap point of the game world. Fixed this by drawing them twice in this scenario at both the left and right of the offscreen image.

Tidy Up Scanner
Changed the way the ‘screen marker’ is positioned as this was overlapping some scanner elements and also fixed an int rounding issue which meant that scanner items with an odd number of pixels in width weren’t getting aligned correctly.



Fix Board Flashing After Player Death
You can see this in some of the previous GIFs – the player’s jetboard was rendering with the ‘collision’ shader when the player continued to get pummeled by bullets after he’d died. I’ve changed this so the jetboard only does this if the player is riding it.

Can’t Collect Pickups After Warp Gates Appear
Dumb bug – fixed!

Carry Last Weapon Over Between Lives
Rather than starting with the default weapon each life.

Weapon Crate Icon Not Showing After New Level
Dumb bug – fixed!

Some Enemy Bullet Trails never Disappear
Dumb bug – fixed! This one was quite a hard one to track down.

And that’s the list all crossed off (for now). Looking forward to actually starting to refine the gameplay!

Dev Time: 1 day
Total Dev Time: approx 31.5 days
Logged

bitbulldotcom
Level 2
**


#indiedev since the #zxspectrum days


View Profile WWW
« Reply #49 on: May 23, 2016, 07:56:32 AM »

This week I was supposed to have started on the initial gameplay testing for Jetboard Joust but I came up against a rather nasty snag.I develop using Xamarin Studio on a Mac and had been using the GenyMotion Android emulator for my main testing platform. This probably seems strange given that my main target platform is PC, but GenyMotion generally runs extremely well and I don’t want to have to buy another machine just for development purposes. Unfortunately I discovered a problem with GenyMotion in that it seems to just ‘miss’ some keyup/keydown events. The problem is intermittent but bad enough to make serious gameplay testing on the platform impossible – no response from their support either.

That means I need another platform for testing. The iOS simulators are hopeless for graphics performance (and don’t respond to keyboard control as far as I’m aware), Google’s stock Android emulators take an age to launch/install builds and the Xamarin Android Player, though fast, is still pretty flaky. That left Xamarin.Mac as the only ‘native’ Mac option but there’s a hefty additional licence charge for that (or at least there used to be – I couldn’t quite work out what’s going on with Xamarin.Mac since the Microsoft buyout).

As a result of this tragic state of affairs (remember when Apple used to take x-platform development seriously in the initial OSX days?) I decided the only option would be to ditch Mac native and move to running Windows under VMWare Fusion (at least for any development that requires serious gameplay testing). Quite a change. I’ve done this before for ‘Attack Of Giant Jumping Man’ though so was optimistic that it should be a workable solution, plus I’d have to do the PC port anyway at some point – may as well get on with it.

So I started with a brand new Windows 8.1 VM and a fresh installation of Visual Studio 2015. I’ve been using MonoGame 3.2 up to this point but this was as good a time as any to update to 3.5. Installation of the various components was a breeze. I chose the DesktopGL target as it was most similar to the target I’d worked on for ‘Attack Of Giant Jumping Man’ (so hopefully the few bits of platform-specifc code I’d had to write could be re-used) and it didn’t take too long to get my project to compile. The only problem I ran into was that references to the Microsoft.Xna.Framework.GamerServices namespace couldn’t be resolved. For some reason the reference to the assembly that contains these wasn’t included in the MonoGame template project and had to be added manually (Add Reference->Extensions and then choose the appropriate MonoGame.Framework.Net assembly for the platform you are targeting, its a bit confusing as all the assemblies are named the same in the list so you have to click on each one to see more info).

I’m using the ‘shared folder’ feature of VMWare Fusion to share my source code directory between Mac and Windows – if I import the source files as links then both my Xamarin Studio projects on MacOS and my Visual Studio projects on windows both remain perfectly in sync – nice!

Next step is to import all the content – unfortunately I can’t figure out a way to keep all these files in sync as importing a file as a link from a shared folder doesn’t seem to work in the MonoGame pipeline tool. This is a bit of a bummer but not to much of an issue at the moment – hopefully I can figure something out eventually.

Only issue with the content was that I was getting an error when compiling my custom shader files due to a missing DirectX component (‘d3dcompiler_43.dll’) despite having DirectX 11 installed. I followed the instructions to fix this here (using the second method, not the full install) and all was fine.

So now everything would compile and run. Imagine my joy when, on launching, all I got was the garbage you can see below. Complete gobbledegook. Spirits totally crushed. What. The. Hell.



I had absolutely no idea what was going on here and no idea where to start debugging. Nothing I thought of initially had any effect. Jetboard Joust runs on MEAT, my own (originally Java-based) 2D gaming platform that has been over ten years in development. MEAT is another layer of abstraction above MonoGame and fairly complex making it difficult to strip things down to MonoGame basics and do a few simple tests but this is clearly what I needed to do.

I decided to run a few simple MEAT tests first and see if I could get anything up and running…

1. Load image and draw sprite
2. Load image and draw sprite with clipping (as if from sprite sheet)
3. Load image and draw sprite with crop (MonoGame ScissorRectangle)
4. Load image, render to offscreen buffer (RenderTarget2D) and then to screen.

…all of these worked fine which was encouraging to an extent but didn’t get me any closer to a solution. However the next test produced some very strange results.

One of the MEAT classes is a graphical font class – a bitmap font and associated metrics data are stored in a single file which can be used to easily render bitmap text to screen. When I tried a test render using one of these graphical fonts the text would appear OK and then mysteriously disappear after around 30 seconds on screen. Bizarre. This mysterious disappearance only happened when my game template code (that handles all the main menus and stuff) had been executed at startup, ie at least 30 seconds before the problem occurred.

So all I could do was to comment out chunks of the game template code, launch the app, and then run a timer for approx 45 seconds to see if the font disappeared – an incredibly tedious process reminiscent of debugging on J2ME handsets. Eventually I narrowed it down to the line of code that was causing the problem – I was reassigning the property originally assigned to the graphical font that was drawn to screen to a different graphical font. Even though this was a mistake on my part there is absolutely nothing ‘wrong’ with this and it wasn’t causing a problem on any other platform. I had to test and retest several times to convince myself that this line of code was the problem but it was – as soon as I didn’t reallocate the property once the font was drawn to screen the test font didn’t disappear and the entire game ran perfectly!



All I can think of is this had something to do with garbage collection of graphics memory. Reallocating the property meant that the garbage collector (incorrectly) thought the memory should be freed which resulted in some kind of graphics meltdown. This would explain why it took around 30 seconds for the problem to appear – it only happened when the garbage collector kicked in. I create the font images using Texture2D.FromStream() rather than the Content.Load() methods in MonoGame which is slightly weird and could be something to do with it as well – I doubt this is as well tested as the Content.Load() methods.

Anyway, one can’t really blame the MonoGame team for missing such an obscure issue and even with the amount of time I wasted over this it was still a pretty fast cross-platform port so kudos to them. Android/iOS to PC in around a day with about 99% of the codebase consistent – not to be sniffed at! Nice to see the issues with the XBox controller fixed in MonoGame 3.5 too!

Dev Time: 1 days
Total Dev Time: approx 32.5 days
« Last Edit: May 23, 2016, 08:06:30 AM by bitbulldotcom » Logged

bitbulldotcom
Level 2
**


#indiedev since the #zxspectrum days


View Profile WWW
« Reply #50 on: May 25, 2016, 08:07:14 AM »

In order to test the gameplay for Jetboard Joust I needed to start to thinking properly about how enemies are going to appear. Originally I was imagining that all enemies would spawn at the start of each level, however a few initial tests have led me to realise that that approach won’t work for two reasons 1) The player is too likely to become overwhelmed at the start of the level and 2) The difficulty of the level would tail off too much as enemies are destroyed.
So in order for levels not to feel too ‘front-loaded’ (see below) I’m going to have enemies spawn in batches after a certain amount of time has elapsed, much like in Defender.



I also needed to think about the logic behind the choice of enemies in each level. As there will be an infinite number of levels in the game they will have to be procedurally generated somehow – my ideal scenario is to allocate a difficulty score for a level and have an algorithm allocate a spread of enemies that matches it without feeling too ‘random’.

The problem is complicated by the fact that many enemies are a combination of two factors, enemy type and weapon type – so allocating a simple difficulty score per enemy type won’t wash.

The solution I’ve come up with so far (which may well change) is as follows…

I have three separate enums WeaponTypes, EnemyRiderTypes and EnemyTypes. The two different enemy types represent ‘armed’ jetboard riding enemies and ‘standard’ enemies. The values allocated to each element in the enum represent a difficulty score, e.g…

I then have a new class EnemyDefinition which represents an enemy to which a difficulty score can be allocated. This could be either a standard EnemyType or a combination of an EnemyRiderType and WeaponType. EnemyDefinition also has a method EnemyDefinition.Create() that creates an instance of the enemy it defines.

At startup I automatically create a list of EnemyDefinitions which contains an entry for each EnemyType and for each possible EnemyRiderType/WeaponType combination – I store this in a static class EnemyRandomizer.

Now I have a static method EnemyRandomizer.CreateBatch() which takes a parameter for a total difficulty score and a parameter for the current level. This method creates a list of all EnemyDefinitions that are equal or less than the supplied difficulty score and chooses one of these at random. It then calls EnemyDefinition.Create() as many times as necessary to create enemies that total the supplied difficulty score and returns this ‘batch’ in a list.

When I originate a level I take a difficulty score based on the level number, split this into a series of ‘batch’ scores and then call EnemyRandomizer.CreateBatch() for each one – so a level with a difficulty score of 500 might have five separate batches with a difficulty score of 100 each. These ‘batches’ spawn at a preset time interval or when all existing enemies have been destroyed.

There’s a few extra complications such as making sure we don’t get ‘stray’ enemies and stuff but this is the basic approach and (for now) it seems to work OK. Hopefully it’ll prove robust enough to be used for the final game.



Dev Time: 0.5 days
Total Dev Time: approx 33 days
Logged

bitbulldotcom
Level 2
**


#indiedev since the #zxspectrum days


View Profile WWW
« Reply #51 on: May 31, 2016, 06:14:47 AM »

Rather a frivolous blog post this one but I feel I should document everything, warts and all – and this issue has cost me a worrying amount of time.

I needed to add a rocket pickup so I could limit the use of the jetboard ‘jump’ attack (will write more on this in the next post). This should have been a simple task but unfortunately my ‘pixel rocket’ ended up looking rather too much like a ‘pocket rocket’!



I tried an alternative which I thought was OK but several people on Twitter though it was still too phallic so it was back to the drawing-board again.

Eventually I got there. The issue really was that the ‘shaft’ of my rocket was only two pixels wide – this meant that the end always looked ’rounded’ instead of ‘pointy’. Thickening the shaft to three pixels allowed me to have a pointy end which, I think, removed any sexual connotations for all but the most filthy-minded of individuals (I can’t believe I’m actually writing this).



Here's the final version in-game...



Oh yeah – I’ve also added a new enemy type, I’m calling this one the Minion!



Dev Time: 0.5 days
Total Dev Time: approx 33.5 days
Logged

bitbulldotcom
Level 2
**


#indiedev since the #zxspectrum days


View Profile WWW
« Reply #52 on: June 01, 2016, 08:34:23 AM »

It’s always a great moment in the development of a game when the game actually starts to feel like a game, rather than a prototype, tech demo, or a bunch of animated GIFs on Twitter.
Thankfully I’ve now reached that stage on Jetboard Joust and have been able to spend the last couple of days refining gameplay rather than tweaking visuals or adding basic functionality – and I’m pleased to say that, considering it’s still early stages, it’s playing fairly well and has the old-school arcade feel I’d hoped for.

So now I’ll bore you with the kind of refinements I’ve been making over the last couple of days – some major, some pretty minor…

The Jump Attack
This was the really major change. It became obvious whilst testing that the ‘jump attack’ (which I’ve sometime previously referred to as the ‘weaponised jetboard’) was far too powerful (see below)...



...and needed to be ‘nerfed’ in some way. I’ve settled for limiting the amount of jump attacks the player can do which seems to work well and is a solution I like because it’s somewhat akin to the smart bombs in Defender.

So there’s now ‘ammo’ for the jump attack which is represented by a new rocket icon in the HUD – enemies also drop extra rockets occasionally when destroyed (see the last post for more on that saga).

I was going to use the ‘jump attack’ as the basic attack when the player runs out of ammo but had never been entirely happy with this idea as I was worried that the transition from button-mashing ‘fire’ to fire a weapon to something that required a more judicious button treatment would be too jarring. I now have a separate button for ‘fire weapon’ and for ‘jump’ which works much better – the only disadvantage is that it will make the control system more complex on touchscreen devices. Those are low-priority for me at the moment though.

Ammo
It was far too easy to run out of ammo so I’ve upped the initial capacity of the pistol to 24 shots. This will be expandable via weapon upgrades. It’s still pretty easy to run out of ammo but I like the gameplay aspect of having to dive down to retrieve the mini-ammo pickups all the time, it adds a ‘survival’ element which is unusual for SHMUPs but I think works nicely. It will have to be well balanced though.

Health
I’ve added mini-health pickups as an additional occasional drop when enemies are destroyed. I felt I need something smaller than the ‘bubble’ health pickup which recharges you to full health (at least at the start of the game, the player’s max health level may be able to be upgraded).

Pickup Balancing
The algorithm that decides which pickups are dropped is ‘intelligent’ to a degree in that if the player is very low on health or rockets it is more likely to drop these items (though there is still a limit on the frequency at which these appear). I’ve done this type of thing in other games and like the result as it leads to plenty of moments where you are just ‘saved by a pickup’ which leads to more of an ‘edge of the seat’ feel – playing on the players ‘gambling response’.

Pickup balancing is going to be very important to gameplay. I’ve also added the more powerful ‘bubble’ pickups which, so far, appear after a certain number of enemy ‘batches’ have been released.

Pickup Timeouts
The ‘mini pickups’ now have a timeout attached so they don’t hang around forever. This is particularly important for the coins which otherwise could all be left for the player to scoop them up easily when the level was complete. Consequently coins have a relatively short timeout, whereas ammo, health and rockets i can afford to have hang around rather longer.

Enemy Frequency
This is another key thing to get right – so far the game seems to work better if smaller enemy batches are released frequently rather than large batches less frequently. In a previous post I talked about allocating enemies based on a difficulty score – I have also added something that prevents additional enemy batches from being released if the enemies currently in-game exceed a certain difficulty threshold. This prevents the user from becoming ‘swarmed’ by enemies which was becoming a bit of a problem.

Enemy Clustering
This one’s still on the ‘to do’ list but I need to add some variation to the speed and acceleration of the same type of enemy so they don’t end up ‘clustering’ too much which has a tendency to happen at the moment. I will probably also add some variation to the timing of their AI decisions.

Those are the main fixes – I’ve also fixed a ton of minor bugs and made a load of other minor improvements. Next step is to finish the initial set of gameplay tweaks and then start to look at optimising performance, particularly in regards to the way the ‘world wrap’ is handled.



Dev Time: 2 days
Total Dev Time: approx 35.5 days
Logged

bitbulldotcom
Level 2
**


#indiedev since the #zxspectrum days


View Profile WWW
« Reply #53 on: June 08, 2016, 04:03:35 AM »

I’ve been thinking for a while that the basic ‘destroy all enemies’ objective in Jetboard Joust was a bit too one-dimensional and that I needed to add something to give the gameplay a bit more depth.

The obvious source to look for inspiration was Defender, to which Jetboard Joust is pretty much a homage, so look to Defender I did!

In Defender you protect these little coloured blob things which get carried off by a certain type of enemy. If an invader manages to get a blob to the top of the screen it mutates and becomes a lot more dangerous. I thought I may as well go the whole hog with the Defender homage thing and replicate this scenario – maybe I could have the player protecting radioactive cannisters which enemies carry off and then use to mutate themselves?

This seemed to make sense to I went about designing some radioactive ‘cargo’. Unfortunately, despite my best efforts, it was shit! The little cannisters were OK but drawing a decent radiation symbol in about 5×5 pixels proved beyond my abilities, and the cannisters on their own just looked too boring. Time to rethink!

According to the Wikipedia page for Defender the little coloured blobs that you defend are, in fact ‘astronauts’ (not that you’d guess it from just playing the game). This triggered a memory of them being referred to as ‘humanoids’ in the original game instructions (though i could be wrong about this).

Something with a bit more character seemed a good idea so I thought I’d go about designing the most basic ‘humanoid’ form I could in as few pixels as possible and see if that would work. What I came up with kind of looked like a baby version of ET so I thought – what if you were protecting alien babies? This seemed to make sense! Babies are inherently something that warrants protecting, they look cute and have character, and having them carried off by aliens has overtones of the whole alien abduction/conspiracy thing which I liked.

So now I have alien babies! I created a little ‘idle’ sequence for them and a ‘panic’ animation for when they’re abducted. I think they’re pretty cute! Glad I was so bad at drawing radiation canisters! Now to work on their abduction…



Dev Time: 1 day
Total Dev Time: approx 36.5 days
Logged

alvarop
Level 9
****


ignorant


View Profile WWW
« Reply #54 on: June 08, 2016, 07:05:36 AM »

At first I thought they were baby skeletons, but I guess in context, it makes sense!

So, will the babies be in a centralized position (like a base that you have to protect) or there will be many in the level / generated dynamically? I don't think I've ever played Defender, so the reference might be lost in my case.

Another question : you're telling us that the enemies are gonna eat the babies and get stronger by doing so?

 Gentleman
Logged

i make games that can only ever be played once on http://throwaway.fun
bitbulldotcom
Level 2
**


#indiedev since the #zxspectrum days


View Profile WWW
« Reply #55 on: June 21, 2016, 01:53:44 AM »

At first I thought they were baby skeletons, but I guess in context, it makes sense!

So, will the babies be in a centralized position (like a base that you have to protect) or there will be many in the level / generated dynamically? I don't think I've ever played Defender, so the reference might be lost in my case.

Another question : you're telling us that the enemies are gonna eat the babies and get stronger by doing so?

Haha - no, no baby eating, that might be considered a bit sicko! They'll kind of absorb the babies and mutate (I'm not sure if that's any better)!

The babies will be spread throughout the level, though as I'm playtesting it it works better if they're on a flat area of ground so they might end up being a bit clustered together because of that.

If you've not played 'Defender' you really should - it's a classic!  Wink
Logged

bitbulldotcom
Level 2
**


#indiedev since the #zxspectrum days


View Profile WWW
« Reply #56 on: July 05, 2016, 04:48:53 AM »

OK - now we have our alien babies it’s time to make something horrible happen to them – seems cruel but this is a videogame right?

First step was to get the enemies to abduct them. This was rather harder than I thought as it required some reasonably complex changes to the AI in order to get the ‘chasing baby’ code to play nice with the ‘chase player’ code. Picking up ‘cargo’ in Jetboard Joust is more complex than in Defender as the terrain in Jetboard Joust can be interacted with whereas in Defender it’s just for show.

I didn’t really run into any issues I hadn’t come up against already when writing the ‘chase player’ code though so thankfully I could pretty much reuse the techniques I’d come up with there and blogged about earlier.

One thing I have implemented in order to get things to look vaguely ‘realistic’ is an ‘aggro range’ parameter for the enemies. This is the range within which enemies will actively chase the player – outside of the aggro range enemies will idle or attempt to abduct babies(!) When the aggro range is activated it becomes larger so the player must run a certain distance away from the enemy in order for it to go back to ignoring them.

If an enemy is in the process of abducting a baby the aggro range is shorter, however if the player shoots the enemy or strays too close it will still go on the offensive.

Another issue with the abductions was having the baby ‘jump’ to the middle of the board when picked up. In order to make this look decent I had to implement some code to check whether the enemy had passed ‘through’ the baby at the last update. This raised another issue though in that if a baby ended up positioned right next to a building it was impossible for the enemy to pass ‘through’ it – this was a pretty rare occurrence but impossible to avoid so I’ve implemented a necessary hack for these situations where a ‘pass through’ is not necessary. The baby jumps slightly but it’s better than it being impossible to pick up.



Next step – design a mutant! This was fun and I’m pleased with the results, I didn’t take me too long either. For inspiration I had in mind Space Invaders (of course), Cthulhu, and the aliens from District 9. The mutant animates slightly differently to other board-riding enemies but it wasn’t too tough to get this working OK – I’d already set the relevant methods up so they were easy to override.



Fortunately the actual transformation happens offscreen so this part of the sequence was very easy! Part of me thinks I should do some kind of onscreen transformation – or will that look a bit odd?



Dev Time: 1 day
Total Dev Time: approx 37.5 days
Logged

bitbulldotcom
Level 2
**


#indiedev since the #zxspectrum days


View Profile WWW
« Reply #57 on: July 14, 2016, 02:24:05 AM »

It’s been a while since the last devlog but I haven’t been idle, I decided that before I could start tweaking gameplay again (now that we have abductions and mutations) I should make sure that everything was running as fast and as smooth as possible.

The main performance tweaks involved a bunch of changes to the particle engine which pretty much necessitated a complete refactoring of this part of the game code. This took several days and, whilst I know I have further optimisations to do, the result is an architecture that’s much more flexible and seems to run very well to boot. It could still be improved though. As this was kind of a generic topic I wrote a separate post on it here.

Other performance tweaks involved various memory optimisations, particularly implementing object pooling for commonly used objects. Again, as this was a pretty generic topic I wrote a separate post on it here.

The last thing to be optimised was collision detection and for the record I’ll list the main optimisations I made below. Though these are pretty specific to the way the gameplay and game physics work in Jetboard Joust they could be applied to a bunch of 2D games.

1. Ignore The Real World
Jetboard Joust implements a pretty simple physics model but it is still a physics model – therefore anything that exists in the game world is treated as being constantly under the influence of gravity (ie always falling) unless ‘pushed’ up by another object. This means that a collision check has to be run each frame for each object against any other object that might get in its way. Even though I use a segmented approach for the terrain this can still prove expensive.

When I ran my first diagnostic tests I was shocked to see that around 8.5% of the CPU time in my update loop was taken up by collision detection on the ‘pickup’ items (there are a lot of these created in the game and they can hang around a long time). As these pickup items are stationary most of the time this was clearly a complete waste of cycles!

So what I did was effectively disable the physics on the pickup items once they have come to rest. I can get away with this because I know that once they have come to rest the object on which they rest won’t be removed at any point – all that can happen to them is that they get picked up by the player or disappear if they hang around too long.

This simple optimisation took the CPU useage for this section of the code down to around 0.23% – a pretty hefty saving!

2. Apply Basic Logic, Stupid!
The next chunk of cycles were eaten up by collision detection on the enemies against the terrain. There were a couple of simple optimisations I could make here. Firstly I now keep a record of the highest point the terrain reaches when the level is constructed, if an enemy is higher than this point (as they often are) I know I don’t need to bother checking against the terrain at all. Similarly, if an enemy is travelling right I know I don’t need to bother checking against the right side of terrain objects and the same for the other directions.

3. Cache Me If You Can
I have my own Rectangle class that I use in my code and there were quite a few key places where I was using Rectangle.Width/2, Rectangle.Height/2. I replaced these with a HalfWidth and HalfHeight property that is cached and only updated when the Width or Height of the Rectangle is set – this has potentially saved me many thousands of division calculations per frame.

The game seems to be maintaining close to a 60fps framerate now in most situations though the fact I’m testing on a virtual PC running on a seven-year-old Mac Pro makes it kind of hard to tell for sure. I get occasional juddering but I think this is due to running on an emulated OS.

It's hard to grab game footage reliably at 60fps so I attempted to film some - forgive the pretty crappy camerawork but it gives an idea of how everything is currently running...



And, just for a laugh - here's a quick grab I did of a drawing optimisation not quite going to plan...



Oh yeah, I also decided that having the enemy mutations happen offscreen was kind of a cop out (as well as being annoying gameplay-wise) so we now have onscreen mutations!



Dev Time: 5 days
Total Dev Time: approx 42.5 days

Logged

alvarop
Level 9
****


ignorant


View Profile WWW
« Reply #58 on: July 14, 2016, 06:08:48 AM »

Those on screen enemy mutations are on point. I'm really loving where this game is going, feels very dynamic and "alive".
Logged

i make games that can only ever be played once on http://throwaway.fun
bitbulldotcom
Level 2
**


#indiedev since the #zxspectrum days


View Profile WWW
« Reply #59 on: July 14, 2016, 08:37:09 AM »

Thanks for the feedback - it's good to know people like the look of it.  I think you'll like the next update, I've made collisions and stuff even more dynamic in feel. Stay tuned...  Wink
Logged

Pages: 1 2 [3] 4 5 ... 10
Print
Jump to:  

Theme orange-lt created by panic