Monthly Archives: January 2016

Directional Control Systems for Touchscreen Games

A while ago I wrote a blog post entitled An iPad Is Not A GamePad describing my aversion to virtual ‘d-pad’ (I’ll call them ‘v-pad’) style controls for touchscreen games.

Well, whaddya know – a potential publisher for ‘Attack Of Giant Jumping Man’ has asked to see the game working with a ‘v-pad’ style control system as he’s worried the existing ‘swipe’ control system is not intuitive enough. Personally I just think we need to improve the way we communicate how the existing system works – but, as I’m never one to let my prejudices get in the way of improving the game experience, I decided to roll up my sleeves and see if I could get a decent ‘v-pad’ style control system going. It wasn’t easy and I’ve documented my experiments here. I’ll cover button placement in another post as this one got rather out of control!

First off, as I knew I was going to be experimenting with several different control methods, I had to completely separate the ‘controller’ logic from the ‘game’ logic. I guess this is something that’s pretty standard practice with other application designs (MVVM, MVC etc) but I never really think about doing it with games as (usually) you know what the control method is going to be from the outset and the game is designed with this in mind. Ultimately it makes more sense to keep the controller logic abstracted though (especially in today’s cross-platform world) and, now I’ve been through the pain, I will definitely be approaching game design this way in future. It allows a bunch of different control systems to be easily tested/switched without any alteration of the game code.

So I came up with a generic ‘controller’ interface that produces the usual ButtonPressed / ButtonReleased type events as well as allowing polling to see whether a particular button is held down and the position of two ‘virtual analog thumbsticks’ which produce values between -1.0 and 1.0 on both the horizontal and vertical axis. Basically pretty much an abstracted representation of the XBox Controller.

Next stage was to experiment with some different controllers, I’ll go through each of these in turn…

The Virtual D-Pad
This is the simplest approach of the lot. Basically a virtual button for up/down/left/right that produces a binary KeyHeld result if the user is pressing the screen in the appropriate place.

This method is very easy to implement but, in my opinion, sucks for the following reasons (many of which apply to all v-pad style controllers).

1. It requires an overlay on the screen to show the user where to press. This uses up valuable screen real-estate and potentially gets in the way of the action.

2. It requires the same size controller whatever the physical size of the device, therefore is much more problematic on small devices. A fact that’s blindingly obvious but a lot of developers ignore is that people’s thumbs are the same size whether they’re using an iPhone 4s or an iPad. Think how much research goes into designing the perfect d-pad size for a console controller, now imagine sticking one of those on top of a 4s screen – kind of get in the way of the action wouldn’t it?

3. It requires the user to hover their finger/thumb over the same area of the screen all the time. Again, using up valuable screen real-estate and potentially getting in the way of the action. As above, on a physically smaller device this is even more of an issue.

4. It’s too easy to stray off the controls. With a physical controller you can feel your thumbs resting on the controls without actually pressing them – it’s very unlikely you’ll slip onto the wrong control accidentally, let alone slip off the entire controller. Modern touchscreen devices however are designed to be as super-smooth as possible with no tactile differentiation between the screen itself and the ‘dead’ frame of the device. This makes it all to easy to stray into the ‘dead zone’ without realising it.

You could implement your own tactile feedback solution, ie vibrate the device when the user strays into the ‘dead zone’, but there are a number of issues with this. Firstly, not all devices support a vibrate function (iPads and tablets don’t tend to) and auditory feedback is likely to be annoying – secondly, in order to implement this you are reliant on getting a ‘TouchReleased’ event when the user strays into the ‘dead zone’ and for that event to be accurate enough to warrant doing something with. In my tests on an iPad 4, when moving quickly that event could be generated up to 45 pixels from the edge of the screen – that’s 0.25inch so probably within the bounds of a ‘normal’ release event.

As you can tell, I’m not a fan of this option and can’t really see any situation where it’s decent control method to use. This brings us on to…

The Virtual Thumbstick
This method is similar to the ‘Virtual D-Pad’ described above. However, instead of simply checking whether we have pressed a virtual button to determine directional control we measure the distance of TouchPressed and TouchReleased events from a central point and use this to compute a value between -1.0 and 1.0 on the horizontal and vertical axis. This can be converted to a binary event if necessary by testing against a threshold value. A TouchReleased event resets all values to zero.

The computation I use for calculating the x and y values is something like this…

//
// Calculates thumbstick values and y between -1.0 and 1.0 where px and py
// are the distance of the touch event from the centre of the virtual thumbstick
// and radius is the distance required to produce a maximum value
//
public static void CalculateThumbstickValues( out float x, out float y, int px, int py, int radius )
{
// Work out x and y distances as a proportion of radius
x /= radius;
y /= radius;

if ( x>1.0f ) x=1.0f;
else if ( x<-1.0f ) x=-1.0f;

if ( y>1.0f ) y=1.0f;
else if ( y<-1.0f ) y=-1.0f;
}

This method has certain advantages of the ‘Virtual D-Pad’ method. It’s not restricted to binary events and, importantly, it doesn’t require the user to target one area of the screen quite so much as any deviation from the ‘edge’ of the thumbstick area reads as a maximum value. Consequently I find it works much better.

It still suffers from the fact that it requires some kind of visual overlay (though technically only the very centre point of the thumbstick needs to be marked), that it’s restricted to one area of the screen (so better make sure it’s not getting in the way of anything important), and (worst of all) that a user can still easily stray into the ‘dead’ zone (effectively letting go of the thumbstick).

Given these problems I thought I’d work on a couple of variations of the ‘Virtual Thumbstick’…

The Floating Thumbstick
This method is identical to the ‘Virtual Thumbstick’ with the difference that the thumbstick isn’t fixed to a set centre point – instead the location of the stick changes every time a TouchPressed event is received.

The advantages of this method are twofold – no visual overlay is required and the user can direct their input to a location on the screen that doesn’t get in the way of the in-game action (possibly making it less likely that they will stray into the ‘dead zone’).

One disadvantage of this method is that the player has to make a small drag motion for each TouchPressed event in order to generate any kind of directional data. On some types of games this might become an issue.

Another disadvantage is that if the player generates their original TouchPressed event near to the edge of the screen (say at the left edge) it then becomes impossible to move left without first releasing touch.

Generally I found that this control method works very well as long as the game in question is designed for one-handed play. On games that require two-handed play players will tend to position their thumbs permanently over the same area of the screen anyway, pretty much negating any advantage this control method brings.

The Elastic Thumbstick
This method takes the idea of the ‘Floating Thumbstick’ one step further. As well as centering on TouchPressed the thumbstick also centres after a defined period of inactivity, though in this instance it continues to read its last ‘set’ value.

As an example – on a thumbstick with a radius of 50 pixels a swipe to the right of 50 pixels will generate a value on the x axis of +1. If the user doesn’t release and doesn’t move their finger the thumbstick will be re-centred but continues to read +1 on the x-axis until a significant movement in the other direction on the same axis is made.

The thumbstick is also recentered if the user makes a sudden change of direction, so a swipe to the right of 50 pixels on the same thumbstick followed immediately by a swipe to the left of 50 pixels will result in the thumbstick being recentered in the +50 position (now reading 100% left).

The advantage of this approach over the ‘Floating Thumbstick’ is that it takes a much less significant movement to change direction on either axis. Consequently the problem of centering the thumbstick at the edges of the screen is negated and the amount of screen real estate required to process movement (and therefore be blocked by your user’s fat thumbs) is reduced by approximately 50%.

The only real disadvantage is that this control method doesn’t allow for ‘decceleration’, ie setting a thumbstick to max and then reducing this value – however, in practice this won’t make a lot of difference on most games and no difference at all on games that are using the thumbstick as a ‘binary’ controller.

In practice I found this method to operate best on two-handed games or on one-handed games where no decceleration is required and quick changes of direction are key to gameplay. It’s more finicky to set up than the others but well worth the effort.

NOTE: I also tried a similar approach by polling average movement on the touchscreen every few frames but this was pretty much a disaster.

The Sticky Elastic Thumbstick
OK, the names are getting pretty ridiculous now and a ‘sticky elastic thumbstick’ sounds distinctly dodgy but who cares. This is a new one based on gameplay testing I’ve just been doing on Jetboard Joust. It operates exactly like the ‘elastic thumbstick’ above with the difference that a straightforward touch event with no movement generates the values the thumbstick was set at the last touch release rather than zeroing the thumbstick and waiting for another movement.

This has the effect of a drag motion being required to set the direction but no movement being required to continue to move in that direction which makes control a lot easier and makes it a hell of a lot less likely that the players thumbs stray onto the ‘dead zone’. It seems to work extremely well on Jetboard Joust.

The Event-Driven Thumbstick (Swipe Controls)
This method is based on the ‘Floating Thumbstick’ with the key difference that it does not support continuous polling of thumbstick values. Instead it is event-based – a thumbstick event begins on TouchPressed (when the thumbstick is centered) and ends in one of two ways…

1. A TouchReleased event is generated within a specified time (approx <750ms)
2. The thumbstick is 'moved' to it's maximum position on any axis (different thresholds can be set for different axis if necessary)

… either of these causes an event to be sent to the game which is then processed appropriately.

The real advantage of this control method is that (with certain games) it allows one-handed operation where two-handed operation would normally be necessary (for example LEFT, RIGHT and JUMP). This in turn means that the user is free to swipe anywhere on the screen and that their thumbs and fingers are far less likely to get in the way of the action. Using this method also means that there's no requirement for the user to 'hover over' or touch any particular point of the screen for any length of time, again meaning that less of the action is likely to be obscured by fat fingers.

The disadvantage of this method is that the game needs to be suited to event-driven rather than continuous polling-based control. A game that requires a character to run in certain directions for long periods of time for example would be annoying to control by endless swiping, though there may be workarounds for this (e.g. swipe to move, tap to stop moving).

In practice I find the event-driven method to be the best way of controlling touchscreen games providing the game design is suited to it and the game can be operated one-handed. The event-driven method can enable very accurate control, obscures the screen far less than other methods, and never really runs the risk of the user losing control by straying into the 'dead-zone'. It's still our preferred control method for 'Attack Of Giant Jumping Man'.

Out of the two-handed methods the ‘elastic thumbstick’ seems to be the best compromise in this instance. 'Attack Of Giant Jumping Man' requires the user to make quick directional changes and the ‘elastic thumbstick’ allows for this whilst obscuring a minimum of the screen real-estate.

mockup_3x
Seriously, Just Don’t!
Advertisements

Jetboard Joust Devlog #5 – Another One Bites The Dust

Another case of #gamedev pottering here as I started work on one thing and got pretty much distracted with another. It was a constructive distraction though and has provided me with plenty of re-useable code so I’m not beating myself up about it.

I started work on the animation for falling off the Jetboard and got it to a stage where I was pretty happy with it, then thought it would look better if I added some dust as the player hits the floor. I decided to use the basic particle generator I’d created for the enemy explosions and added some additional functionality such as the ability to animate particles, apply gravity, and restrict the angle at which particles are fired.

This worked, but in the process of testing I accidentally had the dust particles generated whenever the jetboard landed on anything – and it looked good! Decided to refine this which meant quite a few changes to the particle generator – mainly the ability for one generator to manage particles generated from several locations (to save the costly instantiation of a new generator every time I need some dust). Pretty pleased with the results though the parameters still need a bit of tweaking – some of that dust is getting flung rather too far!

Next up was working on the collision detection and figuring out the various ways you can be knocked off your jetboard. I’ve pretty much nabbed the collision detection from ‘Attack Of Giant Jumping Man’ which has saved a bunch of time and I think I’m going to restrict items you can interact with to simple static platforms as this is a SHMUP in essence, not a platformer.

So, other than colliding with enemies, there’s three ways that you and your jetboard can become separated…

1. Jetboard hits obstacle mid-jump, player still moving freely
2. Player hits obstacle mid-jump, jetboard still moving freely
3. Player hits obstacle whilst in flight, jetboard moves freely

…I also had to cover the occurrence where both player and jetboard come into contact with the same obstacle mid-jump. In this instance (I think) it’s reasonable that the player is able to land on the jetboard and recover though I may restrict this based on how far the player falls.

I’m still not entirely happy with some of the player falling animations but we’re getting there. Probably going to bit a bit of a break from this now whilst I work on ‘Attack Of Giant Jumping Man’ for a bit. Next up will be implementing a simple ‘lose life/retry’ loop.

Dev Time: 1.5 days
Total Dev Time: approx 8.5 days

previous|next

mockup_3x
First Stab At Falling Animation

mockup_3x
Dust Particles In Action

mockup_3x
Three Ways To Fall Off A Jetboard #1

mockup_3x
Three Ways To Fall Off A Jetboard #2

mockup_3x
Three Ways To Fall Off A Jetboard #3

mockup_3x
Recovering From A Fall