@bezadの正反対をお勧めします。
1台の車と無限の道から始めましょう。
レンダリングとダイナミクスの問題を 2 つの完全に異なるものに分割します。一般的なCar
アップデート および/または は、CarRenderModel
と の間のリンクCarPhysicsModel
です。
Car
が GL シーンにどのようなシェイプを配置するかはCar
.
とりわけ、これは、Car
画面上に非常に単純な表示を作成し、それに非常に単純な物理モデルをCar
追加して、2 つを結びつけることなく、よりきれいにするか、物理的により良く動作させることができることを意味します。そして、理想的には、各段階で再生可能なものを用意します。
つまり、長さ 5、幅 3、高さ 1 ユニットの長方形の車です。幅13単位、どこまでも続く道。静止カメラ。たぶん地平線。最初の物理モデルはロケット船で、矢印キーを 1 秒押すごとに、車はその方向に x 単位/秒の速度を得ます。この車は回転しないことに注意してください。軸が揃っています。車が道路から離れると爆発し、「ゲーム」は終了します。
これで、ユーザー入力に応答する何かが画面に表示されました。より洗練された車のモデル (ホイールなど) を作成するのに時間を費やすか、車の物理学と制御モデルを改善するか (方向! 角度! ブレーキング != スピードアップ!)、または環境をより興味深いものにする (黒を追加する) ことができます。道路の端で速度を見ることができるように白のストライプ. 道路近くのオフロード部分、およびおそらく車を爆破する木) または、カメラをより興味深いものにすることができます (たとえば、カメラの後ろにとどまります)。車、そしてその肩越しに見える)。
さて、ダイナミクスについては、ユニバースと車の相互作用を、車と車の相互作用とは異なるコードを使用して扱います。これは、正気を保つためだけです。車は環境を変えることができません。
これは、車と車の相互作用よりも、車と宇宙の相互作用の束を簡単に作成できることを意味します。
...
C++ で任意のツリーを構築するのは簡単です。
#include <vector>
#include <memory>
#include <string>
struct MyTree;
typedef std::unique_ptr<MyTree> upTree; // punt on memory management!
struct MyBaseNode;
typedef std::unique_ptr<MyBaseNode> upNode;
struct MyTree {
std::vector<upTree> children;
upNode node;
MyTree( upNode node_ ):node(std::move(node_)) {}
private:
// if C++11 compiler, use these:
MyTree( MyTree const& ) = delete;
MyTree& operator=( MyTree const& ) = delete;
// if C++03, use these:
// MyTree( MyTree const& ); // no implementation
// MyTree& operator=( MyTree const& ); // no implementation
};
upTree make_tree(upNode node) { return upTree( new MyTree(std::move(node)) ); }
enum EOrder{ eFirst, eMiddle, eLast };
template<typename Functor>
void walk_tree( upTree const& tree, Functor f, bool bFirst = true, bool bLast = true) {
if (!tree) return;
f( tree, bFirst, bLast );
for (auto it = tree->children.begin(); it != tree->children.end(); ++it) {
bool bChildFirst = (it == tree->children.begin());
bool bChildLast = ((it+1) == tree->children.end());
walk_tree( *it, f, bChildFirst, bChildLast );
}
}
struct MyBaseNode {
virtual ~MyBaseNode() {};
// put things that your tree nodes have to be able to do here
// as pure virtual functions...
virtual std::string MyName() const = 0;
};
struct CarsNode : MyBaseNode {
// cars node implementation!
virtual std::string MyName() const /*override*/ { return "I am a bunch of CARS!"; }
};
upNode make_cars() { return upNode( new CarsNode() ); }
struct CarNode : MyBaseNode {
// car node implementation!
virtual std::string MyName() const /*override*/ { return "I am a CAR!"; }
};
upNode make_car() { return upNode( new CarNode() ); }
struct RoadNode : MyBaseNode {
// car node implementation!
virtual std::string MyName() const /*override*/ { return "I am a ROAD!"; }
};
upNode make_road() { return upNode( new RoadNode() ); }
#include <iostream>
void tree_printer_func( upTree const& tree, bool bFirst, bool bLast ) {
if (bFirst) std::cout << "[ ";
if (tree->node) {
std::cout << tree->node->MyName().c_str();
} else {
std::cout << "nullNode";
}
if (bLast) {
std::cout << " ]\n";
} else {
std::cout << ", ";
}
}
int main() {
upTree root = make_tree(upNode());
upTree carsTree = make_tree(make_cars());
carsTree->children.push_back( make_tree( make_car() ) );
carsTree->children.push_back( make_tree( make_car() ) );
root->children.push_back( std::move(carsTree) );
upTree roadTree = make_tree(make_road());
root->children.push_back( std::move(roadTree) );
walk_tree( root, tree_printer_func );
}
上記はかなり大雑把ですが (たとえば、プリンターでエンドノードの処理が正しく行われませんでした)、C++ で非均一、非リーク、n-ary ツリー構造を示しています。