//======================================================================== // File: MovementController.cpp // // Part of the GameCode4 Application // // GameCode4 is the sample application that encapsulates much of the source code // discussed in "Game Coding Complete - 4th Edition" by Mike McShaffry and David // "Rez" Graham, published by Charles River Media. // ISBN-10: 1133776574 | ISBN-13: 978-1133776574 // // If this source code has found it's way to you, and you think it has helped you // in any way, do the authors a favor and buy a new copy of the book - there are // detailed explanations in it that compliment this code well. Buy a copy at Amazon.com // by clicking here: // http://www.amazon.com/gp/product/1133776574/ref=olp_product_details?ie=UTF8&me=&seller= // // There's a companion web site at http://www.mcshaffry.com/GameCode/ // // The source code is managed and maintained through Google Code: // http://code.google.com/p/gamecode4/ // // (c) Copyright 2012 Michael L. McShaffry and David Graham // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser GPL v3 // as published by the Free Software Foundation. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See // http://www.gnu.org/licenses/lgpl-3.0.txt for more details. // // You should have received a copy of the GNU Lesser GPL v3 // along with this program; if not, write to the Free Software // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. // //======================================================================== #include "../Unix/GameCodeStd.h" #include "Geometry.h" #include "MovementController.h" #include "SceneNodes.h" //////////////////////////////////////////////////// // MovementController Implementation - Chapter 10, page 282 //////////////////////////////////////////////////// #define MAX(a, b) ((a) >= (b) ? (a) : (b)) #define MIN(a, b) ((a) < (b) ? (a) : (b)) MovementController::MovementController(std::shared_ptr object, float initialYaw, float initialPitch, bool rotateWhenLButtonDown) : m_object(object) { m_object->VGet()->Transform(&m_matToWorld, &m_matFromWorld); m_fTargetYaw = m_fYaw = glm::degrees(-initialYaw); m_fTargetPitch = m_fPitch = glm::degrees(initialPitch); m_maxSpeed = 30.0f; // 30 meters per second m_currentSpeed = 0.0f; glm::vec3 pos = geometry::GetPosition(m_matToWorld); m_matPosition = geometry::BuildTranslation(pos); float mouseX, mouseY; SDL_MouseButtonFlags mouseState = SDL_GetMouseState(&mouseX, &mouseY); m_lastMousePos.x = (int) mouseX; m_lastMousePos.y = (int) mouseY; memset(m_bKey, 0x00, sizeof(m_bKey)); m_mouseLButtonDown = mouseState & SDL_BUTTON_LEFT; m_bRotateWhenLButtonDown = rotateWhenLButtonDown; } bool MovementController::VOnPointerButtonDown(const Point &mousePos, const int radius, const std::string &buttonName) { if (buttonName == "PointerLeft") { m_mouseLButtonDown = true; // We want mouse movement to be relative to the position // the cursor was at when the user first presses down on // the left button m_lastMousePos = mousePos; return true; } return false; } bool MovementController::VOnPointerButtonUp(const Point &mousePos, const int radius, const std::string &buttonName) { if (buttonName == "PointerLeft") { m_mouseLButtonDown = false; return true; } return false; } // class MovementController::VOnMouseMove - Chapter 10, page 282 bool MovementController::VOnPointerMove(const Point &mousePos, const int radius) { // There are two modes supported by this controller. if (m_bRotateWhenLButtonDown) { // Mode 1 - rotate the view only when the left mouse button is down // Only look around if the left button is down if(m_lastMousePos!=mousePos && m_mouseLButtonDown) { m_fTargetYaw = m_fTargetYaw + (mousePos.x - m_lastMousePos.x); m_fTargetPitch = m_fTargetPitch + (mousePos.y - m_lastMousePos.y); m_lastMousePos = mousePos; } } else if(m_lastMousePos!=mousePos) { m_fTargetYaw = m_fTargetYaw + (mousePos.x - m_lastMousePos.x); m_fTargetPitch = m_fTargetPitch + (m_lastMousePos.y - mousePos.y); m_lastMousePos = mousePos; } return true; } // class MovementController::OnUpdate - Chapter 10, page 283 void MovementController::OnUpdate(uint64_t const deltaMilliseconds) { //if (m_bKey['Q']) //{ // // This code is a cheat to position the camera exactly in a given // // spot so I can take screen shots! // Mat4x4 camTranslate; // D3DXMatrixTranslation(&m_matPosition, 8.847f, 7.055f, 11.618f); // m_fTargetYaw = m_fYaw += -64.35f; // m_fTargetPitch = m_fPitch = 28.57f; // // Calculate the new rotation matrix from the camera // // yaw and pitch. // Mat4x4 matRot; // D3DXMatrixRotationYawPitchRoll(&matRot, DEGREES_TO_RADIANS(m_fYaw), DEGREES_TO_RADIANS(m_fPitch), 0); // // Create the new object-to-world matrix, and the // // new world-to-object matrix. // D3DXMatrixMultiply(&m_matToWorld, &matRot, &m_matPosition); // D3DXMatrixInverse(&m_matFromWorld, NULL, &m_matToWorld); // m_object->VSetTransform(&m_matToWorld, &m_matFromWorld); // return; //} bool bTranslating = false; glm::vec4 atWorld(0,0,0,0); glm::vec4 rightWorld(0,0,0,0); glm::vec4 upWorld(0,0,0,0); if (m_bKey[SDL_SCANCODE_W] || m_bKey[SDL_SCANCODE_S]) { // In D3D, the "look at" default is always // the positive Z axis. glm::vec4 at = -g_Forward4; if (m_bKey[SDL_SCANCODE_S]) at *= -1; // This will give us the "look at" vector // in world space - we'll use that to move // the camera. atWorld = m_matToWorld * at; bTranslating = true; } if (m_bKey[SDL_SCANCODE_A] || m_bKey[SDL_SCANCODE_D]) { // In D3D, the "right" default is always // the positive X axis. glm::vec4 right = g_Right4; if (m_bKey[SDL_SCANCODE_A]) right *= -1; // This will give us the "right" vector // in world space - we'll use that to move // the camera rightWorld = m_matToWorld * right; bTranslating = true; } if (m_bKey[SDL_SCANCODE_SPACE] || m_bKey[SDL_SCANCODE_C] || m_bKey[SDL_SCANCODE_X]) { // In D3D, the "up" default is always // the positive Y axis. glm::vec4 up = g_Up4; if (!m_bKey[SDL_SCANCODE_SPACE]) up *= -1; //Unlike strafing, Up is always up no matter //which way you are looking upWorld = up; bTranslating = true; } // Handling rotation as a result of mouse position { // The secret formula!!! Don't give it away! //If you are seeing this now, then you must be some kind of elite hacker! m_fYaw += (m_fTargetYaw - m_fYaw) * ( .35f ); m_fTargetPitch = MAX(-90, MIN(90, m_fTargetPitch)); m_fPitch += (m_fTargetPitch - m_fPitch) * ( .35f ); // Calculate the new rotation matrix from the camera // yaw and pitch. glm::mat4 matRot = geometry::BuildYawPitchRoll(glm::radians(-m_fYaw), glm::radians(m_fPitch), 0); // Create the new object-to-world matrix, and the // new world-to-object matrix. m_matToWorld = m_matPosition * matRot; m_matFromWorld = glm::inverse(m_matToWorld); m_object->VSetTransform(m_matToWorld, m_matFromWorld); } if (bTranslating) { float elapsedTime = (float)deltaMilliseconds / 1000.0f; glm::vec3 direction = atWorld + rightWorld + upWorld; direction = glm::normalize(direction); // Ramp the acceleration by the elapsed time float numberOfSeconds = 5.f; m_currentSpeed += m_maxSpeed * ( (elapsedTime*elapsedTime) / numberOfSeconds); if (m_currentSpeed > m_maxSpeed) m_currentSpeed = m_maxSpeed; direction *= m_currentSpeed; glm::vec3 pos = geometry::GetPosition(m_matPosition) + direction; geometry::SetPosition(m_matPosition, pos); geometry::SetPosition(m_matToWorld, pos); m_matFromWorld = glm::inverse(m_matToWorld); m_object->VSetTransform(m_matToWorld, m_matFromWorld); } else { m_currentSpeed = 0.0f; } }