Last active
August 29, 2015 14:12
-
-
Save JordanBell/52b2930b2cfb5bc6fe33 to your computer and use it in GitHub Desktop.
A class, TestingConsole, which allows quick run-time function calls via SDL input, and an example implementation, CGConsole.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// CGConsole.cpp | |
// Testing-Console | |
// | |
// Created by Jordan Bell on 15/10/2014. | |
// Copyright (c) 2014 Jordan Bell. All rights reserved. | |
// | |
#include "CGConsole.h" | |
#include "Coin.h" | |
#include "Player.h" | |
#include "Game.h" | |
#include "Inventory.h" | |
#include "LaunchData.h" | |
#include "ParticleSnow.h" | |
#include "Camera.h" | |
#define DIVIDES(a, b) (a%b == 0) | |
/* Temporary calculation function for printing arbitrary calculations used in debugging. | |
Override the contents of this function for your own calculations when appropriate. */ | |
void Calc(vector<int> args) | |
{ | |
// Nothing | |
} | |
/* Launch all coins at the player */ | |
void Pull(vector<int> args) | |
{ | |
int suppression = args.empty() ? 1 : args.front(); | |
printf("supp: %d\n ? %d\n\n", suppression, args.empty()); | |
for (Throwable* t : g_throwables) | |
{ | |
if (!t->IsAirborne()) { | |
t->LaunchTo(g_player->x, g_player->y, suppression); | |
} | |
} | |
} | |
/* Make a small explosion of simple particles */ | |
void ParticleExplosion(vector<int> args) | |
{ | |
if (args.front()) | |
{ | |
int s_x, s_y; // Start coords | |
s_x = screen->w/2 - TILE_SIZE/2; | |
s_y = screen->h/2 - TILE_SIZE/2+2*TILE_SIZE; | |
int e_x, e_y; // End coords | |
list<Particle*> particles; | |
int num = args.front(); | |
for (int i = 0; i < num; i++) | |
{ | |
// Dirt flies somewhere around behind the player | |
e_x = s_x + (rand() % (6*TILE_SIZE)) - 3*TILE_SIZE; | |
e_y = s_y + (rand() % (4*TILE_SIZE)) - 2*TILE_SIZE; | |
ParticleSimple* part = new ParticleSimple(s_x, s_y, e_x, e_y); | |
particles.push_back(part); | |
g_game->addGameObject(part); | |
} | |
for (Particle* p : particles) | |
p->Launch(1); | |
} | |
} | |
/* Make all coins bounce in place */ | |
void BounceUp(vector<int> args) | |
{ | |
for (Throwable* t : g_throwables) | |
if (!t->IsAirborne()) | |
t->Bounce( rand()%15 + 5); | |
} | |
/* Make all coins bounce in place */ | |
void SetBouncy(vector<int> args) | |
{ | |
if (args.front()) | |
{ | |
for (Throwable* t : g_throwables) | |
if (!t->IsAirborne()) | |
t->SetBouncy(args.front()); | |
} | |
} | |
/* Enables Abilty: Pull. Press 1 to use. */ | |
void TogglePull(vector<int> args) | |
{ KeyCode::ToggleBool1(); } | |
/* Home coins toward the player */ | |
void HomeIn(vector<int> args) | |
{ | |
int distance = args.size() > 0 ? args.at(0) : 400; | |
int speed = args.size() > 1 ? args.at(1) : 10; | |
list<Throwable*> closeThrowables = Throwable::ThrowablesAroundPlayer(distance); | |
for (Throwable* t : closeThrowables) | |
{ | |
if (!t->IsAirborne()) { | |
t->SetHoming(distance, speed); | |
} | |
} | |
} | |
/* Forces Abilty: Smash. Specifies radius. */ | |
void Smash(vector<int> args) | |
{ if (args.front()) g_player->Smash(args.front()); } | |
/* Forces Ability: Smash Wave */ | |
void SmashWave(vector<int> args) | |
{ g_player->SmashWave(); } | |
/* Toggles coin magnetism */ | |
void ToggleMagnetism(vector<int> args) | |
{ //g_player->SetMagnetic( !g_player->IsMagnetic() ); | |
} | |
/* Turn off all sounds */ | |
void Mute(vector<int> args) | |
{ g_game->Mute(); } | |
/* Turn on all sounds */ | |
void Unmute(vector<int> args) | |
{ g_game->Unmute(); } | |
/* Add any number of coins to the wallet */ | |
void AddCoins(vector<int> args) | |
{ | |
if (args.front()) | |
{ | |
const int numCoins = args.front(); | |
// Get the current room element | |
Element ele = g_camera->GetRoomFocus()->GetElement(); | |
Inventory::GetCoinWallet(ele)->Add(numCoins); | |
} | |
} | |
/* Add a ludicrous number of coins to the wallet of the current room */ | |
void AddCoins_Large(vector<int> args) | |
{ Inventory::GetCoinWallet(g_camera->GetRoomFocus()->GetElement())->Add(99999999); } | |
/* Doubles the player's coins in their room */ | |
void DoubleCoins(vector<int> args) | |
{ | |
int currentNumber = Inventory::GetCoinWallet(g_camera->GetRoomFocus()->GetElement())->GetAmount(); | |
Inventory::GetCoinWallet(g_camera->GetRoomFocus()->GetElement())->Add(currentNumber * 2); | |
} | |
/* Dispense Coins */ | |
void Dispense(vector<int> args) | |
{ if (args.front()) g_camera->GetRoomFocus()->GetDispenser()->ForceDispense(args.front()); } | |
/* Print Information about the Tier's Launch Info */ | |
void Talk(vector<int> args) | |
{ | |
g_player->Say("Hey."); | |
} | |
/* Jordan's debug preset */ | |
void j(vector<int> args) | |
{ | |
TogglePull(args); | |
//ToggleMagnetism(args); | |
//// Toggle Mute | |
//if (g_game->IsMuted()) | |
// Unmute(args); | |
//else | |
// Mute(args); | |
/*g_machine->ForceDispense(1000); | |
Mute(args);*/ | |
} | |
/* Set the rendering offset values */ | |
void SetRenderOffset(vector<int> args) | |
{ | |
s_renderingOffset_x = args.at(0); | |
s_renderingOffset_y = args.at(1); | |
} | |
/* Draw the player's hit box and AABB */ | |
void ShowPlayerCollisionBoxes(vector<int> args) | |
{ | |
g_player->ToggleDebug(); | |
} | |
CGConsole::CGConsole(void) | |
{ | |
// All recognised commands | |
m_commands.push_back( | |
Command("pull", | |
"Pulling all coins toward the player.", | |
"Launches all coins to the player.", | |
Pull) | |
); | |
m_commands.push_back( | |
Command("bounce", | |
"Bouncing.", | |
"Bounces all throwables up into the air.", | |
BounceUp) | |
); | |
m_commands.push_back( | |
Command("set_bounce", | |
"Bouncing set.", | |
"Pass an int boolean to set the bounciness of all throwables.", | |
SetBouncy) | |
); | |
m_commands.push_back( | |
Command("toggle_pull", | |
"Pull toggled. When enabled, press 1 to pull all coins toward the player.", | |
"Toggles the pull ability. Activate by pressing hotkey: 1", | |
TogglePull) | |
); | |
m_commands.push_back( | |
Command("mag", | |
"Magnetism Toggled", | |
"Toggles player magnetism, making it easier to collect coins.", | |
ToggleMagnetism) | |
); | |
m_commands.push_back( | |
Command("smash", | |
"Smash Activated.", | |
"Simulates the 'Smash' Ability.", | |
Smash) | |
); | |
m_commands.push_back( | |
Command("smash_wave", | |
"Wave Smash activated.", | |
"Simulates the 'Smash Wave' Ability.", | |
SmashWave) | |
); | |
m_commands.push_back( | |
Command("mute", | |
"Muted all sounds.", | |
"Mutes coin collection sound effects.", | |
Mute) | |
); | |
m_commands.push_back( | |
Command("unmute", | |
"Restored all sounds.", | |
"Restores all coin collection sound effects.", | |
Unmute) | |
); | |
m_commands.push_back( | |
Command("add_coins", | |
"Coins added.", | |
"Adds a specified number of coins to the player's wallet.", | |
AddCoins) | |
); | |
m_commands.push_back( | |
Command("max", | |
"Coins added. So many coins.", | |
"Adds 999999999 coins to the player's wallet.", | |
AddCoins_Large) | |
); | |
m_commands.push_back( | |
Command("double_coins", | |
"Coins have been doubled", | |
"Doubles the player's coins in their wallet.", | |
DoubleCoins) | |
); | |
m_commands.push_back( | |
Command("dispense", | |
"Dispensing...", | |
"Dispenses a specified number of coins directly into the game. May be unstable.", | |
Dispense) | |
); | |
m_commands.push_back( | |
Command("home", | |
"Homing in on player.", | |
"Sets all collectables' homing property to true.", | |
HomeIn) | |
); | |
m_commands.push_back( | |
Command("calc", | |
"Calculating: ", | |
"Performs a calculation. May change depending on the developer's choice of debug calculation.", | |
Calc) | |
); | |
m_commands.push_back( | |
Command("offset", | |
"Setting the offset ", | |
"Gives a manual value to the rendering offset values, x and y respectively.", | |
SetRenderOffset) | |
); | |
m_commands.push_back( | |
Command("j", | |
"Yes sir.", | |
"Jordan's preset of debug calls. Changes upon his mood. Originally [mag], [toggle_pull] and [mute].", | |
j) | |
); | |
m_commands.push_back( | |
Command("exp", | |
"Exploding particles", | |
"Adds a small, standard explosion of simple particles at (320,320).", | |
ParticleExplosion) | |
); | |
m_commands.push_back( | |
Command("talk", | |
"", | |
"Tests speech bubbles by making the player talk", | |
Talk) | |
); | |
m_commands.push_back( | |
Command("collision_debug", | |
"", | |
"Draws the player's hit box and AABB for collision debugging.", | |
ShowPlayerCollisionBoxes) | |
); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// CGConsole.h | |
// Testing-Console | |
// | |
// Created by Jordan Bell on 15/10/2014. | |
// Copyright (c) 2014 Jordan Bell. All rights reserved. | |
// | |
#pragma once | |
#include "testingconsole.h" | |
class CGConsole : | |
public TestingConsole | |
{ | |
public: | |
CGConsole(void); | |
~CGConsole(void) {} | |
}; | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// TestingConsole.cpp | |
// Testing-Console | |
// | |
// Created by Jordan Bell on 15/10/2014. | |
// Copyright (c) 2014 Jordan Bell. All rights reserved. | |
// | |
#include "TestingConsole.h" | |
#include <cstdlib> | |
#include <iostream> | |
void TestingConsole::Open(void) | |
{ | |
m_active = true; | |
printf("Console Active. Enter 'help' for a list of commands."); | |
SDL_EnableUNICODE( SDL_ENABLE ); | |
} | |
void TestingConsole::Close(void) | |
{ | |
m_active = false; | |
printf("\nConsole Inactive\n"); | |
SDL_EnableUNICODE( SDL_DISABLE ); | |
} | |
void TestingConsole::Toggle(void) | |
{ | |
m_active ? Close() : Open(); | |
if (m_active) NewLine(); | |
} | |
void TestingConsole::KeyIn(SDL_keysym& keysym) | |
{ | |
SDLKey key = keysym.sym; | |
if (key == SDLK_BACKSPACE) // Backspace | |
{ | |
// Pop the last element of the string in the line | |
if (m_line.size() > 0) { | |
m_line.pop_back(); | |
printf("\b \b"); // Backspace | |
} | |
} | |
else if (key == SDLK_RETURN) // Enter/Return | |
{ | |
// Enter the code into the console | |
printf("\n"); | |
Enter(); | |
NewLine(); | |
} | |
else if (key == SDLK_UP) // Traverse UP along the command memory | |
{ | |
string commandStr = ""; | |
if (!m_commandMemory.empty()) | |
{ | |
if (m_memoryIterator != m_commandMemory.begin()) { | |
m_memoryIterator--; | |
commandStr = *m_memoryIterator; | |
} | |
} | |
if (commandStr != "") | |
OverrideLine(commandStr); | |
} | |
else if (key == SDLK_DOWN) // Traverse DOWN along the command memory | |
{ | |
string commandStr = ""; | |
if (!m_commandMemory.empty()) | |
{ | |
if (m_memoryIterator != m_commandMemory.end()) | |
{ | |
m_memoryIterator++; | |
if (m_memoryIterator != m_commandMemory.end()) | |
commandStr = *m_memoryIterator; | |
} | |
} | |
OverrideLine(commandStr); | |
} | |
else | |
{ | |
// Otherwise, just input the character | |
char keyChar = keysym.unicode; | |
if (ValidationInput(keyChar)) | |
printf("%c", keyChar); | |
} | |
} | |
void TestingConsole::OverrideLine(string _line) | |
{ | |
// Replace the output on the command line with the new string | |
int strSize = m_line.size(); | |
for (int i = 0; i < strSize; i++) | |
printf("\b \b"); | |
// Set the new line | |
m_line = _line; | |
// Print it | |
printf("%s", m_line.c_str()); | |
} | |
void TestingConsole::Enter(void) | |
{ | |
// Add this line to the list of entered command strings | |
m_commandMemory.remove(m_line); | |
m_commandMemory.push_back(m_line); | |
m_memoryIterator = m_commandMemory.end(); | |
// Separate the activation command from its arguments, if any | |
pair<string, string> codeArgumentsPair = SplitCommandCode(m_line); | |
string activationCode = codeArgumentsPair.first; | |
vector<int> arguments = ExtractArguments(codeArgumentsPair.second); | |
if (m_line == "help") { | |
CommandHelp(); | |
return; | |
} | |
// Search through all of the commands for a match | |
for (Command possibleCommand : m_commands) | |
{ | |
if (activationCode == possibleCommand.code) | |
{ | |
try | |
{ | |
// Execute the function | |
possibleCommand.func(arguments); | |
// Output the command's message, ie "Pull activated." | |
printf("%s", possibleCommand.message.c_str()); | |
} | |
catch (exception e) | |
{ | |
// If, for some reason, the called function does not operate correctly and throws an exception, fail and notify the user. Don't crash the game. | |
printf("Error. Called function threw an exception: %s", e.what()); | |
} | |
catch (...) | |
{ | |
// For everything else that isn't an exception, be more vague. | |
printf("Error caught. Called function and something went wrong."); | |
} | |
// Reset the m_line | |
m_line.clear(); | |
// No point to continue searching | |
return; | |
} | |
} | |
// If no commands are recognised by now | |
printf("Command [%s] not recognised.", activationCode.c_str()); | |
m_line.clear(); | |
} | |
void TestingConsole::CommandHelp(void) | |
{ | |
printf("Available commands:\n\n"); | |
for (Command c : m_commands) | |
{ | |
printf("[%s] = %s\n", | |
c.code.c_str(), | |
c.help.c_str()); | |
} | |
NewLine(); | |
} | |
pair<string, string> TestingConsole::SplitCommandCode(string line) | |
{ | |
pair<string, string> codeArgumentsPair; // Return | |
string head = ""; | |
string tail = line; | |
for (unsigned int i = 0; i < line.size(); i++) | |
{ | |
char c = line.at(i); | |
tail.erase(0, 1); | |
if (c == ' ') { | |
// End of command code, beginning of arguments | |
codeArgumentsPair.first = head; | |
codeArgumentsPair.second = tail; | |
return codeArgumentsPair; | |
} | |
else | |
head.push_back(c); | |
} | |
codeArgumentsPair.first = line; | |
codeArgumentsPair.second = ""; | |
return codeArgumentsPair; | |
} | |
vector<int> TestingConsole::ExtractArguments(string argumentsString) | |
{ | |
vector<int> r_args; | |
string head = ""; | |
string tail = argumentsString; | |
for (int i = 0; i < argumentsString.size(); i++) | |
{ | |
char c = argumentsString.at(i); | |
tail.erase(0, 1); | |
if (c == ' ') { | |
r_args.push_back(atoi(head.c_str())); | |
head = ""; | |
} | |
else | |
{ | |
head.push_back(c); | |
} | |
} | |
// Add the last argument | |
if (head != "") | |
r_args.push_back(atoi(head.c_str())); | |
return r_args; | |
} | |
bool TestingConsole::ValidationInput(char keyChar) | |
{ | |
// All valid character types | |
bool isMisc = ((keyChar == ' ') || (keyChar == '_')); | |
bool isNumber = ((keyChar >= '0') && (keyChar <= '9')); | |
bool isLowercase = ((keyChar >= 'a') && (keyChar <= 'z')); | |
bool isUppercase = ((keyChar >= 'A') && (keyChar <= 'Z')); | |
// Add the character if it is any of the above | |
if (isMisc || isNumber || isLowercase || isUppercase) | |
{ | |
//Append the character | |
m_line += (char)keyChar; | |
} | |
return (isMisc || isNumber || isLowercase || isUppercase); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// TestingConsole.h | |
// Testing-Console | |
// | |
// Created by Jordan Bell on 15/10/2014. | |
// Copyright (c) 2014 Jordan Bell. All rights reserved. | |
// | |
#pragma once | |
#include <string> | |
#include <list> | |
#include <functional> | |
#include <type_traits> | |
#include <vector> | |
#include "SDL.h" | |
using namespace std; | |
class TestingConsole | |
{ | |
public: | |
TestingConsole(void) : m_active(false), m_prompt("~: "), m_memoryIterator(m_commandMemory.begin()) {} | |
~TestingConsole(void) {} | |
// Activate or Deactivate the Testing Console for input | |
void Toggle(void); | |
// Return whether or not the Testing Console is currently active | |
bool IsActive(void) { return m_active; } | |
/* Enter the current m_line into the console, invoking any corresponding functions. */ | |
void Enter(void); | |
// Enter a key into the Testing Console | |
void KeyIn(SDL_keysym& keysym); | |
protected: | |
/* | |
A struct containing information pertaining to the various commands that can be recognised by the console. | |
Object of this struct can be instantiated in subclasses of the Testing Console. Otherwise, no commands are recognised. | |
*/ | |
struct Command | |
{ | |
// Standard Constructor | |
Command(string _code, string _message, void (*_func)(vector<int>)) | |
: code(_code), message(_message), help("No description."), func(_func) {} | |
// Constructor, with a help message defined for the Help menu | |
Command(string _code, string _message, string _help, void (*_func)(vector<int>)) | |
: code(_code), message(_message), help(_help), func(_func) {} | |
string code; // The string that invokes a console response | |
string help; // The description displayed on the help menu | |
string message; // The response that is printed to acknowledge its activation | |
void (*func)(vector<int>); // The function to be called when the matching string is enterred. | |
}; | |
// The list of commands recognised by the testing console | |
list<Command> m_commands; | |
private: | |
// The "prompt" displayed in the console before the user input | |
string m_prompt; | |
// The list of previously enterred commands, cycled through using the UP and DOWN keys | |
list<string> m_commandMemory; | |
// The iterator through the list of command memories | |
list<string>::iterator m_memoryIterator; | |
// The string currently enterred into the console | |
string m_line; | |
// Defines whether or not this console will accept input | |
bool m_active; | |
// Returns a pair of strings. The first being the argument's activation code, the second being its arguments | |
static pair<string, string> SplitCommandCode(string line); | |
// Returns a vector of arguments from a string of arguments, separated by spaces | |
static vector<int> ExtractArguments(string argumentsString); | |
// Open the console, enabling SDL unicode input and prompting the user | |
void Open(void); | |
// Close the console, notifying the user of its closing and disabling SDL unicode | |
void Close(void); | |
/* | |
* Add a character to the m_line, given that it is valid. Ignore, if not. | |
* Take a keysym object containing relevant information for validation | |
* Return a boolean indicating the validity of that key character | |
*/ | |
bool ValidationInput(char keysym); | |
// Print the Help menu - all of the currently held commands, and their corresponding descriptions, if provided. | |
void CommandHelp(void); | |
// Add a new line, clearing the current m_line value and starting again | |
void NewLine(void) { m_line.clear(); printf("\n%s", m_prompt.c_str()); } | |
// Override m_line's value with a given string, and delete its output in the console | |
void OverrideLine(string _line); | |
}; | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment