C++实现游戏登录/注册框架,并可实现游戏存档

24年了,想写些游戏。今年会慢慢学unity和qt,这个月先把文件读写练熟练。当然写的时候还是不熟练的,参考了很多帖子,请教了下copilot。

如题,这是一个实现游戏登录/注册/存档的框架,其他功能是暂时没有实现的。不过既然是框架,其他功能实现起来也并不困难。

框架由UI(用户界面)类,Player(玩家信息)类,和未实现的RunGame(游戏玩法)类组成。界面全程由UI类把握,每个流程实时捆绑正在交互的Player类对象,方便获取信息和修改信息。
框架接口基本没限制,RunGame类在此框架下是自由度很高的。可以写任意类型的小游戏。在我的构想下,分为单人/双人/人机对抗,这将通过继承RunGame类实现。

玩家在流程中始终通过选择a/b/c/d操作。我觉得对于控制台游戏来说,这是很理想的状态。

实现效果如下

C++实现游戏登录/注册框架,并可实现游戏存档_第1张图片 玩家Sam注册成功
  C++实现游戏登录/注册框架,并可实现游戏存档_第2张图片 玩家Tom不存在,登录失败
 
C++实现游戏登录/注册框架,并可实现游戏存档_第3张图片 玩家Sam密码正确,登录成功
​​​​
C++实现游戏登录/注册框架,并可实现游戏存档_第4张图片 玩家Sam的游戏主界面
  C++实现游戏登录/注册框架,并可实现游戏存档_第5张图片 玩家Sam的个人信息
 
C++实现游戏登录/注册框架,并可实现游戏存档_第6张图片 玩家Sam注册成功后记录的信息

下面展示类与方法接口。

//玩家类
class Player
{
    protected:
        string _name = "未命名"; //玩家名
        string _password = "000000"; //玩家密码
        string _likedSentence = "这个人很懒 什么都没有留下"; //玩家个性签名
        int _level = 0; //玩家等级

    public:
        //构造函数
        Player(string name, string password, string likedSentence, int level);
        Player() { }
        static Player signIn(); //注册
        static Player logIn(); //登录
        static void Pos(int, int); //设置光标位置
        static bool isUsernameExist(const string& username); //判断用户名是否存在

        //获取信息
        string getName() { return this->_name; }
        string getPassword() { return this->_password; }
        string getSentence() { return this->_likedSentence; }
        int getLevel() { return this->_level; }

    //友元类UI
    friend class UI;
};


//用户交互界面类
class UI
{
    private:
        string _process = "start";// 记录当前的进程 用于显示在屏幕上 每个选项都设置了进程
        void versionInfo() { return; } //版本信息 待完成
        void gameRule() { return; } //游戏规则 待完成
        void mainScreen(Player); //主界面
        void mainScreen_a(Player); //主界面的a选项

    public:
        Player start(); //整个登录注册流程在此完成 返回登录的玩家对象
        void Pos(int, int); //设置光标位置
        void showMainScreen(Player player) { this->mainScreen(player); } //显示主界面
        void showChoice(char[7][50]); //通用显示选项
        void showplayerInfo(Player); //显示玩家信息
        void hideCursor(); //隐藏控制台光标
        void newName(Player); //修改玩家名
};

能够看到在友元UI类中,几乎每个方法都使用了Player类对象。

这个框架的重点在于如何读写文件。
需要实现:
1、对未注册的玩家,能够注册一个新账号,包含名称、密码、个性签名、等级(0级) 等等信息(可以根据游戏类型写入丰富多样的信息);
2、拒绝注册已经被注册过的名称,防止出现重名,也方便管理账号信息;
3、对已经注册的玩家,能够通过名称和密码登录,这包括从文件中读取改名称下的密码,并与登录输入的密码比对;
4、拒绝登录没有注册过的账号名;
5、(未来将要实现的)在游戏的各种奖励机制中,赋予玩家游戏货币和经验值等,对于Player类是很容易实现的。

一下是核心方法实现。完整的代码已经放在文章最后。
 


/*
    注册方法
    当玩家输入新用户名时判断名称是否已经存在
    注册成功后把信息赋予当前Player类对象并返回
    同时把信息写入玩家列表更新
*/
Player Player::signIn()
{
    string name, password, likedSentence;
    while (true)
    {
        system("cls");
        cout << "未知玩家-注册界面"; //流程
        Pos(30, 10); cout << "注册";
        Pos(30, 12); cout << "新玩家名:";
        getline(cin, name);

        if (Player::isUsernameExist(name) == true) //用户名已经存在
        {
            system("cls");
            Pos(30, 16); cout << "玩家名已存在, ";
            cin.clear(); //清空输入缓存
            system("pause");
        }
        else break;
    }
    Pos(30, 14); cout << "设置密码:";
    getline(cin, password);
    Pos(30, 16); cout << "设置个性签名:";
    getline(cin, likedSentence);

    //写入玩家信息列表
    ofstream fout("Player_List.txt", ios::app);
    Player player(name, password, likedSentence, 0);
    fout << player._name << ","
        << player._password << ","
        << player._likedSentence << ","
        << player._level << "\n";
    fout.close();

    Pos(30, 18); cout << "注册成功, ";
    system("pause");
    return player;
}

/*
    登录方法
    首先读取玩家输入的已注册名称
    在文件中查找名称是否存在
    如果存在便读取与该玩家注册的密码
    等待判断用户输入密码是否匹配
    匹配成功则注册成功
*/
Player Player::logIn()
{
    while(true)
    {
        system("cls");
        string knownName, knownPassword;
        cout << "未知玩家-登录界面";
        Pos(30, 10); cout << "登录";
        Pos(30, 12); cout << "用户名:";
        getline(cin, knownName);
        Pos(30, 14); cout << "密码:";
        getline(cin, knownPassword);

        //读取玩家信息列表
        ifstream fin("Player_List.txt");
        string line;
        bool found = false;
        while (getline(fin, line))
        {
            stringstream ss(line);
            string name, password, likedSentence, levelStr;
            getline(ss, name, ',');
            getline(ss, password, ',');
            getline(ss, likedSentence, ',');
            getline(ss, levelStr, ',');
            if (name == knownName)  //用户名匹配
            {
                found = true;
                if (password == knownPassword)
                {
                    int level = stoi(levelStr);
                    Pos(30, 16); cout << "登录成功, ";
                    Player player(name, password, likedSentence, level);
                    system("pause");
                    return player;
                }
                else  //密码错误
                {
                    Pos(30, 16); cout << "密码错误, ";
                    system("pause");
                    break;
                }
            }
        }
        if (!found)  //没有找到该玩家
        {
            Pos(30, 16); cout << "没有找到该玩家, ";
            system("pause");
        }
        fin.close();
    }
}

//判断用户名是否存在
bool Player::isUsernameExist(const string& username)
{
    ifstream fin("Player_List.txt");
    if (fin.is_open())
    {
        string line;
        while (getline(fin, line))
        {
            stringstream ss(line);
            string existingName;
            getline(ss, existingName, ',');
            if (existingName == username) //用户名匹配
                return true;
        }
        fin.close();
    }
    else //文件打开失败
        cout << "出现错误!!";

    return false;
}

/*
    修改玩家名和修改其他任何信息都一样麻烦
    需要修改Player类中的对应信息
    然后将修改后的信息写入Player_List.txt文件
    最后删除原文件,将临时文件重命名为原文件
*/
void UI::newName(Player player)
{
    system("cls");
    string Newname;
    Pos(30, 10); cout << "请输入新用户名:";
    getline(cin, Newname);
    player._name = Newname;

    ifstream fin("Player_List.txt"); // 打开玩家信息列表txt文件
    ofstream fout("temp.txt");  // 创建临时文件
    string line;
    while (getline(fin, line))
    {
        stringstream ss(line);
        string name, password, likedSentence, levelStr;
        //用逗号隔开信息
        getline(ss, name, ',');
        getline(ss, password, ',');
        getline(ss, likedSentence, ',');
        getline(ss, levelStr, ',');
        if (name == player._name)
        {
            name = Newname;
            line = name + "," + password + "," + likedSentence + "," + levelStr;
        }
        fout << line << endl;  // 将修改后的内容写入临时文件
    }
    fin.close();
    fout.close();

    remove("Player_List.txt");  // 删除原文件
    rename("temp.txt", "Player_List.txt");  // 将临时文件重命名为原文件
    return showplayerInfo(player);
}

这个框架也有不足之处,以下问题是困扰我很久但是我没有解决,只能放弃或者绕过的:
1、没有设置违法输入页面(之前做了一个,并尝试传入游戏进程给解决违法输入的函数,以返回正确的界面,但由于函数返回值可能为Player类成员,违法界面就不能return空对象,从而无限递归,最终导致栈溢出);
2、测试的时候界面出现了乱码,不知起因是何处,估计是Pos的控制台方法有些冲突;
3、显示版本信息、改个性签名这些函数在未来会实现
 

完整代码如下

/*
 * @Author: Specptr(Github), cin在等Enter(CSDN)
 * @Date: 2024.1.17
 * @LastEditTime: 2024.1.24
 * @Description:
       实现了玩家类功能 包括登录注册 写入信息 修改信息等
 * @FilePath: \C_Player.hpp
 */

#ifndef C_PLAYER_HPP
#define C_PLAYER_HPP

#include 
#include 
#include 
#include 
#include 
using namespace std;

//玩家类
class Player
{
    protected:
        string _name = "未命名"; //玩家名
        string _password = "000000"; //玩家密码
        string _likedSentence = "这个人很懒 什么都没有留下"; //玩家个性签名
        int _level = 0; //玩家等级

    public:
        //构造函数
        Player(string name, string password, string likedSentence, int level)
        {
            this->_name = name;
            this->_password = password;
            this->_likedSentence = likedSentence;
            this->_level = level;
        }
        Player() { }
        static Player signIn(); //注册
        static Player logIn(); //登录
        static void Pos(int, int); //设置光标位置
        static bool isUsernameExist(const string& username); //判断用户名是否存在

        //获取信息
        string getName() { return this->_name; }
        string getPassword() { return this->_password; }
        string getSentence() { return this->_likedSentence; }
        int getLevel() { return this->_level; }

    //友元类UI
    friend class UI;
};

//设置光标位置
void Player::Pos(int x,int y)
{
    COORD pos;
    HANDLE hOutput;
    pos.X=x;
    pos.Y=y;
    hOutput=GetStdHandle(STD_OUTPUT_HANDLE);
    SetConsoleCursorPosition(hOutput,pos);
}

//注册
Player Player::signIn()
{
    string name, password, likedSentence;
    while (true)
    {
        system("cls");
        cout << "未知玩家-注册界面"; //流程
        Pos(30, 10); cout << "注册";
        Pos(30, 12); cout << "新玩家名:";
        getline(cin, name);

        if (Player::isUsernameExist(name) == true) //用户名已经存在
        {
            system("cls");
            Pos(30, 16); cout << "玩家名已存在, ";
            cin.clear(); //清空输入缓存
            system("pause");
        }
        else break;
    }
    Pos(30, 14); cout << "设置密码:";
    getline(cin, password);
    Pos(30, 16); cout << "设置个性签名:";
    getline(cin, likedSentence);

    //写入玩家信息列表
    ofstream fout("Player_List.txt", ios::app);
    Player player(name, password, likedSentence, 0);
    fout << player._name << ","
        << player._password << ","
        << player._likedSentence << ","
        << player._level << "\n";
    fout.close();

    Pos(30, 18); cout << "注册成功, ";
    system("pause");
    return player;
}

//登录
Player Player::logIn()
{
    while(true)
    {
        system("cls");
        string knownName, knownPassword;
        cout << "未知玩家-登录界面";
        Pos(30, 10); cout << "登录";
        Pos(30, 12); cout << "用户名:";
        getline(cin, knownName);
        Pos(30, 14); cout << "密码:";
        getline(cin, knownPassword);

        //读取玩家信息列表
        ifstream fin("Player_List.txt");
        string line;
        bool found = false;
        while (getline(fin, line))
        {
            stringstream ss(line);
            string name, password, likedSentence, levelStr;
            getline(ss, name, ',');
            getline(ss, password, ',');
            getline(ss, likedSentence, ',');
            getline(ss, levelStr, ',');
            if (name == knownName)  //用户名匹配
            {
                found = true;
                if (password == knownPassword)
                {
                    int level = stoi(levelStr);
                    Pos(30, 16); cout << "登录成功, ";
                    Player player(name, password, likedSentence, level);
                    system("pause");
                    return player;
                }
                else  //密码错误
                {
                    Pos(30, 16); cout << "密码错误, ";
                    system("pause");
                    break;
                }
            }
        }
        if (!found)  //没有找到该玩家
        {
            Pos(30, 16); cout << "没有找到该玩家, ";
            system("pause");
        }
        fin.close();
    }
}

//判断用户名是否存在
bool Player::isUsernameExist(const string& username)
{
    ifstream fin("Player_List.txt");
    if (fin.is_open())
    {
        string line;
        while (getline(fin, line))
        {
            stringstream ss(line);
            string existingName;
            getline(ss, existingName, ',');
            if (existingName == username) //用户名匹配
                return true;
        }
        fin.close();
    }
    else //文件打开失败
        cout << "出现错误!!";

    return false;
}

#endif
/*
 * @Author: Specptr(Github), cin在等Enter(CSDN)
 * @Date: 2024.1.14
 * @LastEditTime: 2024.1.24
 * @Description:
       实现了UI类的功能,包括登录注册(并写入玩家信息列表txt文件),主界面,角色信息,游戏规则,版本信息等功能。
 * @FilePath: \C_UI.hpp
 */

#ifndef C_UI_HPP
#define C_UI_HPP

#include 
#include 
#include 
#include "C_Player.hpp"
//#include "C_RunGame.hpp" 游戏的具体实现(不在这里放出)

//用户交互界面类
class UI
{
    private:
        string _process = "start";// 记录当前的进程 用于显示在屏幕上 每个选项都设置了进程

        void versionInfo() { return; } //版本信息 待完成
        void gameRule() { return; } //游戏规则 待完成
        void mainScreen(Player); //主界面
        void mainScreen_a(Player); //主界面的a选项

    public:
        Player start(); //整个登录注册流程在此完成 返回登录的玩家对象
        void Pos(int, int); //设置光标位置
        void showMainScreen(Player player) { this->mainScreen(player); } //显示主界面
        void showChoice(char[7][50]); //通用显示选项
        void showplayerInfo(Player); //显示玩家信息
        void hideCursor(); //隐藏控制台光标
        void newName(Player); //修改玩家名
        //void newSentence(Player); //修改个性签名
        //void newColor(Player); //修改主题颜色

};

// 设置光标位置
void UI::Pos(int x,int y)
{
    COORD pos;
    HANDLE hOutput;
    pos.X=x;
    pos.Y=y;
    hOutput=GetStdHandle(STD_OUTPUT_HANDLE);
    SetConsoleCursorPosition(hOutput,pos);
}

// 隐藏控制台光标
void UI::hideCursor()
{
    HANDLE consoleHandle = GetStdHandle(STD_OUTPUT_HANDLE);
    CONSOLE_CURSOR_INFO info;
    info.dwSize = 100;
    info.bVisible = FALSE;
    SetConsoleCursorInfo(consoleHandle, &info);
}

// 通用显示选项
void UI::showChoice(char ch[6][50])
{
    cout << this->_process;
    Pos(30, 10); cout << ch[0];
    Pos(30, 12); cout << ch[1];
    Pos(30, 14); cout << ch[2];
    Pos(30, 16); cout << ch[3];
    Pos(30, 18); cout << ch[4];
    Pos(30, 20); cout << ch[5];
}

// 登录注册流程
Player UI::start()
{
    _process = "未知玩家-登录/注册界面"; //更新流程

    system("cls");
    system("color 1e");
    char Choices[6][50] =
    {
        "欢迎来到游戏!",
        "亲爱的用户 请先 登录/注册",
        "a) 登录已有角色",
        "b) 注册新角色",
        "c) 游客模式",
        "d) 退出"
    };
    string input;

    do 
    {
        system("cls");
        showChoice(Choices);
        getline(cin, input);
        if (input == "a") return Player::logIn();
        else if (input == "b") return Player::signIn();
        else if (input == "c") { // 处理 'C' 键的情况... }
        else if (input == "d") { // 处理 'D' 键的情况... }
    } 
    while (input != "a" && input != "b" && input != "c" && input != "d");
    return Player();
}

//主界面
void UI::mainScreen(Player player)
{
    _process = player.getName() + "-主界面"; //更新流程

    system("cls");
    system("color e5");
    char Choices[6][50] =
    {
        "欢迎来到游戏!",
        "开始新征程吧",
        "a) 新游戏",
        "b) 角色信息",
        "c) 游戏规则",
        "d) 版本信息"
    };
    string input;
    do 
    {
        system("cls");
        showChoice(Choices);
        getline(cin, input);
        if (input == "a") return this->mainScreen_a(player);
        else if (input == "b") return this->showplayerInfo(player);
        else if (input == "c") { //return this->gameRule(); }
        else if (input == "d") { // 处理 'D' 键的情况... }
    } 
    while (input != "a" && input != "b" && input != "c" && input != "d");
    system("cls");
    return;
};

// 主界面a选项
void UI::mainScreen_a(Player player)
{
    _process = player.getName() + "-新游戏"; //更新流程
    system("cls");
    system("color e5");
    char Choices[6][50] =
    {
        "新一场游戏已经准备就绪",
        "请选择模式",
        "a) 单人游玩",
        "b) 双人游玩",
        "c) 人机对抗",
        "d) 返回上级"
    };
    string input;
    do 
    {
        system("cls");
        showChoice(Choices);
        getline(cin, input);
        if (input == "a") return;
        else if (input == "b") return;
        else if (input == "c")
        {
            return;// this->gameRule();
        }
        else if (input == "d")
        {
                    // 处理 'D' 键的情况...
        }
    } 
    while (input != "a" && input != "b" && input != "c" && input != "d");
};

//修改玩家名
void UI::newName(Player player)
{
    system("cls");
    string Newname;
    Pos(30, 10); cout << "请输入新用户名:";
    getline(cin, Newname);
    player._name = Newname;

    ifstream fin("Player_List.txt"); // 打开玩家信息列表txt文件
    ofstream fout("temp.txt");  // 创建临时文件
    string line;
    while (getline(fin, line))
    {
        stringstream ss(line);
        string name, password, likedSentence, levelStr;
        //用逗号隔开信息
        getline(ss, name, ',');
        getline(ss, password, ',');
        getline(ss, likedSentence, ',');
        getline(ss, levelStr, ',');
        if (name == player._name)
        {
            name = Newname;
            line = name + "," + password + "," + likedSentence + "," + levelStr;
        }
        fout << line << endl;  // 将修改后的内容写入临时文件
    }
    fin.close();
    fout.close();

    remove("Player_List.txt");  // 删除原文件
    rename("temp.txt", "Player_List.txt");  // 将临时文件重命名为原文件
    return showplayerInfo(player);
}

// 显示玩家信息
void UI::showplayerInfo(Player player)
{
    system("cls");
    string input;
    do 
    {
        _process = player.getName() + "-玩家信息";
        cout << this->_process;
        Pos(30, 10); cout << "玩家名:" << player.getName();
        Pos(30, 12); cout << "个性签名:" << player.getSentence();
        Pos(30, 14); cout << "玩家等级:" << player.getLevel();
        Pos(30, 18); cout << "a) 修改玩家名?";
        Pos(30, 20); cout << "b) 修改个性签名?";
        Pos(30, 22); cout << "c) 修改主题颜色?";
        Pos(30, 24); cout << "d) 返回上级";
        Pos(30, 26);
        getline(cin, input);
        if (input == "a") return newName(player);
        else if (input == "b") return;// player.newSentence(); 待完成
        else if (input == "c") return;// player.newColor(); 待完成
        else if (input == "d") return mainScreen(player);
    } 
    while (input != "a" && input != "b" && input != "c" && input != "d");
    system("pause");
    system("cls");
    return mainScreen(player);
}

#endif
/*
 * @Author: Specptr(Github), cin在等Enter(CSDN)
 * @Date: 2024.1.17
 * @LastEditTime: 2024.1.24
 * @Description:
       这是main文件
 * @FilePath: \main.cpp
 */

#include "C_Player.hpp"
#include "C_UI.hpp"
//#include "C_RunGame.hpp"

int main()
{
    UI ui;
    ui.hideCursor();
    Player player = ui.start();
    ui.showMainScreen(player);
    return 0;
}

——完——

你可能感兴趣的:(游戏,c++,开源,交互)