Posts Tagged ‘controls’

Decoupling game logic from input handling logic

Thursday, August 23rd, 2012

In this post we want to share how we are decoupling our game logic from the input handling as we explained briefly in a previous post about different controls we tested for Super Flying Thing.

Introduction

There are different ways to handle the input in a game. Basically, you could have a framework that provides a way to define event handlers for each input event, or to poll input values from the API. LibGDX provides both worlds so it is up to you what you consider best for your game. We prefer to poll for input values for the game logic itself.

When starting to make games, you probably feel tempted to add the input handling logic in one or more base concepts of your game, for example, if you were making Angry Birds you probably would add it to the Slingshot class to detect when to fire a bird or not. That is not totally bad if you are making a quick prototype but it is not recommended for long term because it would be harder to add or change between different control implementations.

Abstracting the input

To improve a bit this scenario in our games, we are using an intermediary class named Controller. That class provides values more friendly and related with the game concepts. A possible Controller class for our example could be:

class SlingshotController {
	boolean charging;
	Vector2 direction;
}

Now, we could process the input handling in one part of the code and update a common Controller instance shared between it and the game logic. Something like this:

class SlingshotMouseControllerLogic extends InputListener {

	Slingshot slingshot;
	SlingshotController controller;

	public boolean touchDown (InputEvent event, float x, float y, int pointer, int button) {
		slingshotPosition = slingshot.getPosition();
		controller.charging = slingshotPosition.isNear(x,y);
		return controller.charging;
	}

	public void touchUp (InputEvent event, float x, float y, int pointer, int button) {
		if (!controller.charging) 
			return;
		controller.charging = false;
	}

	public void touchDragged (InputEvent event, float x, float y, int pointer) {
		if (!controller.charging) 
			return;
		slingshotPosition = slingshot.getPosition();
		controller.direction.set(slingshotPosition);
		controller.direction.sub(x,y);
	}	
}

Or if you are polling the input:

class SlingshotMouseControllerLogic implements Updateable {

	Slingshot slingshot;
	SlingshotController controller;

	boolean touchWasPressed = false;

	public void update(float delta) {
		boolean currentTouchPressed = Gdx.input.isPressed();

		slingshotPosition = slingshot.getPosition();
		x = Gdx.input.getX();
		y = Gdx.input.getY();

		if (!touchWasPressed && currentTouchPressed) {
			controller.charging = slingshotPosition.isNear(x,y);
			touchWasPressed = true;
		} 

		if(touchWasPressed && !currentTouchPressed) {
			controller.charging = false;
			touchWasPressed = false
		}

		if (!controller.charging)
			return;

		controller.direction.set(slingshotPosition);
		controller.direction.sub(x,y);	
	}
	
}

Now, the Slingshot implementation will look something like this:

class Slingshot { 

	// multiple fields
	// render logic 

	Controller controller;
	boolean wasCharging = false;

	update() {
		if (controller.charging && !wasCharging) {
			// starts to draw stuff based on the state we are now charging...
			
			// charges a bird in the slingshot.

			wasCharging = true;
		} else if (!controller.charging && wasCharging) {
			// stops drawing the slingshot as charging

			// fires the bird!!
	
			wasCharging = false;
		}
		// more stuff...
	}
}

As you can see, the game concept Slingshot doesn't know anything about input anymore and we could switch to use the keyboard, Xbox 360 Controller, etc, and the game logic will not notice the change.

Conclusion

Decoupling your game logic from the input by abstracting it in a class is a good way to keep your game logic depending mainly on game concepts making it easier to understand and improving its design. Also, it is a good way to create several controls for the game (input, AI, network, recorded input, etc), while the game logic don't even notice the change.

This post provides a really simple concept, the concept of abstraction, it is nothing new and probably most of the game developers are already doing this, even though we wanted to share it, maybe it is helpful for someone.

We tried to use simple and direct code in this post to increase understandability, however in our games, as we use an entity system framework, we do it a bit different using components, scripts and systems instead of direct classes for concepts like the class Slingshot we presented in this post, but that's food for another blog post.

Finally, we use another abstraction layer over the framework input handling which provides us a better and simplified API to poll info from, that's why we prefer to poll values, food for another post as well.

Hope you like it, as always.

VN:F [1.9.22_1171]
Rating: 4.6/5 (16 votes cast)

Multiple Android controls for Super Flying Thing

Tuesday, August 9th, 2011

Most people tell us that the game controls are not fine yet, at least for the Android version. Based on that, we are working on multiple control implementations to test and to let the user choose which controls fits best for him.

How we manage the controls internally

To control the Ship, we created a structure named ShipController with two methods:

  shouldReleaseShip() : boolean
  getMovementDirection() : float

The first one returns true if the Ship should be released from the planet, false otherwise. The second one returns a real number between [-1, 1] to determine the rotation direction of the Ship and the rotation speed.

That is just a structure with the values modified by the real controllers, explained next, and processed by the Ship behaviors.

Classic controller

The classic control is the current one, you have to press one half of the screen to rotate the Ship to the right and the other half to rotate the Ship to the left.

Classic Controller

This controller performs an acceleration from 0 to 1 internally to the returned movement direction. This allows the player to rotate in slower but after pressing the controls for a while start rotating faster.

Problems with this controls are that it is too sensitive on Android, it may be enough to find better values for acceleration but we couldn't find the best solution yet.

Axis based controller

Determines the movement rotation based on a variable Axis and the current pressed position. The Axis could be horizontal or vertical its position is defined with the first pressed position.

Axis based controller

We are just testing and we have to play a bit with the controller values to know exactly if this controller will work or not.

Some options of the controller could be to make the Axis fixed, not dependent of the first pressed position.

Analog stick based controller

This controller behaves like an analog stick, you decide the desired Ship's direction and the controller will do its magic to make the Ship points to that direction.

For now, the stick center is dynamic and defined with the first pressed position and the stick direction is defined with the current pressed position and the stick center.

Analog based controller

A problem with this controller is we are afraid it could change all the original game play of the game, but could be for the best if it let players control the Ship in an easy way.

We are just testing it also, for now it doesn't feel easy to use, but again, we need to test more controller values to know that better.

Same as the previous controller, one option could be to have the stick center fixed in some part of the screen.

Tilt based controller

Finally, the Tilt based controller is just that (not implemented yet), control the Ship using device's sensors, never worked with that before.

No image in this case, should be easy enough to imagine.

An interesting point of this controller is that it let us recover part of the screen and that could be very important for small resolution devices where your fingers could cover a great part of the screen.

Final notes

One interesting point in testing different controls is to understand that different players need different controls, some times they need the game to adapt to them and not vice versa. We are thinking in having a controls menu or something to select the Controller you want to use and maybe some internal values.

Also, some of the controls could work for Desktop version too, have to test them a bit there to see if they fit, could be great to play using only the mouse.

As always, hope you enjoy these kind of posts.

VN:F [1.9.22_1171]
Rating: 5.0/5 (1 vote cast)