|
QSDK 1.1 Documentation |
The various controls of the demo (control map) are detailed here
Control code is about translating physical inputs - controllers, keyboard, mouse - into logical actions in the language of the game. The PhysicalInput object first collects inputs from devices and turn them into metrics, e.g. meaningful boolean or floating-point values. On the other side, the game and its players request input values for specific actions of their own. The two ends do not speak the same language: PhysicalInput speaks in terms of device values, the players in terms of actions. That's why the CommandBank and the Command objects lie in the middle in order to map actions - run, walk, jump, use,... - into combinations of inputs. This mapping is dynamic and may be changed to fit the user preferences. On top of that, different users may listen to the same action value, and that would have different meaning in terms of input combinations: running for one user may be activated by a button while it may be a mouse click for another one.
Here is how it schematically works:
|
|
||||||||||
|
|
|
reads and combines |
|
stores and updates |
|
|||||
|
|
||||||||||
|
|
||||||||||
|
|||||||||||
|
|
|||||||||||
|
|||||||||||
|
|
|||||||||||
|
|
|||||||||||
|
|
|||||||||||
| class: | PhysicalInput |
| files: | physicalinput.h physicalinput.cpp |
PhysicalInput::theInput is a singleton object that collects inputs from registered devices. Each relevant entry, e.g. right mouse button, left controller analogue joystick or arrow up key, is registered by the commands that would like to use them. When PhysicalInput::update is called by the Game object, it pulls all the input entries and stored them with a appropriate format.
The PhysicalInput object only listens to devices that are relevant to the platform (see PhysicalInput::flags_): keyboard and mouse for Win32 and Unix platforms, controllers for consoles.
It may also sometimes checks whether any digital inputs was pressed. The user may want to know when any input was triggered without caring about the actual one that was pressed, e.g. to quit the credits screen. If PhysicalInput::listenToButtonChanges_ is set to true, it sets PhysicalInput::pressed_ to true whenever a digital input gets pressed. This value is then pulled into PhysicalInput::anyKey_ and can be read by the user.
| class: | Command CommandManager |
| files: | command.h command.cpp |
Commands translate input entries into user actions. The best way to look at them is to regard them as input combination formulas: they take one or several inputs and turn them into a value which is meaningful to the application. For example, walking is triggered by the forward and backward keys or by an analogue stick. The associated command reads the input values and combines them to return a floating-point value that indicates how much the player should walk forwards/backwards.
The formula used by the Command to combine the input is determined by Command::mode_. There are 6 formulas. Some reads a single input (Command::hold, Command::click, Command::toggle), some combines two inputs (Command::hold2, Command::click2) and one is triggered when a key or a button gets pressed (e.g. used to quit credits screen).
A set of inputs is passed when the command gets constructed. The command registers the input to PhysicalInput and deregisters them on destruction. When updated (Command::tick), it pulls the input values from the PhysicalInput and combines them.
The user does not care about the actual way the inputs get combined. All he/she wants is a value for a given action he/she wants to perform. For this purpose, a set of predefined types describes the actions the user can perform. The code then describes what the command is for each action. The user can then retrieve the value for a chosen predefined command. In a way, commands present two faces to the code. For the input system, they combine inputs in a way which is flexible and defined per user per platform. For the rest of the code, they return a meaningful value according to a predefined action code.
Predefined command types are listed by Command::Type. What each type means in terms of input entries is defined by a handy set of macros and defined differently on each platform (for instance, on unix, use is triggered by pressing the space key whereas the X button does it on PlayStation 2):
When the code needs a Command object, it calls Command::create(unsigned int user, Type) and the Command code translates the type into a Command::Mode and a set of input entries and creates the appropriate object.
A command combines a constant set of input entries. Therefore there only needs to be at most one instance of it for each type. Commands can be shared by multiple users. The role of the CommandManager singleton is to store all active commands and polls the inputs to update their states. Users tells the CommandManager which actions they would like to perform, through the CommandBank object, and the manager creates the ones it needs and updates them. Commands in the manager are reference-counted as they may be shared among users and among actions. The manager gets rid of them when they are no longer needed.
| class: | CommandBank |
| files: | commandbank.h commandbank.cpp |
The demo has different stages and those stages have a different way to interpret inputs. At runtime, inputs controls the players. When the credits roll on screen, inputs are mainly there to exit the screen. Besides, different users may use the same actions but it may have a different meaning for the inputs. CommandBank solves this. It is a predefined collection of commands for a given mode and a given user. CommandBank::Mode describes a demo stage. The bank lists the relevant command types for the stage.
All the user does is asking the CommandBank for the value describing an action. The CommandBank translating it into a Command that combines input entries and feeds a value back to the user.
Commands are read by all sorts of game elements: entities, cameras and the game itself. These objects create or receive a CommandBank and, through it, query the values for actions they would like to perform. The command bank converts these action queries into input combinations.
Game::commandBank_ is the common CommandBank: it handles the actions common to all users, e.g. quitting the game or displaying the script console.
Each player view has its own CommandBank that handles the action specific to its player. It gets passed to the game object via GameObject::setInput(const CommandBank *). The player can then ask for any desired action values. For instance, JanSeth's code asks the value for run and moveHorizontally in JanSeth::tick:
float run = input_->value(Command::run);
float horizontalFactor = input_->value(Command::moveHorizontally);
float verticalFactor = input_->value(Command::moveVertically);
The code can then take the appropriate measures.
A transparent screen listing the inputs and their actions may be brought on top of the demo screen. This screen is detailed here in the user interface section.
Specification: Controllers may vibrate when some screenplay events happen at runtime, e.g. when Jan Seth gets hit or when the wall in Zone_trap falls down and clash on the floor.
Rumbles are controller vibrations over a specified duration of time. The user requests a rumble by calling PhysicalInput::addRumble. Rumble requests get stored in PhysicalInput::rumbles_. Consequently, PhysicalInput::update calls Input::Controller2::setMotorSpeed to make the controller vibrate.
Rumbles are either requested directly by the code or by scripts. JanSeth::receive calls PhysicalInput::addRumble when the character gets hit. Scripts can call the script function rumble. The script calls it when the wall falls down in Zone_trap and this call gets translated into PhysicalInput::addRumble as explained here.
rumble(Group("trap_walltrap02_heart").position(), 1, 18, 1)
|
|
|
Qube Software Limited © 2000-2004
|
|