C++ 物理挙動もどき①
こんばんは。ネノワヲンです。
やったこと
今日は、プレイヤーの落下やめり込み防止などをしました。物理挙動もどき pic.twitter.com/HhpagmPkTZ
— ネノワヲン@ネノぶろ! (@nenowawon) 2018年11月17日
中身
void Player::LateUpdate(float deltaTime) { float fallSpeed = 0.01f; // 落下させる MoveY(-fallSpeed); // コライダーのリストを取得 for (auto collider : DirectXRenderer::instance->m_ColliderList) { //テスト用オブジェクトにぶつかった場合 if (collider->m_pGameObject->m_tag != Tag::TEST) { continue; } // 衝突判定をする if (!m_pCollider->CheckCollider(collider)) { continue; } // 衝突物の座標 XMFLOAT3 checkColliderPos = collider->m_pGameObject->m_transform->m_pos; RectangleVertex myRect = m_pCollider->GetRect(); RectangleVertex collisionRect = collider->GetRect(); const float beforeMagine = 0.001f; XMFLOAT3 movePos = XMFLOAT3(0.0f, 0.0f, 0.0f); // 自分が上側の場合かつ自分が下側に移動した場合 if (m_transform->m_pos.y > checkColliderPos.y && m_CurrentMoveTemp.y < 0.0f) { float moveYTemp = abs(collisionRect.top - myRect.bottom) + beforeMagine; if (moveYTemp > movePos.y) { // 上に移動する movePos.y = moveYTemp; } } // 自分が下側の場合かつ自分が上側に移動した場合 else if (m_transform->m_pos.y < checkColliderPos.y && m_CurrentMoveTemp.y > 0.0f) { float moveYTemp = -abs(collisionRect.bottom - myRect.top) - beforeMagine; if (moveYTemp < movePos.y) { // 下に移動する movePos.y = moveYTemp; } } // 自分が右側の場合かつ自分が左側に移動した場合 if (m_transform->m_pos.x > checkColliderPos.x && m_CurrentMoveTemp.x < 0.0f) { float moveXTemp = abs(collisionRect.right - myRect.left) + beforeMagine; if (moveXTemp > movePos.x) { // 移動量を更新する movePos.x = moveXTemp; } } // 自分が左側の場合かつ自分が右側に移動した場合 else if (m_transform->m_pos.x < checkColliderPos.x && m_CurrentMoveTemp.x > 0.0f) { float moveXTemp = -abs(collisionRect.left - myRect.right) - beforeMagine; if (moveXTemp < movePos.x) { // 移動量を更新する movePos.x = moveXTemp; } } // 移動する Move(movePos); } }
概要
課題
今回の実装の問題点は、X軸とY軸を同時に動かすとバグるところですね。。。 原因は分かったのですが、どうやって直そうか悩んでいます。。。
あとがき
ユニティちゃんはかわいい。
C++ 衝突判定の中身解説
こんにちは。ネノワヲンです。今日は、昨日作った衝突判定についての中身を書きます。
ソース
コライダー(衝突物クラス)
void RectangleCollider::Create(GameObject* object, ImageVertex(&vertexArray)[4]) { Create(object); float min_x = 0; float max_x = 0; float min_y = 0; float max_y = 0; int size = sizeof(vertexArray) / sizeof(ImageVertex); for (size_t i = 0; i < size; i++) { // x座標の最大値を更新する if (vertexArray[i].m_vertPos.x > max_x) { max_x = vertexArray[i].m_vertPos.x; } // x座標の最小値を更新する if (vertexArray[i].m_vertPos.x < min_x) { min_x = vertexArray[i].m_vertPos.x; } // y座標の最大値を更新する if (vertexArray[i].m_vertPos.y > max_y) { max_y = vertexArray[i].m_vertPos.y; } // y座標の最小値を更新する if (vertexArray[i].m_vertPos.y < min_y) { min_y = vertexArray[i].m_vertPos.y; } } // 左辺の座標を設定 m_pRect->left = min_x; // 右辺の座標を設定 m_pRect->right = max_x; // 上辺の座標を設定 m_pRect->top = max_y; // 下辺の座標を設定 m_pRect->bottom = min_y; } void RectangleCollider::Create(GameObject* object) { m_pGameObject = object; m_pRect = new RectangleVertex(); DirectXRenderer::instance->AddCollider(this); } bool RectangleCollider::CheckCollider(RectangleCollider * collider) { // チェック相手のコライダー RectangleVertex checkRect = collider->GetRect(); // 自分のコライダー RectangleVertex myRect = GetRect(); //横に重なっていた場合 if (myRect.left <= checkRect.right && myRect.right >= checkRect.left) { //縦に重なっていた場合 if (myRect.top >= checkRect.bottom && myRect.bottom <= checkRect.top) { return true; } } return false; } RectangleVertex RectangleCollider::GetRect() { RectangleVertex rect = RectangleVertex(); // 頂点座標をワールド座標に変換する // 左 rect.left = (m_pGameObject->m_transform->m_pos.x) + (m_pRect->left); // 上 rect.top = (m_pGameObject->m_transform->m_pos.y) + (m_pRect->top); // 右 rect.right = (m_pGameObject->m_transform->m_pos.x) + (m_pRect->right); // 下 rect.bottom = (m_pGameObject->m_transform->m_pos.y) + (m_pRect->bottom); return rect; }
このクラスは、4辺の座標、自分のオブジェクトをメンバ変数として保持しています。 コライダーを受け取り、衝突しているかどうかを判定し、結果としてboolを返します。
オブジェクトクラス(コライダーに命令を送る)
HRESULT SpriteTest::Create(HWND hwnd) { HRESULT hr; // 画像を描画するクラスを作成する m_pSprite = new Mesh::Sprite(); hr = m_pSprite->Create(hwnd, &IMAGE_FILE_NAME); // コライダーを作成する m_pCollider = new RectangleCollider(); m_pCollider->Create(this, m_pSprite->m_pVertexArray); // タグを設定する m_tag = Tag::TEST; return hr; } void SpriteTest::LateUpdate() { // コライダーのリストを取得 for (auto collider : DirectXRenderer::instance->m_ColliderList) { // プレイヤーとのみ衝突する if (collider->m_pGameObject->m_tag != Tag::PLAYER) { continue; } // 衝突判定をする if (!m_pCollider->CheckCollider(collider)) { continue; } // 右に移動(テスト用) MoveX(0.05f); } }
メインクラスに保持してあるコライダーを取得し、自分のコライダーに命令を送ります。 衝突している場合、右に移動しています。 また、オブジェクトごとのタグによりプレイヤーを認識しています。
あとがき
このブログとしては初の、ソースについての解説になりました。実際に何をしているかの説明は難しいですね・・・! 何度も練習して上達したいと思います。
C++ 衝突判定に成功しました(一応)
こんばんは。ネノワヲンです。
実装した動作
プレイヤーに当たると右に動く機能を実装しました。
衝突判定できた。 pic.twitter.com/qitOkRQbjH
— ネノワヲン (@nenowawon) 2018年11月15日
実は、オブジェクトごとのタグ付けや、衝突時の処理分岐などもできるようにしてあります。
また改めて中身のソースコードを交えた記事を書こうかと思います。
ご覧いただきありがとうございました。
Directx11 オブジェクトごとに違う画像を使う
こんばんは。ネノワヲンです。
今回は、タイトル通りオブジェクトごとに違う画像を表示させようとしました。
今日起こったバグ
本来は、上と下で画像がそろっていなければいけないのですが、中途半端に混ざる現象が起こりました…。
理由
・PSSetShaderResources
・PSSetSamplers
をDraw命令の後に呼んでいたことが原因でした・・・。
当たり前のことではありますが、命令の順番には十分に気を付ける必要がありますね・・・。
このような不思議な現象が起こったら、この記事を思い出してみてください。
C++ 衝突判定のクラス設計を考えてみた
こんばんは。ネノワヲンです。
今回は、衝突判定のクラス設計を考えてみました。
オブジェクトがそれぞれ1つコライダークラスを持ち、衝突判定の命令をします。
その際、他のコライダーを取得する必要があるため、メインクラスにコライダー一覧を持たせます。
そして、衝突判定に必要なパラメータを取得するため、コライダーはオブジェクトの参照を持ちます。
もっといい設計がありそうな気はしますが…
今回はこんな感じでやってみようと思います。
今回はファミコンのスーパーマリオブラザーズを作ろうと思います。
Detroit Become Human 感想
トロコンしました。
このゲームは、3人のアンドロイドを操作するアドベンチャーゲームです。
実はこのゲーム、4周しました。
このゲームのすごいと思ったところは、自分が取った行動が他のシーンにも影響を与え、最終的には物語の結末さえ変えるところです。
例えば、他の主人公が起こした事件を別の主人公で捜査したり、ニュースに報道されたりなど。
「ここでこうしたらどうなるんだろう?」というワクワクがあります。
また、すごく自由度が高い反面、物語が成り立たなくなるような事はできないようになっています。この塩梅が絶妙で、自由にしつつもゲームを楽しめます。
このゲームに関してはもっと語りたいことがあるのですが、うまく言葉にできないのでまた今度にします…。
駄文長文失礼しました。
トロフィー取った瞬間だいたい黒い