図0015a
1、コントローラやキーボードなどからの入力の受付 2、プレイヤーの操作 3、敵(またはほかのキャラクターやアイテムなど)のAI 4、衝突判定と衝突応答 5、エフェクト 6、インターフェイス 7、ミュージック 8、効果音 9、メニュー、サブメニューやステージ切り替えなどの機能 10、ステージデータなどの読み込み機能 11、プリミティブ形状作成やモデルの読み込みとその描画機能
1、コントローラからの入力の受付 2、プレイヤーの操作 3、敵(またはほかのキャラクターやアイテムなど)のAI 4、衝突判定と衝突応答
1、平面(SquareObject)。地面です。タイリング処理されています。 2、プレイヤー(SphereObject)。コントローラで操作できます。 3、ブロック(MoveBoxObject)。AIでプレイヤーをどこまでも追いかけてきます。 4、固定の障害物(BoxObject)。プレイヤーは乗ることができる障害物です。 5、スプライト(WrappedSprite)。左上で回転しているスプライトです。インターフェイス等に利用できるサンプルです。
void WrappedSprite::OnCreate() { float HelfSize = 0.5f; //頂点配列(縦横10個ずつ表示) m_BackupVertices = { { VertexPositionColorTexture(Vec3(-HelfSize, HelfSize, 0), Col4(1.0f,0,0,1.0f), Vec2(0.0f, 0.0f)) }, { VertexPositionColorTexture(Vec3(HelfSize, HelfSize, 0), Col4(0, 1.0f, 0, 1.0f), Vec2((float)m_XWrap, 0.0f)) }, { VertexPositionColorTexture(Vec3(-HelfSize, -HelfSize, 0), Col4(0, 0, 1.0f, 1.0f), Vec2(0.0f, (float)m_YWrap)) }, { VertexPositionColorTexture(Vec3(HelfSize, -HelfSize, 0), Col4(1.0f, 1.0f, 0, 1.0f), Vec2((float)m_XWrap, (float)m_YWrap)) }, }; //インデックス配列 vector<uint16_t> indices = { 0, 1, 2, 1, 3, 2 }; //メッシュの作成(変更できる) m_SquareMesh = MeshResource::CreateMeshResource(m_BackupVertices, indices, true); //テクスチャの作成 m_TextureResource = TextureResource::CreateTextureResource(m_TextureFileName, L"WIC"); }
void WrappedSprite::OnUpdate() { float ElapsedTime = App::GetApp()->GetElapsedTime(); m_Rot += ElapsedTime; if (m_Rot >= XM_2PI) { m_Rot = 0; } UpdateVertex(ElapsedTime); }
m_Rot += 0.01f;
void WrappedSprite::UpdateVertex(float ElapsedTime) { m_TotalTime += ElapsedTime; if (m_TotalTime >= 1.0f) { m_TotalTime = 0; } auto Dev = App::GetApp()->GetDeviceResources(); auto pD3D11DeviceContext = Dev->GetD3DDeviceContext(); //頂点の変更 //D3D11_MAP_WRITE_DISCARDは重要。この処理により、GPUに邪魔されない D3D11_MAP mapType = D3D11_MAP_WRITE_DISCARD; D3D11_MAPPED_SUBRESOURCE mappedBuffer; //頂点のマップ if (FAILED(pD3D11DeviceContext->Map(m_SquareMesh->GetVertexBuffer().Get(), 0, mapType, 0, &mappedBuffer))) { // Map失敗 throw BaseException( L"頂点のMapに失敗しました。", L"if(FAILED(pID3D11DeviceContext->Map()))", L"WrappedSprite::UpdateVertex()" ); } //頂点の変更 VertexPositionColorTexture* vertices = (VertexPositionColorTexture*)mappedBuffer.pData; for (size_t i = 0; i < m_SquareMesh->GetNumVertices(); i++) { Vec2 UV = m_BackupVertices[i].textureCoordinate; if (UV.x == 0.0f) { UV.x = m_TotalTime; } else if (UV.x == 4.0f) { UV.x += m_TotalTime; } vertices[i] = VertexPositionColorTexture( m_BackupVertices[i].position, m_BackupVertices[i].color, UV ); } //アンマップ pD3D11DeviceContext->Unmap(m_SquareMesh->GetVertexBuffer().Get(), 0); }
D3D11_MAP mapType = D3D11_MAP_WRITE_DISCARD; D3D11_MAPPED_SUBRESOURCE mappedBuffer; //頂点のマップ if (FAILED(pD3D11DeviceContext->Map(m_SquareMesh->GetVertexBuffer().Get(), 0, mapType, 0, &mappedBuffer))) {
//頂点の変更
VertexPositionColorTexture* vertices
= (VertexPositionColorTexture*)mappedBuffer.pData;
for (size_t i = 0; i < m_SquareMesh->GetNumVertices(); i++) {
Vec2 UV = m_BackupVertices[i].textureCoordinate;
if (UV.x == 0.0f) {
UV.x = m_TotalTime;
}
else if (UV.x == 4.0f) {
UV.x += m_TotalTime;
}
vertices[i] = VertexPositionColorTexture(
m_BackupVertices[i].position,
m_BackupVertices[i].color,
UV
);
}
//アンマップ pD3D11DeviceContext->Unmap(m_SquareMesh->GetVertexBuffer().Get(), 0);
//テクスチャとサンプラーの設定 ID3D11ShaderResourceView* pNull[1] = { 0 }; pD3D11DeviceContext->PSSetShaderResources(0, 1, m_TextureResource->GetShaderResourceView().GetAddressOf()); //ラッピングサンプラー ID3D11SamplerState* pSampler = RenderState->GetLinearWrap(); pD3D11DeviceContext->PSSetSamplers(0, 1, &pSampler);
//-------------------------------------------------------------------------------------- /*! @brief 描画するオブジェクトを追加する @param[in] MeshRes メッシュ @param[in] TextureRes テクスチャ @param[in] WorldMat ワールド行列 @param[in] Trace 透明処理するかどうか @param[in] Wrap ラッピング処理するかどうか @return なし */ //-------------------------------------------------------------------------------------- void AddDrawMesh(const shared_ptr<MeshResource>& MeshRes, const shared_ptr<TextureResource>& TextureRes, const Mat4x4& WorldMat, bool Trace,bool Wrap = false);
void PNTDrawObject::AddDrawMesh(const shared_ptr<MeshResource>& MeshRes, const shared_ptr<TextureResource>& TextureRes, const Mat4x4& WorldMat, bool Trace, bool Wrap) { DrawObject Obj; Obj.m_MeshRes = MeshRes; Obj.m_TextureRes = TextureRes; Obj.m_WorldMatrix = WorldMat; Obj.m_Trace = Trace; Obj.m_Wrap = Wrap; m_DrawObjectVec.push_back(Obj); }
void PNTDrawObject::OnUpdate() { m_DrawObjectVec.clear(); }
要素数(size()関数の戻り値) | capacity(capacity()関数の戻り値) |
---|---|
1 | 1 |
2 | 2 |
3 | 4 |
5 | 8 |
9 | 16 |
17 | 32 |
m_DrawObjectVec.clear();
//後始末 Dev->InitializeStates();
1、平面(SquareObject)。地面です。タイリング処理されています。 2、プレイヤー(SphereObject)。コントローラで操作できます。 3、ブロック(MoveBoxObject)。AIでプレイヤーをどこまでも追いかけてきます。 4、固定の障害物(BoxObject)。プレイヤーは乗ることができる障害物です。
void SquareObject::CreateBuffers(float WrapX, float WrapY) { float HelfSize = 0.5f; vector<VertexPositionNormalTexture> vertices = { { VertexPositionNormalTexture(Vec3(-HelfSize, HelfSize, 0), Vec3(0, 0, -1.0f), Vec2(0.0f, 0.0f)) }, { VertexPositionNormalTexture(Vec3(HelfSize, HelfSize, 0), Vec3(0, 0, -1.0f), Vec2(WrapX, 0.0f)) }, { VertexPositionNormalTexture(Vec3(-HelfSize, -HelfSize, 0), Vec3(0, 0, -1.0f), Vec2(0.0f, WrapY)) }, { VertexPositionNormalTexture(Vec3(HelfSize, -HelfSize, 0), Vec3(0, 0, -1.0f), Vec2(WrapX, WrapY)) }, }; vector<uint16_t> indices = { 0, 1, 2, 1, 3, 2, }; //メッシュの作成(変更できない) m_SquareMesh = MeshResource::CreateMeshResource(vertices, indices, false); }
//メッシュの作成(変更できない)
m_SquareMesh = MeshResource::CreateMeshResource(vertices, indices, false);
//-------------------------------------------------------------------------------------- /// ボックスの親 //-------------------------------------------------------------------------------------- class BoxBase : public ObjectInterface, public ShapeInterface { public: //-------------------------------------------------------------------------------------- /*! @brief コンストラクタ */ //-------------------------------------------------------------------------------------- BoxBase() : ObjectInterface(), ShapeInterface() {} //-------------------------------------------------------------------------------------- /*! @brief デストラクタ */ //-------------------------------------------------------------------------------------- virtual ~BoxBase() {} //-------------------------------------------------------------------------------------- /*! @brief OBBを得る(仮想関数) @return OBB */ //-------------------------------------------------------------------------------------- virtual OBB GetOBB()const = 0; //-------------------------------------------------------------------------------------- /*! @brief 衝突判定をする(仮想関数) @return なし */ //-------------------------------------------------------------------------------------- virtual void OnCollision() {} //-------------------------------------------------------------------------------------- /*! @brief 回転処理をする(仮想関数) @return なし */ //-------------------------------------------------------------------------------------- virtual void OnRotation() {} };
//--------------------------------------------------------------------------------------
/// 固定のボックス
//--------------------------------------------------------------------------------------
class BoxObject : public BoxBase {
//中略
public:
//中略
//--------------------------------------------------------------------------------------
/*!
@brief OBBを得る
@return OBB
*/
//--------------------------------------------------------------------------------------
virtual OBB GetOBB()const;
//--------------------------------------------------------------------------------------
/*!
@brief 初期化
@return なし
*/
//--------------------------------------------------------------------------------------
virtual void OnCreate() override;
//中略
};
void BoxObject::OnCreate() {
vector<VertexPositionNormalTexture> vertices;
vector<uint16_t> indices;
MeshUtill::CreateCube(1.0f, vertices, indices);
//メッシュの作成(変更できない)
m_BoxMesh = MeshResource::CreateMeshResource(vertices, indices, false);
//テクスチャの作成
m_TextureResource = ObjectFactory::Create<TextureResource>(m_TextureFileName, L"WIC");
}
MeshUtill::CreateCube(1.0f, vertices, indices);
//-------------------------------------------------------------------------------------- /// ゲームシーン //-------------------------------------------------------------------------------------- class Scene : public SceneInterface { shared_ptr<SquareObject> m_SquareObject; ///<平面オブジェクト shared_ptr<SphereObject> m_SphereObject; ///<球オブジェクト vector<shared_ptr<BoxBase>> m_BoxVec; ///<ボックスの配列 shared_ptr<PNTDrawObject> m_PNTDrawObject; ///<描画オブジェクト shared_ptr<WrappedSprite> m_WallSprite; ///<スプライト //以下略
void Scene::OnCreate() { //中略 m_BoxVec.push_back( ObjectFactory::Create<BoxObject>( GetThis<Scene>(), strTexture, false, Vec3(5.0f, 0.5f, 5.0f), Quat(), Vec3(5.0f, 0.25f, 0.0f) ) ); //中略 m_BoxVec.push_back( ObjectFactory::Create<BoxObject>( GetThis<Scene>(), strTexture, false, Vec3(5.0f, 0.5f, 5.0f), Quat(Vec3(0, 0, 1), -XM_PIDIV4), Vec3(-5.0f, 1.0f, 0.0f) ) ); strTexture = DataDir + L"wall.jpg"; //移動ボックス m_BoxVec.push_back( ObjectFactory::Create<MoveBoxObject>( GetThis<Scene>(), strTexture, false, Vec3(0.25f, 0.5f, 0.5f), Quat(), Vec3(0.0f, 0.25f, 5.0f) ) ); //中略 }
//-------------------------------------------------------------------------------------- /// ボックスの親 //-------------------------------------------------------------------------------------- class BoxBase : public ObjectInterface, public ShapeInterface { public: //中略 //-------------------------------------------------------------------------------------- /*! @brief OBBを得る(仮想関数) @return OBB */ //-------------------------------------------------------------------------------------- virtual OBB GetOBB()const = 0; //-------------------------------------------------------------------------------------- /*! @brief 衝突判定をする(仮想関数) @return なし */ //-------------------------------------------------------------------------------------- virtual void OnCollision() {} //-------------------------------------------------------------------------------------- /*! @brief 回転処理をする(仮想関数) @return なし */ //-------------------------------------------------------------------------------------- virtual void OnRotation() {} };
void Scene::OnUpdate() {
//更新
m_SquareObject->OnUpdate();
m_SphereObject->OnUpdate();
for (auto& v : m_BoxVec) {
v->OnUpdate();
}
//衝突判定
m_SphereObject->OnCollision();
for (auto& v : m_BoxVec) {
v->OnCollision();
}
//回転処理
m_SphereObject->OnRotation();
for (auto& v : m_BoxVec) {
v->OnRotation();
}
//描画オブジェクトの更新
m_PNTDrawObject->OnUpdate();
m_WallSprite->OnUpdate();
//中略
}
void MoveBoxObject::UpdateVelosity() { auto ShPtrScene = m_Scene.lock(); if (!ShPtrScene) { return; } //フォース(力) Vec3 Force(0, 0, 0); //プレイヤーを向く方向ベクトル Vec3 ToPlayerVec = ShPtrScene->GetSphereObject()->GetPosition() - m_Pos; //縦方向は計算しない ToPlayerVec.y = 0; ToPlayerVec *= m_Speed; //力を掛ける方向を決める Force = ToPlayerVec - m_Velocity; //力と質量から加速を求める Vec3 Accel = Force / m_Mass; //前回のターンからの経過時間を求める float ElapsedTime = App::GetApp()->GetElapsedTime(); //速度を加速する m_Velocity += Accel * ElapsedTime; }
1、直接、位置(Position)を変化させる 2、速度(Velocity)を変化させて、その値でPositionを動かす。 3、力(Force)を作り出して、加速を加え、それで速度(Velocity)を変化させる。 最後に、Velocityの値でPositionを動かす。
void MoveBoxObject::CollisionWithBoxes(const Vec3& BeforePos) {
//前回のターンからの経過時間を求める
float ElapsedTime = App::GetApp()->GetElapsedTime();
//衝突判定
auto ShPtrScene = m_Scene.lock();
for (auto& v : ShPtrScene->GetBoxVec()) {
if (v == GetThis<BoxBase>()) {
//相手が自分自身なら処理しない
continue;
}
OBB DestObb = v->GetOBB();
OBB SrcObb = GetOBB();
SrcObb.m_Center = BeforePos;
float HitTime;
Vec3 CollisionVelosity = (m_Pos - BeforePos) / ElapsedTime;
if (HitTest::CollisionTestObbObb(SrcObb, CollisionVelosity, DestObb, 0, ElapsedTime, HitTime)) {
m_Pos = BeforePos + CollisionVelosity * HitTime;
float SpanTime = ElapsedTime - HitTime;
//m_Posが動いたのでOBBを再取得
SrcObb = GetOBB();
Vec3 HitPoint;
//最近接点を得るための判定
HitTest::ClosestPtPointOBB(SrcObb.m_Center, DestObb, HitPoint);
//衝突法線をHitPointとm_Posから導く
Vec3 Normal = m_Pos - HitPoint;
Normal.normalize();
//速度をスライドさせて設定する
m_Velocity = ProjUtil::Slide(m_Velocity, Normal);
//Y方向はなし
m_Velocity.y = 0;
//最後に衝突点から余った時間分だけ新しい値で移動させる
m_Pos = m_Pos + m_Velocity * SpanTime;
//追い出し処理
//少しづつ相手の領域から退避する
//最大10回退避するが、それでも衝突していたら次回ターンに任せる
int count = 0;
while (count < 20) {
//退避する係数
float MiniSpan = 0.001f;
//もう一度衝突判定
//m_Posが動いたのでOBBを再取得
SrcObb = GetOBB();
if (HitTest::OBB_OBB(SrcObb, DestObb)) {
//最近接点を得るための判定
HitTest::ClosestPtPointOBB(SrcObb.m_Center, DestObb, HitPoint);
//衝突していたら追い出し処理
Vec3 EscapeNormal = SrcObb.m_Center - HitPoint;
EscapeNormal.y = 0;
EscapeNormal.normalize();
m_Pos = m_Pos + EscapeNormal * MiniSpan;
}
else {
break;
}
count++;
}
}
}
}
//追い出し処理 //少しづつ相手の領域から退避する //最大10回退避するが、それでも衝突していたら次回ターンに任せる int count = 0; while (count < 20) { //退避する係数 float MiniSpan = 0.001f; //もう一度衝突判定 //m_Posが動いたのでOBBを再取得 SrcObb = GetOBB(); if (HitTest::OBB_OBB(SrcObb, DestObb)) { //最近接点を得るための判定 HitTest::ClosestPtPointOBB(SrcObb.m_Center, DestObb, HitPoint); //衝突していたら追い出し処理 Vec3 EscapeNormal = SrcObb.m_Center - HitPoint; EscapeNormal.y = 0; EscapeNormal.normalize(); m_Pos = m_Pos + EscapeNormal * MiniSpan; } else { break; } count++; }
void SphereObject::OnUpdate() {
//1つ前の位置を取っておく
m_BeforePos = m_Pos;
//前回のターンからの経過時間を求める
float ElapsedTime = App::GetApp()->GetElapsedTime();
//コントローラの取得
auto CntlVec = App::GetApp()->GetInputDevice().GetControlerVec();
auto ShPtrScene = m_Scene.lock();
if (!ShPtrScene) {
return;
}
if (CntlVec[0].bConnected) {
if (!m_JumpLock) {
//Aボタン
if (CntlVec[0].wPressedButtons & XINPUT_GAMEPAD_A) {
m_BeforePos.y += 0.01f;
m_Pos.y += 0.01f;
m_GravityVelocity = Vec3(0, 4.0f, 0);
m_JumpLock = true;
}
}
Vec3 Direction = GetMoveVector();
if (Direction.length() < 0.1f) {
m_Velocity *= 0.9f;
}
else {
m_Velocity = Direction * 5.0f;
}
}
m_Pos += (m_Velocity * ElapsedTime);
m_GravityVelocity += m_Gravity * ElapsedTime;
m_Pos += m_GravityVelocity * ElapsedTime;
if (m_Pos.y <= m_BaseY) {
m_Pos.y = m_BaseY;
m_GravityVelocity = Vec3(0, 0, 0);
m_JumpLock = false;
}
}
void SphereObject::CollisionWithBoxes(const Vec3& BeforePos) {
//前回のターンからの経過時間を求める
float ElapsedTime = App::GetApp()->GetElapsedTime();
//衝突判定
auto ShPtrScene = m_Scene.lock();
for (auto& v : ShPtrScene->GetBoxVec()) {
OBB Obb = v->GetOBB();
SPHERE Sp = GetSPHERE();
Sp.m_Center = BeforePos;
float HitTime;
//相手の速度
Vec3 DestVelocity(0, 0, 0);
auto MovBoxPtr = dynamic_pointer_cast<MoveBoxObject>(v);
if (MovBoxPtr) {
DestVelocity = MovBoxPtr->GetPosition() - MovBoxPtr->GetBeforePos();
Obb.m_Center = MovBoxPtr->GetBeforePos();
}
Vec3 SrcVelocity = m_Pos - BeforePos;
Vec3 CollisionVelosity = (SrcVelocity - DestVelocity) / ElapsedTime;
if (HitTest::CollisionTestSphereObb(Sp, CollisionVelosity, Obb, 0, ElapsedTime, HitTime)) {
m_JumpLock = false;
m_Pos = BeforePos + CollisionVelosity * HitTime;
float SpanTime = ElapsedTime - HitTime;
//m_Posが動いたのでSPHEREを再取得
Sp = GetSPHERE();
Vec3 HitPoint;
//最近接点を得るための判定
HitTest::SPHERE_OBB(Sp, Obb, HitPoint);
//衝突法線をHitPointとm_Posから導く
Vec3 Normal = m_Pos - HitPoint;
Normal.normalize();
Vec3 angle(XMVector3AngleBetweenNormals(Normal, Vec3(0, 1, 0)));
if (angle.x <= 0.01f) {
//平面の上
m_GravityVelocity = Vec3(0, 0, 0);
}
else {
//重力をスライドさせて設定する
//これで、斜めのボックスを滑り落ちるようになる
m_GravityVelocity = ProjUtil::Slide(m_GravityVelocity, Normal);
}
if (MovBoxPtr) {
//お互いに反発する
Vec3 TgtVelo = CollisionVelosity * 0.5f;
if (TgtVelo.length() < 1.0f) {
//衝突時の速度が小さかったら、速度を作り出す
TgtVelo = MovBoxPtr->GetPosition() - m_Pos;
TgtVelo.normalize();
TgtVelo *= 2.0f;
}
Vec3 DestVelo(XMVector3Reflect(-TgtVelo, Normal));
DestVelo.y = 0;
MovBoxPtr->SetVelocity(DestVelo);
//速度を反発させて設定する
m_Velocity = XMVector3Reflect(TgtVelo, -Normal);
}
else {
//速度をスライドさせて設定する
m_Velocity = ProjUtil::Slide(m_Velocity, Normal);
}
//Y方向は重力に任せる
m_Velocity.y = 0;
//最後に衝突点から余った時間分だけ新しい値で移動させる
m_Pos = m_Pos + m_Velocity * SpanTime;
m_Pos = m_Pos + m_GravityVelocity * SpanTime;
//もう一度衝突判定
//m_Posが動いたのでSPHEREを再取得
Sp = GetSPHERE();
if (HitTest::SPHERE_OBB(Sp, Obb, HitPoint)) {
//衝突していたら追い出し処理
Vec3 EscapeNormal = Sp.m_Center - HitPoint;
EscapeNormal.normalize();
m_Pos = HitPoint + EscapeNormal * Sp.m_Radius;
}
}
}
}