/*********************************************************************** File : walljump.cpp Author: Jonathan Rust WallJump uses the direction the player is facing (i.e., the Y rotation of the camera) - as well as the current velocity and the normal of the wall being jumped off of - to calculate which direction the player should jump. All content © 2011 DigiPen (USA) Corporation, all rights reserved. ************************************************************************/ #pragma hdrstop #include "jump.h" #include "walljump.h" #include "Core/Entity/entity.h" #include #include "Core/GameState/gameState.h" #include "Core/GameState/gameStateManager.h" #include "Core/input.h" #include "Game/GameCameraSystem.h" #include "Serialization/jsonSerializer.h" #include "Editor/editorMessages.h" #include "Core/Messages/message.h" #include "Physics/body.h" registerType(WallJump); WallJump::WallJump() : vertJumpSpeed(3.0f), horiJumpSpeed(3.0f) {} float WallJump::getVertJumpSpeed() const { return vertJumpSpeed; } void WallJump::setVertJumpSpeed(float value) { vertJumpSpeed = value; } float WallJump::getHoriJumpSpeed() const { return horiJumpSpeed; } void WallJump::setHoriJumpSpeed(float value) { horiJumpSpeed = value; } SERIALIZE_FUNCTION_IMPLEMENTATION(WallJump, 0) { //start serialization SERIALIZE_START(); SERIALIZE_BASE(Component); //serialize variables SERIALIZE(vertJumpSpeed); SERIALIZE(horiJumpSpeed); //end serialization SERIALIZE_END(); } void WallJump::init(Entity & entity) { //initialize base Component::init(entity); //ensure the player position component exists playerPosition = getOwner()->findComponent(); if (!playerPosition) getOwner()->addComponent(new PlayerPosition()); //ensure the component is unregistered for the collision message when destroyed unregisterFromKeyDown = getOwningGameState()->registerForGlobalEvent(*this, KeyDown, &WallJump::onKeyDown); unregisterFromKeyDown.setUnregisterInDestructor(true); getOwningGameState()->registerForGlobalEvent(*this, NewLevelVersion, [](WallJump & handler, LevelVersionMessage & msg) { if (msg.getOldVersion() == 0) { handler.Component::setDisabled(false); } }); } void WallJump::update(const FrameTime &) { //this function is empty because the entire action is handled upon keydown for space bar } void WallJump::onKeyDown(KeyboardMessage &msg) { //ignore message if component is disabled or incorrect key is pressed if (Component::isDisabled() || getGameStateManager().isPaused() || msg.getKey() != ' ') return; //current velocity of the player Vector4 currVel = getOwner()->getBody()->getVelocity(); //only walljump if player is on wall and not on floor if (playerPosition->isOnWallScaled() && !playerPosition->isOnFloorScaled()) { Vector4 newVel(0); //find direction player is facing, to be used to determine where to jump float rotateY = getOwningGameState()->findSystem()->getCamera().getRotateY(); Vector4 cameraDir = Vector4(sin(rotateY), 0, cos(rotateY), 0); cameraDir.y = cameraDir.w = 0; cameraDir.normalize(); //ignore any vertical velocity, as it is irrelevant (and w should always be zero anyway) currVel.y = currVel.w = 0; //compare camera direction to velocity and wall normal float camDotVel = cameraDir.dot(currVel).getValue(); float camDotWall = cameraDir.dot(playerPosition->getWallNormal()).getValue(); //facing backward (should never happen once other code is implemented, but hey let's handle it anyway JUST IN CASE) if (camDotVel < -0.0001f) { //jump only slightly away from the wall newVel = playerPosition->getWallNormal().normalized() * (horiJumpSpeed + currVel.length().getValue()); newVel.y = vertJumpSpeed; //facing away from wall } else if (camDotWall > -0.15f) { //not facing enough away from the wall if (camDotWall < 0.15f) //jump only slightly away from the wall newVel = (currVel.normalized() * (horiJumpSpeed + currVel.length().getValue())) + (playerPosition->getWallNormal().normalized() * 0.5f); else //jump in the direction the player is facing newVel = cameraDir * (horiJumpSpeed + currVel.length().getValue()); newVel.y = vertJumpSpeed; //facing into wall } else { //jump only slightly away from the wall newVel = playerPosition->getWallNormal().normalized() * horiJumpSpeed; newVel += currVel; newVel.y = vertJumpSpeed; } //now actually apply the velocity, and let other components know the jump has begun getOwner()->getBody()->setVelocity(newVel); getOwner()->sendMessage(new Message(JumpStart)); } }