stevo14 d72aaa70f5 Camera now points in the direction that the kart will be turning (but less so at higher speeds in order to reduce sudden camera movement).
git-svn-id: svn+ssh://svn.code.sf.net/p/supertuxkart/code/main/branches/irrlicht@3467 178a84e3-b1eb-0310-8ba1-8eac791a3b58
2009-05-07 15:17:58 +00:00

215 lines
7.3 KiB
C++

// $Id$
//
// SuperTuxKart - a fun racing game with go-kart
// Copyright (C) 2004-2005 Steve Baker <sjbaker1@airmail.net>
// Copyright (C) 2006 SuperTuxKart-Team, Steve Baker
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 3
// of the License, or (at your option) any later version.
//
// 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 the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "graphics/camera.hpp"
#include "user_config.hpp"
#include "audio/sound_manager.hpp"
#include "graphics/irr_driver.hpp"
#include "karts/player_kart.hpp"
#include "modes/world.hpp"
#include "race_manager.hpp"
#include "tracks/track.hpp"
#include "utils/constants.hpp"
#include "utils/coord.hpp"
Camera::Camera(int camera_index, const Kart* kart)
{
m_mode = CM_NORMAL;
m_index = camera_index;
m_camera = irr_driver->addCamera();
m_distance = kart->getKartProperties()->getCameraDistance() * 0.75f;
m_kart = kart;
m_angle_up = 0.0f;
m_angle_around = 0.0f;
// TODO: Put these values into a config file
m_position_speed = 8.0f;
m_target_speed = 10.0;
// TODO: Set fog distance and clipping planes
setScreenPosition(camera_index);
} // Camera
// ----------------------------------------------------------------------------
Camera::~Camera()
{
reset();
}
// ----------------------------------------------------------------------------
void Camera::setScreenPosition(int camera_index)
{
const int num_players = race_manager->getNumLocalPlayers();
assert(camera_index >= 0 && camera_index <= 3);
if (num_players == 1)
{
// m_camera->setFOV( DEGREE_TO_RAD(75.0f) ) ;
m_x = 0.0f; m_y = 0.0f; m_w = 1.0f; m_h = 1.0f ;
}
else if (num_players == 2)
{
// m_context -> setFOV ( 85.0f, 85.0f*3.0f/8.0f ) ;
switch ( camera_index )
{
case 0 : m_x = 0.0f; m_y = 0.5f; m_w = 1.0f; m_h = 0.5f; break;
case 1 : m_x = 0.0f; m_y = 0.0f; m_w = 1.0f; m_h = 0.5f; break;
}
}
else if (num_players == 3)
{
// m_context -> setFOV ( 50.0f, 0.0f );
switch ( camera_index )
{
case 0 : m_x = 0.0f; m_y = 0.5f; m_w = 0.5f; m_h = 0.5f; break;
case 1 : m_x = 0.5f; m_y = 0.5f; m_w = 0.5f; m_h = 0.5f; break;
case 2 : m_x = 0.0f; m_y = 0.0f; m_w = 1.0f; m_h = 0.5f;
// m_context -> setFOV ( 85.0f, 85.0f*3.0f/8.0f );
break;
}
}
else if (num_players == 4)
{
// m_context -> setFOV ( 50.0f, 0.0f );
switch ( camera_index )
{
case 0 : m_x = 0.0f; m_y = 0.5f; m_w = 0.5f; m_h = 0.5f; break;
case 1 : m_x = 0.5f; m_y = 0.5f; m_w = 0.5f; m_h = 0.5f; break;
case 2 : m_x = 0.0f; m_y = 0.0f; m_w = 0.5f; m_h = 0.5f; break;
case 3 : m_x = 0.5f; m_y = 0.0f; m_w = 0.5f; m_h = 0.5f; break;
}
}
} // setScreenPosition
//-----------------------------------------------------------------------------
void Camera::setMode(Mode mode)
{
m_mode = mode;
} // setMode
// ----------------------------------------------------------------------------
Camera::Mode Camera::getMode()
{
return m_mode;
}
//-----------------------------------------------------------------------------
/** Reset is called when a new race starts. Make sure that the camera
is aligned neutral, and not like in the previous race
*/
void Camera::reset()
{
setMode(CM_NORMAL);
// m_position, m_target etc. are set when the worlds has computed the right starting
// position of all karts and calls setInitialTransform for each camera.
} // reset
//-----------------------------------------------------------------------------
/** Saves the current kart position as initial starting position for the
* camera.
*/
void Camera::setInitialTransform()
{
m_position = Vec3(0,0,0);
m_target = m_kart->getXYZ();
m_temp_position = m_position;
m_temp_target = m_target;
} // updateKartPosition
//-----------------------------------------------------------------------------
void Camera::update(float dt)
{
// Each case should set m_target and m_position according to what is needed for that mode.
// Yes, there is a lot of duplicate code but it is (IMHO) much easier to follow this way.
switch(m_mode)
{
case CM_NORMAL:
// This first line moves the camera around behind the kart, pointing it
// towards where the kart is turning (but only at lower speeds).
m_angle_around = m_kart->getHPR().getX() + (m_kart->getSteerPercent() / (m_kart->getSpeed() * 0.1f + 1));
m_angle_up = m_kart->getHPR().getY() - DEGREE_TO_RAD(30.0f);
m_target = m_kart->getXYZ();
m_position.setX( sin(m_angle_around));
m_position.setY(-cos(m_angle_around));
m_position.setZ(-sin(m_angle_up));
m_position *= m_distance;
m_position += m_target;
break;
case CM_CLOSEUP: // Lower to the ground and closer to the kart
m_angle_around = m_kart->getHPR().getX() + (m_kart->getSteerPercent() / (m_kart->getSpeed() * 0.1f + 1));
m_angle_up = m_kart->getHPR().getY() - DEGREE_TO_RAD(20.0f);
m_target = m_kart->getXYZ();
m_position.setX( sin(m_angle_around));
m_position.setY(-cos(m_angle_around));
m_position.setZ(-sin(m_angle_up));
m_position *= m_distance * 0.75f;
m_position += m_target;
break;
case CM_LEADER_MODE: // Follows the leader kart, higher off of the ground, further from the kart,
// and turns in the opposite direction from the kart for a nice effect. :)
m_angle_around = RaceManager::getKart(0)->getHPR().getX();
m_angle_up = RaceManager::getKart(0)->getHPR().getY() + DEGREE_TO_RAD(40.0f);
m_target = RaceManager::getKart(0)->getXYZ();
m_position.setX(sin(m_angle_around));
m_position.setY(cos(m_angle_around));
m_position.setZ(sin(m_angle_up));
m_position *= m_distance * 2.0f;
m_position += m_target;
break;
case CM_FINAL:
// TODO: Implement
break;
case CM_SIMPLE_REPLAY:
// TODO: Implement
break;
}
// Smoothly interpolate towards the position and target
m_temp_target += ((m_target - m_temp_target) * m_target_speed) * dt;
m_temp_position += ((m_position - m_temp_position) * m_position_speed) * dt;
m_camera->setPosition(m_temp_position.toIrrVector());
m_camera->setTarget(m_temp_target.toIrrVector());
if(race_manager->getNumLocalPlayers() < 2)
sound_manager->positionListener(m_temp_position, m_temp_target - m_temp_position);
} // update
//-----------------------------------------------------------------------------
void Camera::apply ()
{
} // apply