首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在制品RPG

在制品RPG
EN

Code Review用户
提问于 2021-02-24 12:10:34
回答 1查看 471关注 0票数 5

下面是我正在开发的一个只使用标准C++库的RPG。我在为映射中生成的字符概念化一个坐标系统时遇到了困难,而库存/物品系统目前只是一个shell。但是,我已经创建了一个小演示,其中包含了将出现在完整产品(Game::Test())中的一些特性。这是我第一次真正尝试一场比赛,所以我很想听听你对我到目前为止的想法,以及我可以改进的方式。

注:我没有包括我的库存系统,因为它几乎没有任何代码,还有什么是所有的概念。

main.cpp

代码语言:javascript
复制
#include 
#include 
#include 
#include 

#include "Game.h"

int main() {
    //Seed to use for run;
    //!FIX; OVERHAUL TO HAVE SEED GENERATED BY RUN INSTEAD OF INSTANCE
    srand(time(NULL));
    
    Game myRpg;
    char charInput;
    std::string strInput;
    
    //Run Test Mode (Has Access To Basic Game Mechanics)
    std::cout << "Run test? Enter \'Y\' for test." << std::endl;
    std::cin >> charInput;
    
    //Test is all that exists right now. Always enter Y to run game
    if (charInput == 'Y') {
        myRpg.Test();
    }
            
    return 0;
}

游戏.h

代码语言:javascript
复制
#ifndef GAME_H
#define GAME_H

#include 
#include 
#include 

#include "Characters.h"
#include "Maps.h"
#include "Player.h"

class Game {
    public:
        Game() {Clear(); Intro(); myChar.CharacterCreation();};
        void Clear();
        
        void Intro();
        
        void Test();
        void Run();
    
    private:
        //!FIX; `OUT-OF-RANGE` CRASH WHEN INITIALIZING MAP LIST
        /*===WIP===
        Maps mapLib;
        */
    
        Characters charLib; //!Will use `(mapLib.size())` once Maps fixed
        Characters* myChars = &charLib;
        
        Player myChar;
        Character* player = myChar.p;
        
        //Counts num turns player has made since init; Currently unused
        int time;
};

#endif

Game.cpp

代码语言:javascript
复制
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#include "Game.h"

void Game::Clear() {
    for(unsigned int i = 0; i < 50; i++) {
        std::cout << std::endl;
    }
}

//Displays game intro using text file "intro.txt"
void Game::Intro() {
    //Opens text file "intro.txt"
    std::ifstream intro;
    intro.open("intro.txt");
    
    //Outputs text from file
    if(intro.is_open()) {
        std::string str;
        //While file has not reached the end
        while(!(intro.eof())) {
            getline(intro, str);
            std::cout << str << std::endl;
        }
        std::cout << std::endl << std::endl;
        intro.close();
    }
}

//Mode to run basic battle functions
void Game::Test() {
    //Clear previous screen
    Clear();
    
    /*!===TEST; Test() Start===
    std::cout << "Test Start" << std::endl;
    */
    
    //Create character and single opponent
    Character opponent;
    opponent = charLib.CreateChar("Bandit");
    Character* opp = &opponent;
    
    //Create Default Map
    Map default_map; //!FIX; Find Seg. Fault (Map.cpp)
    default_map.Print();
    
    std::cout << "As you sail across the ocean, you come across a bandit," << std::endl
              << "floating over the water. You pull him aboard, when      " << std::endl
              << "suddenly he jolts up, knife readied in hand. It was a  " << std::endl
              << "trick!" << std::endl;
    std::cout << "Press \'enter\' to continue.";
    std::cin.get();
    std::cin.ignore();
    std::cout << std::endl;
    
    player->Battle(opp);
    
    if (player->IsAlive() == 0) {
        std::cout << "The treasure remains lost. GAME OVER" << std::endl;
        return;
    }
    
    std::cout << "You won!- but the treasure is still out there somewhere..." << std::endl;
    
    /*!===TEST; Test() End===
    std::cout << "Test Successful!" << std::endl;
    */
    
}

Player.h

代码语言:javascript
复制
#ifndef PLAYER_H
#define PLAYER_H

#include 
#include 
#include 

#include "Character.h"  

class Player {
    public:
        Player() {p = &player; lv = 1; player.SetSym('@');}
        int GetLv();
        
        void PlayerTurn();
        void Battle(Character *opponent);          //Option 1
        void Defend();          //Option 2
        void OpenInventory();   //Option 3
        void RunAway();         //Option 4
        
        void CharacterCreation();
        
        Character* p;
    
    private:
        Character player;
        int lv;
};

/*===WIP===//
struct Ability {
    std::string name;
    int lv;
    
    int cost(int lv) {
        return (lv);
    }
    
    bool canAfford(int lv, int mp) {
        return cost(lv) <= mp;
    }
        
    void show(int lv) {
        std::cout << "[" << cost() << "] mp\n";
    }
};

class Job {
    public:
        void PrintAbilities(int lv);
        
    private:
        std::string name;
        std::vector abilities;
        int numAbilities() {return abilities.size();}
        
        Ability const &operator[](int index) const {
            return abilities.at(index);
        }
    
};
//=========*/

#endif

Player.cpp

代码语言:javascript
复制
#include 
#include 
#include 
#include 
#include 

#include "Player.h"

//===WIP===
void Player::PlayerTurn() {
    char usrInput = ' ';
    
    std::cout << "Your turn. Press \'?\' for help." << std::endl;
    usrInput = getchar();
    
    switch(usrInput) {
        case 'w' || 'a' || 's' || 'd':
            break;
        case '?':
            break;
        case 'i':  //!FIX; FINISH INVENTORY/ITEM SYSTEM
            std::cout << "Not functional at this time." << std::endl;
            break;
        case '*':
            break;
    }
    
    if (player.IsAlive() == 0) {
        std::cout << "Your adventure has come to an end." << std::endl;
    }
}

void Player::Battle(Character *opponent) {
    player.Battle(opponent);
}   

void Player::CharacterCreation() {
    std::string usrStr;
    
    //Set Player Name
    std::cout << "What's your name? ";
    getline(std::cin, usrStr);
    player.SetName(usrStr); //Set name as usrStr input
    std::cout << std::endl;
    
    //Set Player Stats
    bool isYes;
    bool isRollOrSet;
    
    do {
        std::cout << "Would you like to \'roll\' or \'set\' your stats? "
                  << "Please enter \'roll\' or \'set\'" << std::endl;
        std::cin >> usrStr;
        if ((usrStr != "roll") && (usrStr != "set")) {
            std::cout << "Please enter an appropriate response." << std::endl;
        }
        else {
            do {
                bool setOrRoll = (usrStr == "roll");
                switch (setOrRoll) {
                    case 1: //Rolls stats
                        player.RollStats();
                        break;
                        
                    case 0: //Use a stat pool
                        player.SetStats();
                        break;
                }
                //Confirm with user that they want these stats; Display Stats
                std::cout << "Are these stats okay? Enter \'YES\' if so, or enter "
                          << "\'roll\' / \'set\' to redo your stats accordingly.\n";
                std::cout << std::setw(2);
                std::cout << "HP: " << player.GetHp() << std::endl;
                std::cout << "MP: " << player.GetMp() << std::endl;
                std::cout << "STR: " << player.GetStr() << std::endl;
                std::cout << "DEF: " << player.GetDef() << std::endl;
                std::cout << "MAG: " << player.GetMag() << std::endl;
                std::cout << "SPD: " << player.GetSpd() << std::endl;
                
                do {
                    std::cin >> usrStr;
                    
                    isYes = (usrStr == "YES");
                    isRollOrSet = ((usrStr == "roll") || (usrStr == "set"));
                    
                    //If they entered "YES"
                    if (usrStr == "YES") {
                        break;
                    }
                    //If they entered something other than "YES", "roll", or "set"
                    else if ((isYes == false) && (isRollOrSet == false)) {
                        std::cout << "Please enter an appropriate answer." << std::endl << std::endl;
                    }
                //Loops input
                } while((isYes == false) && (isRollOrSet == false));
            //Loops stat roll
            } while(isRollOrSet == true);
        }
    //Loops initial question
    } while(isYes == false);
}

/*===WIP===//
Job::PrintAbilities(int lv) {
    for(unsigned int i = 0; i < numAbilities; i++) {
        std::cout << "[" << i << "]";
        abilites[i].show(lv);
    }
}
//=========*/

字符.h

代码语言:javascript
复制
#ifndef CHARACTERS_H
#define CHARACTERS_H

#include 
#include 

#include "Character.h"

class Coord {
    public:
        Coord() {};
        void SetData(int x, int y) {
            this->x = x;
            this->y = y;
        }
        
        void XShift(int a) {x += a;}
        void YShift (int b) {y += b;}
        
        int GetX() {return x;}
        int GetY() {return y;}
        
    private:
        int x;
        int y;
};

/********************************************************************/

class Characters {
    public:
        Characters() {SetArchList();}
        Characters(int numMaps) {SetArchList(); charList.resize(numMaps);}
        void AddCharArch(Character _char, std::vector _chars);
        Character CreateChar(std::string archName);
        
    private:
        //Stores character archetypes
        std::vector archList;
        std::vector> charList;
        /*!FIX; DYNAMICALLY ADD CHARACTERS FROM CURR MAP TO LIST
         * Reference == Map.cpp, `void Map::SpawnEntities() {};`  */
        
        void SetArchList();
};

#endif

字符>Characters.cpp

代码语言:javascript
复制
#include 
#include 
#include 

#include "Characters.h"

//Adds character archetypes to characterList
void Characters::AddCharArch(Character _char, std::vector _chars = {{"null"}}) {
    if (_chars.at(0).GetName() == "null") {
        //Copies character data _char
        archList.push_back(_char);
    }
    else {
        //Copies data from character vector _chars
        for(unsigned int i = 0; i < _chars.size(); i++) {
            archList.push_back(_chars.at(i));
        }
    }
}

//Retrieves character archetype data from characterList
Character Characters::CreateChar(std::string archName) {
    Character archType;
    for(unsigned int i = 0; i < archList.size(); i++) {
        Character* charListArch = &archList.at(i); //Creates a pointer for archetype in charList at i
        if(charListArch->GetName() == archName) {
            archType = charListArch->GetName();
        }
        else {
            continue;
        }
    }
    
    return archType;
}

void Characters::SetArchList() {
    //Archetype Info |Name     | hp| mp|str|def|mag|spd|sym|
    archList =      {{"Bandit" ,  15,  0,  5,  2,  0,  2,'b'},
                     {"Crew"   ,  24,  4,  8,  5,  2,  4,'c'},
                     {"Captain",  32,  8, 10,  8,  5,  6,'C'}};
};

字符.h

代码语言:javascript
复制
#ifndef CHARACTER_H
#define CHARACTER_H

#include 
#include 
#include 

#include "Inventory.h"

class Character {
    public:
        Character() : name("Default"), hp(6), mp(6), str(6), def(6), mag(6), spd(6) {};
        Character(std::string name) : hp(12), mp(6), str(6), def(6), mag(6), spd(6) {this->name = name;}
        Character(std::string name, int hp, int mp, int str, int def, int mag, int spd, char symbol) {
            this->name = name;
            this->hp = hp * 3;
            this->mp = mp;
            this->str = str;
            this->def = def;
            this->mag = mag;
            this->spd = spd;
            this->symbol = symbol;
        }
        
        void SetName(std::string);                //Create character name
        std::string GetName() {return name;}      //Get character's name
        
        void SetStats();      //Set stat values using point pool
        void RollStats();     //Roll d12 for character's start stats
        
        void SetHp(int hp) {this->hp = hp;}
        void SetMp(int mp) {this->mp = mp;}
        void SetStr(int str) {this->str = str;}
        void SetDef(int def) {this->def = def;}
        void SetMag(int mag) {this->mag = mag;}
        void SetSpd(int spd) {this->spd = spd;}
        void SetSym(char symbol) {this->symbol = symbol;}
        
        int GetHp() const {return hp;}
        int GetMp() const {return mp;}
        int GetStr() const {return str;}
        int GetDef() const {return def;}
        int GetMag() const {return mag;}
        int GetSpd() const {return spd;}
        char GetSym() const {return symbol;}
        
        void Battle(Character *opponent);
        
        bool IsAlive() const {return hp > 0;}        //Check if character's alive
        void TakeDamage(Character *opponent);        //Take damage
        int GetDamage(Character* opponent) const;
        
    private:
        std::string name;  //Character name
        int hp;            //Health of character
        int mp;            //Magic points of character
        int str;           //Strength of character
        int def;           //Defense of character
        int mag;           //Magic skill of character
        int spd;           //Speed of character
        
        char symbol;
};

#endif

字符.Character.cpp

代码语言:javascript
复制
#include 
#include 
#include 

#include "Character.h"

void Character::SetName(std::string name) {
    this->name = name;
}

//Allows the user to freely set their character's stats from a pool of 36
void Character::SetStats() {
    int pointPool = 36;
    
    for(unsigned int i = 0; i < 6; i++) {
        int usrInt = 0;
        bool goodStat = false;
        
        do {
            std::cout << "You have " << pointPool << " points remaining.\n";
            std::cout << "How many points for ";
            switch(i) {
                case 0:
                    std::cout << "HP? ";
                    std::cin >> usrInt;
                    break;
                    
                case 1:
                    std::cout << "MP? ";
                    std::cin >> usrInt;
                    break;
                    
                case 2:
                    std::cout << "STR? ";
                    std::cin >> usrInt;
                    break;
                    
                case 3:
                    std::cout << "DEF? ";
                    std::cin >> usrInt;
                    break;
                    
                case 4:
                    std::cout << "MAG? ";
                    std::cin >> usrInt;
                    break;
                    
                case 5:
                    std::cout << "SPD? ";
                    std::cin >> usrInt;
                    break;
            }
            // Check if player choice was appropriate
            if (usrInt > pointPool) {
                std::cout << "Not enough points." << std::endl;
            }
            else if (usrInt < 0) {
                std::cout << "Can't allocate less than 0 points." << std::endl;
            }
            //Set Stats
            else {
                switch(i) {
                    case 0:
                        SetHp(usrInt * 3);
                        break;
                        
                    case 1:
                        SetMp(usrInt);
                        break;
                        
                    case 2:
                        SetStr(usrInt);
                        break;
                        
                    case 3:
                        SetDef(usrInt);
                        break;
                        
                    case 4:
                        SetMag(usrInt);
                        break;
                        
                    case 5:
                        SetSpd(usrInt);
                        break;
                }
                goodStat = true;
            }       
        } while(goodStat == false);
        
        //Subtract player choice from point pool
        pointPool -= usrInt;
        
        /*!===TEST; SetStats() Interval===
        std::cout << std::endl;
        std::cout << "Test: Interval " << i << std::endl;
        */
    }
}

void Character::RollStats() {
    int pointPool = 36;
    
    for(unsigned int i = 0; i < 6; i++) {
        int randNum;
        
        //Get random number 1-8 for stat allocation
        do {
            randNum = (rand() % 8) + 1;
            if(randNum <= pointPool) {
                break;
            }
        } while(randNum > pointPool);
        
        //Set stat using randNum
        switch(i) {
            case 0:
                if (randNum <= 3) {
                    randNum = 4;
                }
                SetHp(randNum * 3); //Set Health
                break;
            case 1:
                SetMp(randNum); //Set Magic Points
                break;
            case 2:
                SetStr(randNum); //Set Strength
                break;
            case 3:
                SetDef(randNum); //Set Defense
                break;
            case 4:
                SetMag(randNum); //Set Magic Skill
                break;
            case 5:
                SetSpd(randNum); //Set Speed
                break;
        }
        pointPool -= randNum; //Remove randNum from pointPool
    }
}

void Character::Battle(Character *opponent) {
    bool att; //Attacker
    bool opp; //Opponent
    
    do {
        bool whoseFaster = GetSpd() > opponent->GetSpd();
        
        switch(whoseFaster) {
            case 1: //Player's faster
                opponent->TakeDamage(this);
                std::cout << name << " hits " << opponent->GetName()
                          << " for " << opponent->GetDamage(this) << " points." << std::endl;
                
                //If the opponent died from attack, end battle
                if (IsAlive() == false) {
                    break;
                }
                
                TakeDamage(opponent);
                std::cout << opponent->GetName() << " hits " << name
                          << " for " << GetDamage(opponent) << " points." << std::endl;
                break;
            case 0: //Opponent's faster
                TakeDamage(opponent);
                std::cout << opponent->GetName() << " hits " << name
                          << " for " << GetDamage(opponent) << " points." << std::endl;
                          
                //If player died from attack, end battle
                if (IsAlive() == false) {
                    break;
                }
                
                //Else, player attacks
                opponent->TakeDamage(this);
                std::cout << name << " hits " << opponent->GetName()
                          << " for " << opponent->GetDamage(this) << " points." << std::endl;
                break;
        }
        
        std::cout << GetName() << " has " << GetHp() << " HP remaining." << std::endl
                  << opponent->GetName() << " has " << opponent->GetHp() << " hp remaining." << std::endl
                  << std::endl;
        
        att = IsAlive();
        opp = opponent->IsAlive();
    } while( (att == true) && (opp == true) );
    
    switch(att) {
        case 1:
            std::cout << opponent->GetName() << " was slain." << std::endl;
            break;
        case 0:
            std::cout << name << " was cut down." << std::endl;
            break;
    }
}

//Character takes damage from parameter
//  |Recipient|            |Attacker|
void Character::TakeDamage(Character *opponent) {
    int dmg = GetDamage(opponent);
    
    hp -= dmg;
}

//Returns damage value
//  |Recipient|          |Attacker|
int Character::GetDamage(Character* opponent) const {
    int dmg = (opponent->GetStr() - def);
    if (dmg < 1) {
        dmg = 1;
    }
    
    return dmg;
}

Maps.h

代码语言:javascript
复制
#ifndef MAPS_H
#define MAPS_H

#include 
#include 
#include 

#include "Map.h"

class Maps {
    public:
        Maps() {SetMapTypes(); SetMapNumTypes(); GenMaps(1);}
        Maps(int numMaps) {SetMapTypes(); SetMapNumTypes(); GenMaps(numMaps);}
        void SetCurrMap();
        void PrintCurrMap() const;
        
    private:
        //Map types and num of maps per type
        std::vector mapTypes;
        std::vector mapNumTypes;
        
        //Collection of Map
        std::vector maps;
        
        //Copy of map for gameplay 
        Map currMap;
        
        void SetMapTypes();
        void SetMapNumTypes();
        void GenMaps(int numMaps);
};

#endif

Maps.cpp

代码语言:javascript
复制
#include 
#include 
#include 
#include 

#include "Maps.h"
#include "Map.h"

void Maps::SetMapTypes() {
    mapTypes = {"test_area", "ship_battle"};
}

void Maps::SetMapNumTypes() {
    //             test_area, ship_battles
    mapNumTypes = {        1,            1};
}

void Maps::GenMaps(int numMaps) {
    srand(time(NULL));
        
    for(int k = 0; k < numMaps; k++) {  
        //Set random map type from library
        int randType = rand() % mapTypes.size();
        std::string mapType = mapTypes.at(randType);
            
        //Get num of maps for type; Set random map variation
        int mapVars = mapNumTypes.at(randType);
        int randMapVar = rand() % mapVars;
            
        //Set map name
        std::string mapName = mapType;
        mapName.push_back(randMapVar);
        mapName.append(".txt");
            
        //Generate and store map copy
        Map map(mapName);
        maps.push_back(map);
    }
}

Map.h

代码语言:javascript
复制
#ifndef MAP_H
#define MAP_H

#include 
#include 
#include 

#include "Characters.h"

class Map {
    public:
        Map() {this->name = "default"; GenMap(); SpawnEntities();}
        Map(std::string name) {this->name = name; GenMap(); SpawnEntities();}
        void Print() const;
    
    private:
        std::string name;
        std::vector> map;

        void GenMap();
        void SpawnEntities();
};

#endif

Map.cpp

代码语言:javascript
复制
#include 
#include 
#include 
#include 
#include 
#include 

#include "Map.h"

void Map::GenMap() {
    /*!===TEST; GenMap() Start===
    std::cout << "Map Gen Start" << std::endl;
    */
    
    int width = 0;
    int height = 0;
    
    //If name is "default", generate pre-made test map
    if (name == "default") {
        map = {{'~','~','~','~','~','~','~','~','~'},
               {'~','~','~','~','~','~','~','~','~'},
               {'~','~','~','~','-','~','~','~','~'},
               {'~','~','~','|','*','|','~','~','~'},
               {'~','~','~','|','b','|','~','~','~'},
               {'~','~','~','|','@','|','~','~','~'},
               {'~','~','~','~','-','~','~','~','~'},
               {'~','~','~','~','~','~','~','~','~'},
               {'~','~','~','~','~','~','~','~','~'}};
    }
    else {
        //Open map file of the same name as parameter
        std::ifstream mapFile;
        mapFile.open(name);
        
        //Copy contents of map to 2D vector
        if (mapFile.is_open()) {
            std::string str;
            getline(mapFile, str);
            
            
        } //Closes if statement
        mapFile.close();
        
    } //Closes else statement
    /*!===TEST; GenMap() END===
    std::cout << "Map Gen Successful!" << std::endl;
    */
}

//===WIP===
void Map::SpawnEntities() {
    //Do not spawn entities when map is default
    if (name == "default") {
        return;
    }
    
    int randNum1 = rand() % 16;
    
    //Spawn Player
    for(size_t i = 0; i < map.size(); i++) { //Row size
        bool placedPlayer = false;
        for(size_t k = 0; k < map.at(i).size(); k++) { //Column size
            int thisRandNum = rand() % 16;
            if((thisRandNum == randNum1) && (map[i][k] == '*')) {
                map[i][k] = '@';
                placedPlayer = true;
                break;
            }
        }
        if(placedPlayer == true) {
            break;
        }
    }
    
    //Spawn enemies
    int mapSeverity = (rand() % 5) + 1; //Enemy # multiplier between 1-5
    int numEntities = ((rand() % 4) + 1) * mapSeverity; //# of enemies spawned
    
    std::vector includeEntities;
    std::vector numSpawns;
    
    //!===TEST; mapSeverity Setting===
    if(name == "default") {
        mapSeverity = 1;
        numEntities = 3;
    }
    
    switch(mapSeverity) {
        case 5:
        case 4:
            includeEntities.push_back('C');
        case 3:
            includeEntities.push_back('c');
        case 2:
        case 1:
            includeEntities.push_back('b');
    }
    
    int randNum2 = rand() % 16;
    
    for(size_t i = 0; i < map.size(); i++) { //Row
        for(size_t k = 0; k < map.at(i).size(); k++) { //Column
            int thisRandNum = rand() % 16;
            if((thisRandNum == randNum2) && (map[i][k] == '*')) {
                
                    /*!===Finish Coding Entitiy Spawner===
                    //Needs: - Spawn number of each entity
                    //         using int numEntities
                    */
                    
            }
        }
    }
}

void Map::Print() const {
    for(size_t i = 0; i < map.size(); i++) {
        for(size_t k = 0; k < map.at(i).size(); k++) {
            std::cout << map[i][k];
        }
        std::cout << std::endl;
    }
}               
EN

回答 1

Code Review用户

回答已采纳

发布于 2021-02-24 14:50:59

票数 10
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/256405

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档