Добавление многопользовательского режима с разделенным экраном в игру C++
Я кодирую для NDS в C++ с libnds, но этот вопрос не является специфичным для NDS. В настоящее время у меня есть текстовая игра, в которой на верхнем экране просто отображается логотип, а вы играете на нижнем экране.
Поэтому я хочу добавить тип мультиплеера с одним DS, в котором один игрок играет на верхнем экране, а другой - на нижнем. У меня нет проблем с настройкой текстового движка на обоих экранах, мне просто нужно найти способ эффективного кодирования в мультиплеере. Ниже я написал краткую или упрощенную версию.
Примечание: consoleClear() очищает экран, и единственное место, где игра останавливается, - это функция паузы.
//Headers
void display(int x,int y,const char* output))
{
printf("\x1b[%d;%dH%s", y, x,output);
}
void pause(KEYPAD_BITS key) //KEYPAD_BITS is an ENUM for a key on the NDS
{
scanKeys();
while (keysHeld() & key)
{
scanKeys();
swiWaitForVBlank();
}
while (!(keysHeld() & key))
{
scanKeys();
swiWaitForVBlank();
}
return;
}
void pause() //Only used to simplify coding
{
pause(KEY_A);
return;
}
int main(void)
{
//Initializations/Setup
while (1)
{
if (rand()%2==1) //Say Hello
{
if (rand()%3!=1) //To Friend (greater chance of friend than enemy)
{
display(6,7,"Hello Friend!");
display(6,8,"Good greetings to you.");
pause();
consoleClear(); //Clears text
display(6,7,"Would you like to come in?");
pause();
//Normally more complex complex code (such as interactions with inventories) would go here
}
else //To enemy
{
display(6,7,"Hello enemy!");
display(6,8,"I hate you!");
pause();
consoleClear();
display(6,7,"Leave my house right now!!!");
pause();
}
}
else //Say goodbye
{
if (rand()%4==1) //To Friend (lesser chance of friend than enemy)
{
display(6,7,"Goodbye Friend!");
display(6,8,"Good wishes to you.");
pause();
consoleClear();
display(6,7,"I'll see you tomorrow.");
pause();
consoleClear();
display(6,7,"Wait, I forgot to give you this present.");
pause();
}
else //To enemy
{
display(6,7,"Goodbye enemy!");
display(6,8,"I hate you!");
pause();
consoleClear();
display(6,7,"Never come back!!");
pause();
consoleClear();
display(6,7,"Good riddance!"); //I think I spelt that wrong...
pause();
}
}
}
}
Я знаю, что gotos сбивают с толку и могут считаться плохой привычкой, но я не могу придумать лучшего пути. Моя версия интеграции мультиплеера:
//Headers and same functions
int game(int location)
{
switch (location)
{
case 1: goto one; break;
case 2: goto two; break;
case 3: goto three; break;
case 4: goto four; break;
case 5: goto five; break;
case 6: goto six; break;
case 7: goto seven; break;
case 8: goto eight; break;
case 9: goto nine; break;
case 10: goto ten; break;
default: break;
}
if (rand()%2==1) //Say Hello
{
if (rand()%3!=1) //To Friend (greater chance of friend than enemy)
{
display(6,7,"Hello Friend!");
display(6,8,"Good greetings to you.");
return 1;
one:;
consoleClear(); //Clears text
display(6,7,"Would you like to come in?");
return 2;
two:;
//Normally more complex complex code (such as interactions with inventories) would go here
}
else //To enemy
{
display(6,7,"Hello enemy!");
display(6,8,"I hate you!");
return 3;
three:;
consoleClear();
display(6,7,"Leave my house right now!!!");
return 4;
four:;
}
}
else //Say goodbye
{
if (rand()%4==1) //To Friend (lesser chance of friend than enemy)
{
display(6,7,"Goodbye Friend!");
display(6,8,"Good wishes to you.");
return 5;
five:;
consoleClear();
display(6,7,"I'll see you tomorrow.");
return 6;
six:;
consoleClear();
display(6,7,"Wait, I forgot to give you this present.");
return 7;
seven:;
}
else //To enemy
{
display(6,7,"Goodbye enemy!");
display(6,8,"I hate you!");
return 8;
eight:;
consoleClear();
display(6,7,"Never come back!!");
return 9;
nine:;
consoleClear();
display(6,7,"Good riddance!"); //I think I spelt that wrong...
return 10;
ten:;
}
return -1;
}
}
int main(void)
{
//Initializations/Setup
int location1 = -1, location2 = -1;
location1 = game(location1);
location2 = game(location2);
while (1)
{
scanKeys(); //Whenever checking key state this must be called
if (keysDown() & KEY_A) //A key is used to continue for player1
location1 = game(location1);
if (keysDown() & KEY_DOWN) //Down key is used to continue for player2
location2 = game(location2);
}
}
Помимо того, что этот метод является плохой практикой, в реальном исходном коде у меня есть сотни goto-ов, которые мне нужно было бы добавить, что заняло бы слишком много времени.
Любая помощь приветствуется. Если у кого-то есть хоть какой-то вопрос или ответ, пожалуйста, спросите / ответьте.
Изменить: Хотя это не является предпочтительным, я готов переписать игру с нуля, если у кого-то есть способ сделать это.
1 ответ
Использование условных операторов if-else для каждого случая - простое решение, которое приходит на ум первым.
Например:
int game(int i){
if(i == 1){
//first case code here.
}
else if(i == 2){
//second case code here.
}
//....
return 0;
}
Код в каждом случае можно даже поместить в другие функции, которые будут вызываться в зависимости от каждого условия. Это, вероятно, будет достаточно для вашего случая.
Более гибким решением (но гораздо более сложным) является таблица диспетчеризации. Идея состоит в том, чтобы иметь отдельные функции с каждой желаемой функциональностью и помещать их указатели в массив. Затем вы можете вызвать их, проиндексировав таблицу, используя эти указатели на функции. Это может быть чрезвычайно полезно, если у вас есть последовательность выполнений (вызовов функций), и вы хотите, чтобы это было легко сделать, или вы хотите получить разные результаты в зависимости от вашего ввода, без изменения вашей программы.
Ниже приведен пример. Этот код можно использовать и в C, если вы замените std::cout на printf, а iostream на библиотеку stdio.
#include <iostream>
using namespace std;
// Arrays start from 0.
// This is used for code
// readability reasons.
#define CASE(X) X-1
typedef void (*chooseCase)();
// Functions to execute each case.
// Here, I am just printing
// different strings.
void case1(){
cout<< "case1" << endl;
}
void case2(){
cout<< "case2" << endl;
}
void case3(){
cout<< "case3" << endl;
}
void case4(){
cout<< "case4" << endl;
}
//Put all the cases in an array.
chooseCase cases[] = {
case1, case2, case3, case4
};
int main()
{
//You can call each scenario
//by hand easily this way:
cases[CASE(1)]();
cout << endl;
//Idea: You can even set in another
// array a sequence of function executions desired.
int casesSequence[] = {
CASE(1), CASE(2), CASE(3), CASE(4),CASE(3),CASE(2),CASE(1)
};
//Execute the functions in the sequence set.
for(int i = 0; i < (sizeof(casesSequence)/sizeof(int)); ++i){
cases[casesSequence[i]]();
}
return 0;
}
Это напечатает на выходе:
case1
case1
case2
case3
case4
case3
case2
case1