図1201a
チュートリアル001(FullSample101)と似ている感じですが、ちょっと違います。
//プレイヤーの作成
void GameStage::CreatePlayer() {
//プレーヤーの作成
auto PlayerPtr = AddGameObject<Player>();
//シェア配列にプレイヤーを追加
SetSharedGameObject(L"Player", PlayerPtr);
PlayerPtr->AddTag(L"Player");
}
Player::Player(const shared_ptr<Stage>& StagePtr) : GameObject(StagePtr), m_Velocity(0) {}
template<typename T, typename... Ts>
shared_ptr<T> AddGameObject(Ts&&... params) {
try {
auto Ptr = ObjectFactory::Create<T>(GetThis<Stage>(), params...);
PushBackGameObject(Ptr);
return Ptr;
}
catch (...) {
throw;
}
}
SeekObject::SeekObject(const shared_ptr<Stage>& StagePtr, const Vec3& StartPos) :
GameObject(StagePtr),
m_StartPos(StartPos),
m_StateChangeSize(5.0f),
m_Force(0),
m_Velocity(0)
{
}
//追いかけるオブジェクトの作成
void GameStage::CreateSeekObject() {
//オブジェクトのグループを作成する
auto Group = CreateSharedObjectGroup(L"SeekGroup");
//配列の初期化
vector<Vec3> Vec = {
{ 0, 0.125f, 10.0f },
{ 10.0f, 0.125f, 0.0f },
{ -10.0f, 0.125f, 0.0f },
{ 0, 0.125f, -10.0f },
};
//オブジェクトの作成
for (auto& v : Vec) {
AddGameObject<SeekObject>(v);
}
}
void Player::OnCreate() { //初期位置などの設定 auto Ptr = GetComponent<Transform>(); Ptr->SetScale(0.25f, 0.25f, 0.25f); //直径25センチの球体 Ptr->SetRotation(0.0f, 0.0f, 0.0f); Ptr->SetPosition(0, 0.125f, 0); //CollisionSphere衝突判定を付ける auto PtrColl = AddComponent<CollisionSphere>(); //重力をつける auto PtrGra = AddComponent<Gravity>(); //文字列をつける auto PtrString = AddComponent<StringSprite>(); PtrString->SetText(L""); PtrString->SetTextRect(Rect2D<float>(16.0f, 16.0f, 640.0f, 480.0f)); //中略 //カメラを得る auto PtrCamera = dynamic_pointer_cast<MyCamera>(OnGetDrawCamera()); if (PtrCamera) { //MyCameraである //MyCameraに注目するオブジェクト(プレイヤー)の設定 PtrCamera->SetTargetObject(GetThis<GameObject>()); PtrCamera->SetTargetToAt(Vec3(0, 0.25f, 0)); } }
図1201b
これを実装しているのがVec3 Player::GetMoveVector()const関数です。
Vec3 Player::GetMoveVector() const { Vec3 Angle(0, 0, 0); //コントローラの取得 auto CntlVec = App::GetApp()->GetInputDevice().GetControlerVec(); if (CntlVec[0].bConnected) { if (CntlVec[0].fThumbLX != 0 || CntlVec[0].fThumbLY != 0) { float MoveLength = 0; //動いた時のスピード auto PtrTransform = GetComponent<Transform>(); auto PtrCamera = OnGetDrawCamera(); //進行方向の向きを計算 Vec3 Front = PtrTransform->GetPosition() - PtrCamera->GetEye(); Front.y = 0; Front.normalize(); //進行方向向きからの角度を算出 float FrontAngle = atan2(Front.z, Front.x); //コントローラの向き計算 float MoveX = CntlVec[0].fThumbLX; float MoveZ = CntlVec[0].fThumbLY; Vec2 MoveVec(MoveX, MoveZ); float MoveSize = MoveVec.length(); //コントローラの向きから角度を計算 float CntlAngle = atan2(-MoveX, MoveZ); //トータルの角度を算出 float TotalAngle = FrontAngle + CntlAngle; //角度からベクトルを作成 Angle = Vec3(cos(TotalAngle), 0, sin(TotalAngle)); //正規化する Angle.normalize(); //移動サイズを設定。 Angle *= MoveSize; //Y軸は変化させない Angle.y = 0; } } return Angle; }
void Player::MovePlayer() { float ElapsedTime = App::GetApp()->GetElapsedTime(); Vec3 Angle = GetMoveVector(); if (Angle.length() > 0.0f) { auto Pos = GetComponent<Transform>()->GetPosition(); Pos += Angle * ElapsedTime * m_Speed; GetComponent<Transform>()->SetPosition(Pos); //回転の計算 auto UtilPtr = GetBehavior<UtilBehavior>(); UtilPtr->RotToHead(Angle, 1.0f); } }
//更新 void Player::OnUpdate() { //コントローラチェックして入力があればコマンド呼び出し m_InputHandler.PushHandle(GetThis<Player>()); MovePlayer(); }
template<typename T> struct InputHandler { void PushHandle(const shared_ptr<T>& Obj) { //コントローラの取得 auto CntlVec = App::GetApp()->GetInputDevice().GetControlerVec(); if (CntlVec[0].bConnected) { //Aボタン if (CntlVec[0].wPressedButtons & XINPUT_GAMEPAD_A) { Obj->OnPushA(); } } } };
void Player::OnPushA() { auto Grav = GetComponent<Gravity>(); Grav->StartJump(Vec3(0,4.0f,0)); }
void Player::OnUpdate2() { //文字列の表示 DrawStrings(); }
void Player::DrawStrings() { //文字列表示 auto fps = App::GetApp()->GetStepTimer().GetFramesPerSecond(); wstring FPS(L"FPS: "); FPS += Util::UintToWStr(fps); FPS += L"\nElapsedTime: "; float ElapsedTime = App::GetApp()->GetElapsedTime(); FPS += Util::FloatToWStr(ElapsedTime); FPS += L"\n"; auto Pos = GetComponent<Transform>()->GetPosition(); wstring PositionStr(L"Position:\t"); PositionStr += L"X=" + Util::FloatToWStr(Pos.x, 6, Util::FloatModify::Fixed) + L",\t"; PositionStr += L"Y=" + Util::FloatToWStr(Pos.y, 6, Util::FloatModify::Fixed) + L",\t"; PositionStr += L"Z=" + Util::FloatToWStr(Pos.z, 6, Util::FloatModify::Fixed) + L"\n"; wstring GravStr(L"GravityVelocoty:\t"); auto GravVelocity = GetComponent<Gravity>()->GetGravityVelocity(); GravStr += L"X=" + Util::FloatToWStr(GravVelocity.x, 6, Util::FloatModify::Fixed) + L",\t"; GravStr += L"Y=" + Util::FloatToWStr(GravVelocity.y, 6, Util::FloatModify::Fixed) + L",\t"; GravStr += L"Z=" + Util::FloatToWStr(GravVelocity.z, 6, Util::FloatModify::Fixed) + L"\n"; wstring str = FPS + PositionStr + GravStr; //文字列コンポーネントの取得 auto PtrString = GetComponent<StringSprite>(); PtrString->SetText(str); }
SeekObject::SeekObject(const shared_ptr<Stage>& StagePtr, const Vec3& StartPos) : GameObject(StagePtr), m_StartPos(StartPos), m_StateChangeSize(5.0f), m_Force(0), m_Velocity(0) { }
void GameStage::CreateSeekObject() { //オブジェクトのグループを作成する auto Group = CreateSharedObjectGroup(L"SeekGroup"); //配列の初期化 vector<Vec3> Vec = { { 0, 0.125f, 10.0f }, { 10.0f, 0.125f, 0.0f }, { -10.0f, 0.125f, 0.0f }, { 0, 0.125f, -10.0f }, }; //オブジェクトの作成 for (auto& v : Vec) { AddGameObject<SeekObject>(v); } }
void SeekObject::OnCreate() {
auto PtrTransform = GetComponent<Transform>();
PtrTransform->SetPosition(m_StartPos);
PtrTransform->SetScale(0.125f, 0.25f, 0.25f);
PtrTransform->SetRotation(0.0f, 0.0f, 0.0f);
//オブジェクトのグループを得る
auto Group = GetStage()->GetSharedObjectGroup(L"SeekGroup");
//グループに自分自身を追加
Group->IntoGroup(GetThis<SeekObject>());
//Obbの衝突判定をつける
auto PtrColl = AddComponent<CollisionObb>();
//重力をつける
auto PtrGra = AddComponent<Gravity>();
//分離行動をつける
auto PtrSep = GetBehavior<SeparationSteering>();
PtrSep->SetGameObjectGroup(Group);
//中略
//ステートマシンの構築
m_StateMachine.reset(new StateMachine<SeekObject>(GetThis<SeekObject>()));
//最初のステートをSeekFarStateに設定
m_StateMachine->ChangeState(SeekFarState::Instance());
}
ステート名 | 行動 |
---|---|
SeekFarState |
スピードを出してプレイヤーを追いかける。 お互いはくっつかないようにする。 移動方向に頭を向ける |
SeekNearState | プレイヤーに近づく(到着する) お互いはくっつかないようにする 移動方向に頭を向ける |
class SeekFarState : public ObjState<SeekObject> { SeekFarState() {} public: static shared_ptr<SeekFarState> Instance(); virtual void Enter(const shared_ptr<SeekObject>& Obj)override; virtual void Execute(const shared_ptr<SeekObject>& Obj)override; virtual void Exit(const shared_ptr<SeekObject>& Obj)override; };
shared_ptr<SeekFarState> SeekFarState::Instance() { static shared_ptr<SeekFarState> instance(new SeekFarState); return instance; } void SeekFarState::Enter(const shared_ptr<SeekObject>& Obj) { } void SeekFarState::Execute(const shared_ptr<SeekObject>& Obj) { auto PtrSeek = Obj->GetBehavior<SeekSteering>(); auto PtrSep = Obj->GetBehavior<SeparationSteering>(); auto Force = Obj->GetForce(); Force = PtrSeek->Execute(Force, Obj->GetVelocity(), Obj->GetTargetPos()); Force += PtrSep->Execute(Force); Obj->SetForce(Force); Obj->ApplyForce(); float f = bsm::length(Obj->GetComponent<Transform>()->GetPosition() - Obj->GetTargetPos()); if (f < Obj->GetStateChangeSize()) { Obj->GetStateMachine()->ChangeState(SeekNearState::Instance()); } } void SeekFarState::Exit(const shared_ptr<SeekObject>& Obj) { }
1、スピードを出してプレイヤーを追いかける。 2、お互いはくっつかないようにする。 3、移動方向に頭を向ける
Force = PtrSeek->Execute(Force, Obj->GetVelocity(), Obj->GetTargetPos()); Force += PtrSep->Execute(Force); Obj->SetForce(Force); Obj->ApplyForce();
void SeekObject::OnUpdate() {
m_Force = Vec3(0);
//ステートマシンのUpdateを行う
//この中でステートの切り替えが行われる
m_StateMachine->Update();
auto PtrUtil = GetBehavior<UtilBehavior>();
PtrUtil->RotToHead(1.0f);
}
void SeekObject::OnCollisionEnter(shared_ptr<GameObject>& Other) { if (Other->FindTag(L"Player")) { auto Grav = GetComponent<Gravity>(); Grav->StartJump(Vec3(0, 4.0f, 0)); } }