views:

184

answers:

7

I have to create a model that stores gameplay controls for games on several platforms. I am having trouble finding the right approach.

  1. Controller buttons are different on different systems (Wii, Xbox 360, PS3 have their own specific controller buttons.)
  2. Some games are actually several games packaged as one; this means a single product can have several controls depending on the game being played.
  3. Gameplay controls for many games change depending on your in-game activity (driving/walking/flying, etc...)
  4. It's not sufficient to just store button functions since most games have several special moves that require a combination of buttons.

How would you approach this problem? Honestly, I don't know where to start!

FYI: Current database in use is MySQL

Update: Many thanks to everyone for your thoughtful and very helpful input. I am yet to choose and answer as I'm still uncertain about my approach. But this is a great starting point.

+1  A: 

You can try this for starters (EDIT: second try):

Game
----------
(PK) GameID integer
GameTitle varchar(100)

Controller
----------
(PK) ControllerID integer
ControllerDescription varchar(100)
(FK) GameID integer

Effect
----------
(PK) EffectID integer
EffectDescription varchar(100)
(FK) ControllerID integer

Buttons
----------
(PK) ButtonID integer
ButtonKey varchar(25)
(FK) EffectID integer

For example:

GameID  GameTitle
----------------------------------------------
1       Super Mario Bros.

ControllerID ControllerDescription GameID
----------------------------------------------
1            Main Controller       1

EffectID EffectDescription ControllerID
----------------------------------------------
1        Run               1
2        Jump              1
3        Pause             1
4        Move Left         1
5        Move Right        1

ButtonID ButtonKey      EffectID
----------------------------------------------
1        B              1
2        Direction Pad  1
3        A              2
4        Start          3
5        Left Pad       4
6        Right Pad      5
LittleBobbyTables
not sure that models key combos well...
Mitch Wheat
Hrm, valid point -- hadn't taken that into account. I've taken a second stab at it, not sure if I'm satisfied with it or not.
LittleBobbyTables
To allow for complex button combinations, add a fake button called "Delay" which indicates the player should pause between button presses of a combo. Maybe add a "Time" column to the Button table to allow for "a button must be held for a certain length of time" requirement. Add an OrderNumber column to the Button table to allow for the order buttons should be pressed to be specified. If buttons are to be pressed at the same time, give them the same order number.
ulty4life
+1  A: 

I'll give this a whirl :)


    controller [table] 
// list of controllers - Wii Mote etc.
    controller_id (int, PK) | title (varchar)

    game_buttons [table] 
// list of buttons on a controller A/B/X/Y/...
    button_id (int, PK) | title (varchar) | controller_id (int, FK)

    game [table] 
// game details - you could, if you want, differentiate the games by console here as well as they may have different titles even though they are similar in nature
    game_id (int, PK) | title (varchar)

    controls [table] 
// this is the main table that will combine the buttons with the games. combo_id is a foreign key to the control_combo table. So if you have a sequence of keys that calls for buttons A and then B, you would call in the same number for combo_id and ord table will tell us in what order they should be placed. If they're not part of a combo, you can leave the default combo_id to 0.

    game_id (int, PK) | button_id (int, FK) | title (varchar) | description (text) | combo_id (int) | ord

    control_combo [table]
// control_combo - the master table for button combos
    combo_id (int, PK) | title (varchar) | ord (tinyint)
Duniyadnd
+1  A: 

How about this:

/* PRODUCTS: Each product has one title and runs on one gamesystem */
(PK) ProductID int
ProductTitle varchar(100)
(FK) GameSystemID int

/* GAMES: Each game has one title and belongs to one product */
(PK) GameID int
GameTitle varchar(100)
(FK) ProductID int

/* GAMESYSTEMS: Each gamesystem has one name */
(PK) GameSystemID int
GameSystemName varchar(100)

/* GAMEACTIVITIES: Each game has one or more activities (flying, running, ..) */
(PK) GameActivityID int
(FK) GameID int
GameActivityDescription VARCHAR(100)

/* BUTTONS: Each gamesystem has certain buttons with names */
(PK) ButtonID int
(FK) GameSystemID int
ButtonName VARCHAR(100)

/* GAMEACTIONS: Each game activity provides certain game actions (fly left, fly right, ..) */
(PK) ActionID int
(FK) GameActivityID int
ActionDescription VARCHAR(100)

/* BUTTONCOMBINATIONS: Each game action is associated with a certain button or combination of buttons */
(FK) ActionID int
(FK) ButtonID int
littlegreen
+1  A: 

Console
    int id
    string name

Controller
    int id
    string name
    int console_id fk

Button
    int id
    string name
    int controller_id fk

Game
    int id 
    string name
    int parent_id fk -- game within a game

-- context within a game (default, driving, swimming)
Context
    int id
    string name
    int game_id fk

-- applicable actions within a context of a game
Action
    int id
    string name
    id context_id int

-- a set of buttons that map to an action, whether it is one button or multiple
Combination
    int id
    int action_id fk
    int button_id fk

An example of using the above structure:

Console: PS3 Game: MAG ...

Current Game State:
Context: Driving
Allowed Actions: Directionals (forward, left etc), Brake, Smoke
Allowed Combinations: List of each combination for each action

When a series of buttons are pressed, eg: L1 + DirectionRight, look up that combination in allowed combinations, find the relevant action, and execute that action.

Josh Smeaton
+1  A: 

Some controllers share common layouts but with different faces, i.e. 360 and PS3 (X is A, triangle is Y, etc). With extra peripherals like fight sticks, flight sticks, guitars, etc - they're just different faces mapping to the console's expectations as well. Since the buttons are usually defined before any controller is even molded, you can do the same.

Each mapping won't all apply to every controller, so it may not be ideal - considering modern console controllers, it should be fine. If you add in Intellivision controllers and keyboard/mouse, things might start to get weird.

// using CHAR(8) for absolutely no good reason. change at will.
CREATE TABLE button_maps (
id tinyint unsigned not null auto_increment,
map_id char(8) not null,
primary key (id),
unique key map_id (map_id)
);

INSERT INTO button_maps (map_id)
VALUES
// dual analog, any direction
('ANA_LFT'), ('ANA_RT'),
// 4-button compass face
('BT_N'), ('BT_S'), ('BT_E'), ('BT_W'),
// shoulder buttons
('BT_LT1'), ('BT_LT2'), ('BT_RT1'), ('BT_RT2'),
// system buttons
('BT_START'), ('BT_SEL'), ('BT_MENU'),
// analog stick click-in, usually called "L/R 3"
('ANA_L3'), ('ANA_R3'),
// 8-direction d-pad - add clockface points for both analogs too
('DPAD_N'), ('DPAD_S'), ('DPAD_E'), ('DPAD_W'),
('DPAD_NW'), ('DPAD_NE'), ('DPAD_SW'), ('DPAD_SE'),
// and DS stylus so it's not obvious what I'm looking at right now
('STL_TAP'), ('STL_DTAP'), ('STL_DRAG'),
// and so on

Note: I have no clue how those full-body motion control things are handled internally, good luck if you ever have to deal with them. LFOOT_HOKEYPOKEY or something.

Note 2: Seriously, don't use a char(8) there. Get detailed, but keep it general enough to apply to a generic controller style and not brand.

Now the buttons per each brand of controller, with their name (assumes a "controllers" table):

CREATE TABLE buttons (
id tinyint unsigned not null auto_increment,
controller_id tinyint unsigned not null references controllers.id,
map_id tinyint unsigned not null references button_maps.id,
button_name varchar(32) not null,
primary key (id),
unique key controller_map (controller_id, map_id)
);

INSERT INTO buttons (controller_id, map_id, button_name)
VALUES
(2, 1, 'Left Analog'), (2, 2, 'Right Analog'),
(2, 3, 'Y'), (2, 4, 'A'), (2, 5, 'B'), (2, 6, 'X'),
(2, 7, 'Left Trigger (LT)'), (2, 8, 'Right Trigger (RT)'),
(2, 9, 'Left Bumper (LB)'), (2, 10, 'Right Bumper (RB)')
// and so on.  PS3 with button shapes and R1/2, L1/2 instead of trigger/bumper

Now, for the actions a button press (or multiple buttons, or a sequence) represents to a game. This doesn't account for the context (2 & 3 of the original question), e.g. game mode or alternate button configurations, but Josh Smeaton and littlegreen already covered that.

This defines actions per each individual game, which isn't very efficient. You might be able to condense things significantly by adding a generic layer of game "types." Many games within a certain genre/perspective have common controls, and it's only becoming more common (console FPSes adding predefined Halo and CoD-style button configurations since players know them, and such). So, if you can define a set of common actions per each genre and use this only to override/extend those defaults as needed, you might be able to pull off a much cleaner solution.

First, define each action:

CREATE TABLE game_actions (
id int unsigned not null auto_increment,
game_id int unsigned not null references games.id,
action varchar(32) not null,
primary key (id)
);

INSERT INTO game_actions (game_id, action)
VALUES (1, 'Shoot'), (1, 'Reload'), (1, 'Turn Left'), (1, 'Turn Right')
// and so on

And finally, define the button presses associated with each action. The "ordinal" field is for combo sequences, like fighting game combos - single actions are 0th ordinal and sequences count up from 1, just to make them easy to differentiate. It doesn't account for timing, so you might need a "nothing" button as a rest for some of the more complex combo games (Soul Caliber et al).

CREATE TABLE game_action_buttons (
id int unsigned not null auto_increment,
game_action_id int unsigned not null references game_actions.id,
ordinal tinyint unsigned not null,
button_map_id tinyint unsigned not null references button_maps.id,
primary key (id)
);

INSERT INTO game_action_buttons (game_action_id, ordinal, button_map_id)
VALUES
(1, 0, 8), // right trigger to shoot
(2, 0, 6), // west face button (X/square) to reload
(3, 0, 7), (3, 0, 9) // combo: both bumpers for rear view look-back while driving
// and a Street Fighter shoryuken on the d-pad to show a sequence:
(4, 1, 21), // DPAD_E: right
(4, 2, 20), // DPAD_S: down
(4, 3, 26), (4, 3, 4) // DPAD_SE + BT_S: down/right + fierce... i think.

(Disclaimer: I created a similar database for a game studio I worked at. Not quite the same, but similar enough that I'm kind of intentionally leaving a lot out. Sorry! Hopefully that's enough to kickstart some ideas though, and it's a fun problem.)

tadamson
+1  A: 

I only give it a short thought but I think you can use something like this (I was to lazy to add ER 'forks' but top table references bottom table(s)):

data model.

  • button - is a button on a controller, I assume you need to identify these also with a type so you could identify things like pressed, direction, pressure etc...
  • consle - stores wii, xbox, ...
  • gameplay - is the level your in and each level has a number of moves (or actions if you prefer) these actions should execute a piece of code in the end to make something happen in this game level.
  • console-move - is the combination of buttons to execute a certain move on a specific console. If you need to press a button combination in the wii and not on the xbox, then should be possible

optionally you could link button to console

Janco
+1  A: 

I'll give it a try :)

1) You'll need a table for systems

2) You'll need a table for packages (with a nullable reference to a parent), a table with games and a table to link games with packages. This ensures that a game can be part of different packages. It's not allowing different packages to have different "specialversions" of the same game, though. But that wasn't a requirement :)

3) I'm not sure if this is the same as 2), if not: a table with a reference to a game, if: see 2)

4) You'll need a table for an action ("sequence") with a reference to a gamepart, then you'll need a table for a key-combination, with a reference to the sequence. Finally, you'll need a table for a particular key, with a reference to a combination.

I think this will cover it, though I have som concerns regarding joysticks, mouse etc. You might want to split the "key"-table into several tables to avoid to many columns in that table, but that's a decision you have to take depending on how you are planning to access your database etc.

Onkelborg