Implementé lo siguiente como una consola para un juego opengl que estaba escribiendo hace un tiempo. No es de ninguna manera una respuesta definitiva a su pregunta, pero funcionó para mí y es posible que obtenga algo útil de ella.
Los 2 archivos se encuentran al final de esta publicación. Es poco probable que el código se ejecute directamente, ya que hay uno para 2 archivos de encabezado de biblioteca que no voy a incluir. Si quieres la fuente completa, házmelo saber.
Básicamente, la clase de consola le permite agregar punteros variables que se pueden cambiar en tiempo de ejecución. Acepta la entrada de los mensajes de eventos de Windows. (El manejo real de la entrada se realiza en otro lugar) El análisis de comandos se realiza en el método ProcessInput() y las variables se actualizan en el método ChangeVariable().
Una palabra de advertencia. Este método esencialmente les da a los usuarios de la consola acceso directo a las ubicaciones de memoria de la variable individual. Esto requiere una buena validación de entrada para garantizar que el usuario no pueda causar que la aplicación se bloquee en el tiempo de ejecución. Si alguna vez me senté e intenté hacer otra consola, probablemente haría las cosas un poco diferente. Sin embargo, espero que esto te brinde un poco de ayuda.
El archivo de cabecera:
#ifndef CONSOLE_H
#define CONSOLE_H
#include <vector>
#include <map>
#include <string>
#include "Singleton.h"
#include <Windows.h>
#include "Enumerations.h"
#include "StringConversion.h"
class Console
{
public:
Console();
~Console();
void Update(std::vector<WPARAM> pressedKeys);
void AddInt(std::string varName, int *ptrToInt);
void AddFloat(std::string varName, float *ptrToFloat);
void AddLong(std::string varName, long *ptrToLong);
void AddBool(std::string varName, bool *ptrToBool);
const std::string &GetCurrentText();
const std::vector<std::string> &GetPreviousText();
private:
std::map<std::string, int *> m_Ints;
std::map<std::string, float *> m_Floats;
std::map<std::string, long *> m_Longs;
std::map<std::string, bool *> m_Bools;
std::map<std::string, std::string> m_Variables;
std::vector<std::string> m_PrevConsoleText;
std::string m_CurrInput;
int m_PrevSelection;
bool ProcessInput();
void ChangeVariable(const std::string &varName, const std::string &value);
};
typedef Singleton<Console> g_Console;
#endif // CONSOLE_H
El archivo CPP:
#include "Console.h"
Console::Console()
{
m_PrevSelection = 0;
}
Console::~Console()
{
}
void Console::AddInt(std::string varName, int *ptrToInt)
{
m_Ints[varName] = ptrToInt;
m_Variables[varName] = "int";
}
void Console::AddFloat(std::string varName, float *ptrToFloat)
{
m_Floats[varName] = ptrToFloat;
m_Variables[varName] = "float";
}
void Console::AddLong(std::string varName, long *ptrToLong)
{
m_Longs[varName] = ptrToLong;
m_Variables[varName] = "long";
}
void Console::AddBool(std::string varName, bool *ptrToBool)
{
m_Bools[varName] = ptrToBool;
m_Variables[varName] = "bool";
}
void Console::ChangeVariable(const std::string &varName, const std::string &value)
{
//*(m_Bools[varName]) = value;
std::string temp = m_Variables[varName];
if(temp == "int")
{
//*(m_Ints[varName]) = fromString<int>(value);
}
else if(temp == "float")
{
//*(m_Floats[varName]) = fromString<float>(value);
}
else if(temp == "long")
{
//*(m_Longs[varName]) = fromString<long>(value);
}
else if(temp == "bool")
{
if(value == "true" || value == "TRUE" || value == "True")
{
*(m_Bools[varName]) = true;
}
else if(value == "false" || value == "FALSE" || value == "False")
{
*(m_Bools[varName]) = false;
}
}
}
const std::string &Console::GetCurrentText()
{
return m_CurrInput;
}
void Console::Update(std::vector<WPARAM> pressedKeys)
{
for(int x = 0; x < (int)pressedKeys.size(); x++)
{
switch(pressedKeys[x])
{
case KEY_A:
m_CurrInput.push_back('a');
break;
case KEY_B:
m_CurrInput.push_back('b');
break;
case KEY_C:
m_CurrInput.push_back('c');
break;
case KEY_D:
m_CurrInput.push_back('d');
break;
case KEY_E:
m_CurrInput.push_back('e');
break;
case KEY_F:
m_CurrInput.push_back('f');
break;
case KEY_G:
m_CurrInput.push_back('g');
break;
case KEY_H:
m_CurrInput.push_back('h');
break;
case KEY_I:
m_CurrInput.push_back('i');
break;
case KEY_J:
m_CurrInput.push_back('j');
break;
case KEY_K:
m_CurrInput.push_back('k');
break;
case KEY_L:
m_CurrInput.push_back('l');
break;
case KEY_M:
m_CurrInput.push_back('m');
break;
case KEY_N:
m_CurrInput.push_back('n');
break;
case KEY_O:
m_CurrInput.push_back('o');
break;
case KEY_P:
m_CurrInput.push_back('p');
break;
case KEY_Q:
m_CurrInput.push_back('q');
break;
case KEY_R:
m_CurrInput.push_back('r');
break;
case KEY_S:
m_CurrInput.push_back('s');
break;
case KEY_T:
m_CurrInput.push_back('t');
break;
case KEY_U:
m_CurrInput.push_back('u');
break;
case KEY_V:
m_CurrInput.push_back('v');
break;
case KEY_W:
m_CurrInput.push_back('w');
break;
case KEY_X:
m_CurrInput.push_back('x');
break;
case KEY_Y:
m_CurrInput.push_back('y');
break;
case KEY_Z:
m_CurrInput.push_back('z');
break;
case KEY_0:
m_CurrInput.push_back('0');
break;
case KEY_1:
m_CurrInput.push_back('1');
break;
case KEY_2:
m_CurrInput.push_back('2');
break;
case KEY_3:
m_CurrInput.push_back('3');
break;
case KEY_4:
m_CurrInput.push_back('4');
break;
case KEY_5:
m_CurrInput.push_back('5');
break;
case KEY_6:
m_CurrInput.push_back('6');
break;
case KEY_7:
m_CurrInput.push_back('7');
break;
case KEY_8:
m_CurrInput.push_back('8');
break;
case KEY_9:
m_CurrInput.push_back('9');
break;
case KEY_QUOTE:
m_CurrInput.push_back('\"');
break;
case KEY_EQUALS:
m_CurrInput.push_back('=');
break;
case KEY_SPACE:
m_CurrInput.push_back(' ');
break;
case KEY_BACKSPACE:
if(m_CurrInput.size() > 0)
{
m_CurrInput.erase(m_CurrInput.end() - 1, m_CurrInput.end());
}
break;
case KEY_ENTER:
ProcessInput();
break;
case KEY_UP:
m_PrevSelection--;
if(m_PrevSelection < 1)
{
m_PrevSelection = m_PrevConsoleText.size() + 1;
m_CurrInput = "";
}
else
{
m_CurrInput = m_PrevConsoleText[m_PrevSelection - 1];
}
break;
case KEY_DOWN:
if(m_PrevSelection > (int)m_PrevConsoleText.size())
{
m_PrevSelection = 0;
m_CurrInput = "";
}
else
{
m_CurrInput = m_PrevConsoleText[m_PrevSelection - 1];
}
m_PrevSelection++;
break;
}
}
}
bool Console::ProcessInput()
{
int x;
std::string variable = "NULL", value;
bool ok = false;
std::string::iterator it;
//Split up the input from the user.
//variable will be the variable to change
//ok will = true if the syntax is correct
//value will be the value to change variable to.
for(x = 0; x < (int)m_CurrInput.size(); x++)
{
if(m_CurrInput[x] == ' ' && variable == "NULL")
{
variable = m_CurrInput.substr(0, x);
}
else if(m_CurrInput[x] == '=' && m_CurrInput[x - 1] == ' ' && m_CurrInput[x + 1] == ' ')
{
ok = true;
}
else if(m_CurrInput[x] == ' ')
{
value = m_CurrInput.substr(x + 1, m_CurrInput.size());
}
}
if(ok)
{
m_PrevConsoleText.push_back(m_CurrInput);
m_PrevSelection = m_PrevConsoleText.size();
if(m_PrevConsoleText.size() > 10)
{
m_PrevConsoleText.erase(m_PrevConsoleText.begin(), m_PrevConsoleText.begin() + 1);
}
m_CurrInput.clear();
ChangeVariable(variable, value);
}
else
{
m_PrevConsoleText.push_back("Error invalid console syntax! Use: <variableName> = <value>");
m_CurrInput.clear();
}
return ok;
}
const std::vector<std::string> &Console::GetPreviousText()
{
return m_PrevConsoleText;
}
Edición 1: Agregado DrawConsole() acabo de recibir el texto de la clase consola de rendir una imagen que parecía similar a la ventana de la consola del motor de origen que se encuentra en cualquier juego de válvulas reciente y luego el texto se dibuja en los lugares apropiados.
void View::DrawConsole()
{
Square console;
std::vector<std::string> temp;
temp = g_Console::Instance().GetPreviousText();
console.top = Vector3f(0.0, 0.0, 1.0);
console.bottom = Vector3f(640, 480, 1.0);
g_Render::Instance().SetOrthographicProjection();
g_Render::Instance().PushMatrix();
g_Render::Instance().LoadIdentity();
g_Render::Instance().BindTexture(m_ConsoleTexture);
g_Render::Instance().DrawPrimative(console, Vector3f(1.0f, 1.0f, 1.0f));
g_Render::Instance().DisableTexture();
g_Render::Instance().SetOrthographicProjection();
//Draw the current console text
g_Render::Instance().DrawString(g_Console::Instance().GetCurrentText(), 0.6f, 20, 465);
//Draw the previous console text
for(int x = (int)temp.size(); x > 0; x--)
{
g_Render::Instance().DrawString(temp[x-1], 0.6f, 20, (float)(425 - (abs((int)temp.size() - x) * 20)));
}
g_Render::Instance().SetPerspectiveProjection();
g_Render::Instance().PopMatrix();
g_Render::Instance().SetPerspectiveProjection();
}
No estoy buscando que sfml lo haga por mí, agregué sfml como una etiqueta y en los ejemplos de código para mostrar que estaba usando sfml. Sé que tengo que escribirlo, lo que busco es instrucciones sobre cómo hacerlo. Cómo han pasado otras personas escribiendo una consola en su aplicación. : D – Elgoog
Sugiero que refine su pregunta en algunas partes más pequeñas una vez que haya identificado qué es lo que quiere lograr. ¿Cuáles son sus requisitos? Intente usar el que está en Quake o Unreal Tournament o cualquier juego que le interese. –
Wolfire desarrolló algo basado en Webkit aparentemente: http://www.youtube.com/watch?v=c-4WdtTGIkg&feature=relmfu –