A downloadable game


What my project does

  • My project reads Input from the Controller and provides easy to use functions for retrieving the button and stick states of the controller. 
  • Here is a list of functions from my interface.


    bool IsConnected();
    
    cResult LoadBindingsFromFile(const 
        std::string& i_keyBindingsPath);
    
    void RumbleControllerForSeconds(float i_amount,
        float i_seconds);
    
    void UpdateState();
    
    bool IsButtonPressed(
        ButtonCodes::eButtonKeyCodes i_buttonCode);
    
    float GetTriggerAnalogInput(
        ButtonCodes::eAnalogButtons i_trigger);
    
    float GetStickAnalogInputXAxis(
        ButtonCodes::eAnalogButtons i_stick);
    
    float GetStickAnalogInputYAxis(
        ButtonCodes::eAnalogButtons i_stick);
    
    double GetStickDirection(
        ButtonCodes::eAnalogButtons i_stick);
    
    bool SubscribeToKeyPressEvent(
        std::function<void(
        const eae6320::GamepadInput::
        ButtonCodes::eButtonKeyCodes& i_button)> i_subscriber);
    
    void NotifyEvent(
        const ButtonCodes::eButtonKeyCodes& i_button);
    
    bool IsActionButtonPressed(std::string i_action);
    
    void UpdateBasedOnTime(
        const float i_elapsedSecondCount_sinceLastUpdate);
    
    cResult CleanUp();

As you can see most of them are self explainable with the function names. User can detect a button press by calling the IsButtonPressed function by sending the button code which are defined here

namespace ButtonCodes
{
    enum eButtonKeyCodes
    {
        CONTROLLER_FACE_BUTTON_UP = 0,
        CONTROLLER_FACE_BUTTON_DOWN = 1,
        CONTROLLER_FACE_BUTTON_LEFT = 2,
        CONTROLLER_FACE_BUTTON_RIGHT = 3,
        CONTROLLER_DPAD_UP = 4,
        CONTROLLER_DPAD_DOWN = 5,
        CONTROLLER_DPAD_LEFT = 6,
        CONTROLLER_DPAD_RIGHT = 7,
        CONTROLLER_LEFT_BUMPER = 8,
        CONTROLLER_RIGHT_BUMPER = 9,
        CONTROLLER_LEFT_STICK_BUTTON = 10,
        CONTROLLER_RIGHT_STICK_BUTTON = 11,
        CONTROLLER_START_BUTTON = 12,
        CONTROLLER_BACK_BUTTON = 13,
        CONTROLLER_LEFT_TRIGGER_BUTTON = 14,
        CONTROLLER_RIGHT_TRIGGER_BUTTON = 15,
    };
    enum eAnalogButtons
    {
        CONTROLLER_LEFT_TRIGGER_ANALOG = 0,
        CONTROLLER_RIGHT_TRIGGER_ANALOG = 1,
        CONTROLLER_LEFT_STICK_ANALOG = 2,
        CONTROLLER_RIGHT_STICK_ANALOG =3,
    };
}

I made different enums for clickable buttons and analog buttons( axis based buttons). 

There are functions to read the analog input from triggers and both the sticks X and Y axis analog values.

There is also a subscibing functionality for the keypress events, you subscirbe to the keypress event by passing the function you want to be invoked when a keypress happens with the info of the key press, this function will be called when the corresponding event is triggered. 

One more useful function is getting keypress based on the action. You can specify which actions to be mapped to which buttons based on a lua file with the extension .keybinding

Here are the guidelines to follow. This file is also available in the KeyBindingsBuilder project under the name readme.info

This document helps you understand the guidelines in using the .keybinding files
Each button is mapped to a string which will be speccified below
If you want to bind an action to a button, the button value must match one of the strings that are mentioned below
Button strings to follow:
"FaceUp",
"FaceDown",
"FaceRight",
"FaceLeft",
"DpadUp",
"DpadDown",
"DpadRight",
"DpadLeft",
"RightBumper",
"LeftBumper",
"LeftStick",
"RightStick",
"LeftTrigger",
"RightTrigger",
"Start",
"Back"
Sample usage of .keybinding files (you can also check my FirstDraft.keybinding file from the MyGame Project's content folder)
return
{
 {
    Action = "Up",
    Button = "DpadUp",
 },
}

Here is a sample

return
{
    {
        Action = "Up",
        Button = "FaceUp",
    },
    {
        Action = "Down",
        Button = "FaceDown",
    },
    {
        Action = "Left",
        Button = "FaceLeft",
    },
    {
        Action = "Right",
        Button = "FaceRight",
    },
    
}

Again The values for buttons are strings which need to be consistent with the strings specified above as in the readme.info.

One other function I’ve implemented is getting the direction of the stick 

Pointed down will be 0 degrees, left will be 90 degrees, Up will be 180 and right will be 270, It rotates in clock wise direction from 0 to 360, with 0 and 360 pointing down.

There is also a function to rumble the controller, It takes two parameters one is the amount, and other one is time in simulation seconds it needs to rumble.

Here is a sample implementation of some functions from my cMyGame.cpp file

Button Press sample

specify the button using the enum eButtonKeyCodes

If(GamepadInput::IsButtonPressed(GamepadInput::ButtonCodes::CONTROLLER_FACE_BUTTON_LEFT)) {
    m_cameraToUse->m_rigidBodyState->velocity = 
    Math::cMatrix_transformation::cMatrix_transformation(
    m_camera->m_rigidBodyState->orientation,
    m_camera->m_rigidBodyState->position
    ).GetRightDirection() * -moveSpeed;
}

Trigger analog sample

Specify the trigger by using enum eAnalogButtons

if(GamepadInput::GetTriggerAnalogInput(GamepadInput::ButtonCodes::CONTROLLER_LEFT_TRIGGER_ANALOG)) {
    m_cameraToUse->m_rigidBodyState->velocity = 
    Math::cMatrix_transformation::cMatrix_transformation(
    m_camera->m_rigidBodyState->orientation,
    m_camera->m_rigidBodyState->position
    ).GetBackDirection() * -moveSpeed;
}

Action-based Input Sample

Pass the string action you specified in your lua file

if (GamepadInput::IsActionButtonPressed("Right")) {
    m_cameraToUse->m_rigidBodyState->velocity = 
    Math::cMatrix_transformation::cMatrix_transformation(
    m_camera->m_rigidBodyState->orientation,
    m_camera->m_rigidBodyState->position)
    .GetRightDirection() * moveSpeed;
}

Rumble Effects

The first argument to be passed is the strength of the rumble (Its a value between 0 to 1), and the second argument is the amount of time to rumble in seconds(not actual time but simulation time)

if (UserInput::IsKeyPressed('H')) {
    eae6320::GamepadInput::RumbleControllerForSeconds(0.5f, 5);
 
}

 

 

 

 

 

Stick Input

Specify the stick by using the enum eAnalogButtons

float xInput = GamepadInput::GetStickAnalogInputXAxis(GamepadInput::ButtonCodes::CONTROLLER_LEFT_STICK_ANALOG);
 
float yInput = GamepadInput::GetStickAnalogInputYAxis(GamepadInput::ButtonCodes::CONTROLLER_LEFT_STICK_ANALOG);
 
float xValue = Math::cMatrix_transformation::
    cMatrix_transformation(
    m_sphereGameobject->m_rigidBodyState->orientation,
    m_sphereGameobject->m_rigidBodyState->position
    ).GetRightDirection().x * xInput;
    
float yValue = Math::cMatrix_transformation::
    cMatrix_transformation(
    m_sphereGameobject->m_rigidBodyState->orientation,
    m_sphereGameobject->m_rigidBodyState->position
    ).GetUpDirection().y * yInput;
 
m_sphereGameobject->m_rigidBodyState->velocity = Math::sVector(xValue, yValue, 0.0f) * moveSpeed;

 

Stick Direction

The direction returned will be in degrees, you can convert them to radians by using the formula I used below.

double angle = GamepadInput::GetStickDirection(GamepadInput::ButtonCodes::CONTROLLER_RIGHT_STICK_ANALOG);
float angleInRadians = (float)(angle * 3.1415) / 180;
if (angle != 0.0) {
    m_torusGameobject->m_rigidBodyState->orientation = 
        eae6320::Math::cQuaternion(
        angleInRadians, 
        eae6320::Math::sVector(0.0, 1.0, 0.0)
        );
}

 

Callback Function

void eae6320::cMyGame::ControllerKeyPressCallback(
const eae6320::GamepadInput::
ButtonCodes::eButtonKeyCodes& i_button)
{
float angle = 90.0f;
float angleInRadians = (float)(angle * 3.1415) / 180;
switch (i_button) {
        case eae6320::GamepadInput::
        ButtonCodes::eButtonKeyCodes::CONTROLLER_DPAD_UP:
            m_torusGameobject->m_rigidBodyState->orientation =
            m_torusGameobject->m_rigidBodyState->orientation * 
            eae6320::Math::
            cQuaternion(
            angleInRadians, 
            eae6320::Math::sVector(0.0, 1.0, 0.0)
            );
            break;
            …./
    }
}

 

Subscribing to call back function

 

std::function<void(const eae6320::GamepadInput::ButtonCodes::eButtonKeyCodes & i_button)> callback;
 
callback = std::bind(&cMyGame::ControllerKeyPressCallback, this, std::placeholders::_1);
 
eae6320::GamepadInput::SubscribeToKeyPressEvent(callback);

 

 

Things you need to do in order to use my project:

(Download the source code from below, add them to your project, The GamepadInput project is part of the Engine and KeyBindingsBuilder is part of the Tools)

 

  • Add references first

References of my GamepadInput project

References of my KeyBindings Builder project

 You also need to add the property sheets for both my projects the same way we did for all the other assignments. EngineDefaults first and then opengl for 32 bit direct3d for 64 ones.

  • Modify the AssetsToBuild.lua to build the keybindings lua files

 

Add this to AssetsToBuild.lua. Make sure to have the extension as keybinding and the files will be in the folder named KeyBindings in Content folder

 

 

  • Modify the AssetBuildFuncitons.lua to use KeyBindingsBuilder project to build the .keybindings files

 

This code is to be added to the AssetBuildFunctions.lua

 

 

  • Make sure to add GamepadInput to the references list of Application project

  • Make the BuildMyGameAssets depend on KeyBindingBuilder project
  • More Stuff you need to do

You need to call two functions of my project from an Update function which is called  periodically. These are important to keep track of the controller state and know how much time has been passed between update calls. That is everything you need to do in order to use my project.

 

This is from a source file which is executed periodically.

 

 

 

Calling UpdateState at the end of this Update function

 

Thats it you are good to go. (of course there is the adding of GamepadInput.h header file to wherever you wanna use the functions)

  Key features:

  • I created a builder project which reads a lua file and converts into binary format
  • Implemented a platform-independent interface. 
  • Differentiated platform-specific code into seperate .cpp files. 
  • I made my interface as easy to use as possible. 
  • I’ve implemented many different functions thinking as a gameplay engineer.  

Things I learned in this process

  • One interesting thing which I already knew but never tried was passing functions as arguments to other functions. I used std::function to do this. 
  • I guess the most challenging part was to implement the keypress call back functions. First, I tried doing the windows implemented native c++ events. But that didn’t make any sense as I made progress. Then I implemented callbacks using the standard publisher observer pattern which was suggested by JP.
  • Most of the things I did in my project were pretty straightforward, following the things I liked from  my professor JP's class.

Download

Download
GamepadInput project 8 kB
Download
KeyBindingsBuilder project 5 kB

Leave a comment

Log in with itch.io to leave a comment.