2017-12-06 9 views
-1

私は昨日質問しましたが、間違って尋ねたようですので、ここでもう一度やります。私はすぐにこのコードを嘲笑し、これがオブジェクトを扱うための適切な方法であるかどうか疑問に思っています(main()にすべてを入れているのではありません)。これは初めて大きなプロジェクトを完了しようとするので、オブジェクトが含まれており、どのように処理するか疑問にする必要があります。(C++)他のすべてのカスタムオブジェクトを扱うための特別なクラス/オブジェクトの作成は、プロジェクトを処理するための適切な方法ですか?

skill.h

#pragma once 

#include <string> 
#include <vector> 
#include <memory> 
#include <unordered_map> 

class Skill; 

typedef std::vector<std::shared_ptr<Skill>> SkillVector; 
typedef std::unordered_map<std::string, std::shared_ptr<Skill>> SkillMap; 

class Skill { 
private: 
    std::string _skill_name; 
    std::string _skill_description; 
    friend std::ostream& operator<< (std::ostream& stream, const Skill& skill); 
    void print(std::ostream& stream) const; 

public: 
    Skill(const std::string& skill_name, const std::string& skill_description); 
    const std::string& getSkillName() const; 
    const std::string& getSkillDescription() const; 
    bool isMatch(const std::string& substring) const; 
}; 

application.h

#pragma once 

#include "skill.h" 

extern std::string SKILL_FILE; 

class Application { 
private: 
    std::unique_ptr<SkillMap> _skill_map; 
    void loadData(); 
    void loadSkills(); 
    void printSkillMap(); 
    void printSkillVector(const SkillVector& skills); 
    std::unique_ptr<SkillVector> skillSearch(const std::string& input) const; 
public: 
    Application(); 
    void run(); 
}; 

main.cppに

#include "application.h" 

int main() { 
    std::unique_ptr<Application> application(new Application); 
    application->run(); 

    return 0; 
} 

これはコマンドラインアプリケーションであるため、これ以外には、アプリケーションクラスのすべてのメソッドを通常の関数としてそのままメインに置くこと以外は何もすることはできません。それは正しいアプローチのようには思われません。私はこれをかなり広範囲に研究しようとしましたが、実際にこれに答えるものは見つかりませんでした。

すべてのオブジェクトを順序どおりに格納するための他のオプションは何ですか?特定のやり方をする利点は何ですか?私がここで受け入れていることは受け入れられているのでしょうか?

注:これは私のプロジェクトの正確な表現ではありません。私はちょうど例として私の質問を理解するための例としてそれを使用しています。

+1

これを実行する最善の方法はありませんが、[デザインパターン](https://www.developer.com/design/overview-of- design-patterns-for-beginners.html) あなたは[this](http://gameprogrammingpatterns.com/contents.html)を読むことができます。あなた自身がもっと便利な情報を見つけてください。時間厳守をしたら、私たちは喜んで助けてくれるでしょう。 – Immac

+0

それは実際にゲームのためではありませんが、それでも私はそれを見ていきます。 – dbrew5

+1

私はあなたが以前にJavaを試したかもしれないという印象を受けます。 :-)クラス内にすべての関数を置く必要はありません。あなたは 'new'を使ってオブジェクトを作成する必要はありませんし、' unique_ptr'を使う必要はありません*所有権を譲渡するつもりはありません。 –

答えて

0

次の規則に従ってください:

  • 継承を持っている場合は、クラスはA-A 'は' に応答する必要があります。たとえば、class Speed : public Skillがあるとします。それは論理的で、スピードはスキルです。

  • あなたが構図を決めたら、クラスは 'has-a'に応答する必要があります。あなたの場合:アプリケーションはスキルマップを持っています。 クラスがヒーローの場合、それは本当に論理的でしょう:ヒーローはスキルマップを持っています。そして、このヒーローは、ヒーローがスキルを印刷するために必要なスキルを開発します...ヒーローがスキルを管理します。

ご質問いただきありがとうございました。

1

TL; DR前方への移動方法に関する回答は1つではありません。それに依存します:

  1. あなたの目標は何ですか。
  2. プロジェクトが持つサブシステムと、どのように相互に統合するか。
  3. プロジェクトに必要なデータの種類と量。

言ったこと、それはあなたのプロジェクトの懸念のそれぞれに対応するタイプの間のデータ&機能を分離、ほとんど常にseparation of concernsを適用することをお勧めします。ここであなたが始めるためにfinite state machineを使った例です:

// Note that this example uses C++11 features. 
// Note that the stubs are intentional, to keep this example as terse as possible. 

// For consistency with your naming style. 
typedef std::string String; 
template<typename T> 
using Vector = std::vector<T>; 
template<typename T> 
using UniquePtr = std::unique_ptr<T>; 

// Skill.hpp: Represents a single skill. 
class Skill { 
private: 
    String _name; 
    String _description; 

public: 
    Skill(String name, String description); 

    const String& getName() const { return _name; } 
    const String& getDescription() const { return _description; } 
}; 

// Player.hpp: Represents a single player. 
class Player { 
private: 
    Vector<Skill*> _skills; 
    bool _isVirtual; // Is this player from another computer? (networked multiplayer) 

public: 
    Player(bool isVirtual = false) : 
     _skills(), 
     _isVirtual(isVirtual) {} 
    Player(const Player& other) = delete; // Non-copyable. 

    bool hasSkill(Skill* skill) const; 
    void addSkill(Skill* skill); 
    bool removeSkill(Skill* skill); // Returns true if removed, false otherwise. 
    bool isVirtual() const { return _isVirtual; } 
}; 

// Level.hpp: Represents a single level of the game. 
class Level { 
private: 
    // Per-level data... 

public: 
    Level(); 
    Level(const Level& other) = delete; // Non-copyable. 
}; 

// GameState.hpp: Represents the state of the game. 
enum class GameState { 
    MainMenu, // The user is in the main menu. 
    World,  // The user is navigating the world. 
    Combat,  // The user is in combat. 
}; 

// Game.hpp: Represents a single game instance. 
class Game { 
private: 
    Application* _app; 
    Vector<UniquePtr<Player>> _players; 
    Vector<UniquePtr<Level>> _levels; 
    Level* _level; // Current level the player(s) are on. 
    GameState _state; // Current state of the game. 
    bool _isRunning; // Is the game running? 

    void mainMenuLoop() { 
     while (_isRunning) { 
      // Implement your main menu here. 
      // Update the menu display after user input. 

      // When a selection is confirmed, execute it and return. 
     } 
    } 
    void combatLoop() { 
     while (_isRunning) { 
      // Implement your combat system here. 

      // When combat is over, update _state and return. 
     } 
    } 

public: 
    Game(Application* app) : 
     _app(app), 
     _players(), 
     _levels(), 
     _level(), 
     _state(GameState::MainMenu), 
     _isRunning(true) { 
     // Finish initializing and: 
     // If loading is fast enough, do so here. 
     // If loading is slow, spin up a thread and load asynchronously. 
    } 
    Game(const Game& other) = delete; // Non-copyable. 

    void run() { 
     // If loading is slow, wait on the loading thread to complete. 

     // Possibly show an introduction banner. 
     while (_isRunning) { 
      switch (_state) { 
       case GameState::MainMenu: 
        mainMenuLoop(); 
        break; 
       case GameState::Combat: 
        combatLoop(); 
        break; 
      } 
     } 
    } 
    void quit() { _isRunning = false; } 
    const Player* getPlayer(int index) const; 
    Player* getPlayer(int index); 
    void addPlayer(Player* player); 
    bool removePlayer(Player* player); // Returns true if removed, false otherwise. 
    const Level* getLevel(int index) const; 
    Level* getLevel(int index); 
    void addLevel(Level* level); 
    bool removeLevel(Level* level); // Returns true if removed, false otherwise. 
}; 

// Options.hpp: Represents command line options. 
struct Options { 
    // Add your command line options here. 

    Options(); 
    Options(const Options& other); 
}; 

// Application.hpp: Represents a single application instance. 
class Application { 
private: 
    Options _options; 
    Game _game; 

public: 
    // For compatibility with your code. 
    Application() : 
     _options(), 
     _game(this) {} 
    // For later, when you add command line options. 
    Application(const Options& options) : 
     _options(options), 
     _game(this) {} 
    Application(const Application& other) = delete; // Non-copyable. 

    const Options& getOptions() const { return _options; } 
    const Game* getGame() const { return &_game; } 
    Game* getGame() { return &_game; } 
    // For compatibility with your code. You could 
    // remove this and directly use getGame()->run() 
    void run() { _game.run(); } 
}; 

Applicationオブジェクトに対してunique_ptrを使用してmainでは不要です。代わりにスタックを使用してください:

// Added arguments because you'll probably want command-line options later. 
int main(int argc, char** argv) { 
    Application app; // Better locality, no dynamic allocation. 
    app.run(); 
    return 0; 
} 
+0

ありがとう!私は実際にゲームを作っていないが、これは実際に私を大いに助けてくれた。 – dbrew5

関連する問題