Skip to content

Commit

Permalink
Add third person view
Browse files Browse the repository at this point in the history
  • Loading branch information
BlockMen committed Apr 12, 2014
1 parent e149d1a commit a1db924
Show file tree
Hide file tree
Showing 19 changed files with 270 additions and 22 deletions.
6 changes: 6 additions & 0 deletions doc/lua_api.txt
Expand Up @@ -1874,6 +1874,12 @@ Player-only: (no-op for other objects)
- override_day_night_ratio(ratio or nil)
^ 0...1: Overrides day-night ratio, controlling sunlight to a specific amount
^ nil: Disables override, defaulting to sunlight based on day-night cycle
- set_local_animation({x=0, y=79}, {x=168, y=187}, {x=189, y=198}, {x=200, y=219}, frame_speed=30): set animation for player model in third person view
^ stand/idle animation key frames
^ walk animation key frames
^ dig animation key frames
^ walk+dig animation key frames
^ animation frame speed

InvRef: Reference to an inventory
methods:
Expand Down
1 change: 1 addition & 0 deletions minetest.conf.example
Expand Up @@ -361,6 +361,7 @@
# try reducing it, but don't reduce it to a number below double of targeted
# client number
#max_packets_per_iteration = 1024

#
# Physics stuff
#
Expand Down
61 changes: 53 additions & 8 deletions src/camera.cpp
Expand Up @@ -40,6 +40,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,

#define CAMERA_OFFSET_STEP 200

#include "nodedef.h"
#include "game.h" // CameraModes

Camera::Camera(scene::ISceneManager* smgr, MapDrawControl& draw_control,
IGameDef *gamedef):
m_smgr(smgr),
Expand Down Expand Up @@ -248,7 +251,8 @@ void Camera::step(f32 dtime)
}

void Camera::update(LocalPlayer* player, f32 frametime, f32 busytime,
v2u32 screensize, f32 tool_reload_ratio)
v2u32 screensize, f32 tool_reload_ratio,
int current_camera_mode, ClientEnvironment &c_env)
{
// Get player position
// Smooth the movement when walking up stairs
Expand Down Expand Up @@ -276,7 +280,7 @@ void Camera::update(LocalPlayer* player, f32 frametime, f32 busytime,

// Fall bobbing animation
float fall_bobbing = 0;
if(player->camera_impact >= 1)
if(player->camera_impact >= 1 && current_camera_mode < CAMERA_MODE_THIRD)
{
if(m_view_bobbing_fall == -1) // Effect took place and has finished
player->camera_impact = m_view_bobbing_fall = 0;
Expand All @@ -303,7 +307,7 @@ void Camera::update(LocalPlayer* player, f32 frametime, f32 busytime,
v3f rel_cam_target = v3f(0,0,1);
v3f rel_cam_up = v3f(0,1,0);

if (m_view_bobbing_anim != 0)
if (m_view_bobbing_anim != 0 && current_camera_mode < CAMERA_MODE_THIRD)
{
f32 bobfrac = my_modf(m_view_bobbing_anim * 2);
f32 bobdir = (m_view_bobbing_anim < 0.5) ? 1.0 : -1.0;
Expand Down Expand Up @@ -352,19 +356,60 @@ void Camera::update(LocalPlayer* player, f32 frametime, f32 busytime,
v3f abs_cam_up;
m_headnode->getAbsoluteTransformation().rotateVect(abs_cam_up, rel_cam_up);

// Seperate camera position for calculation
v3f my_cp = m_camera_position;

// Reposition the camera for third person view
if (current_camera_mode > CAMERA_MODE_FIRST) {

if (current_camera_mode == CAMERA_MODE_THIRD_FRONT)
m_camera_direction *= -1;

my_cp.Y += 2;

// Calculate new position
bool abort = false;
for (int i = BS; i <= BS*2; i++) {
my_cp.X = m_camera_position.X + m_camera_direction.X*-i;
my_cp.Z = m_camera_position.Z + m_camera_direction.Z*-i;
if (i > 12)
my_cp.Y = m_camera_position.Y + (m_camera_direction.Y*-i);

// Prevent camera positioned inside nodes
INodeDefManager *nodemgr = m_gamedef->ndef();
MapNode n = c_env.getClientMap().getNodeNoEx(floatToInt(my_cp, BS));
const ContentFeatures& features = nodemgr->get(n);
if(features.walkable) {
my_cp.X += m_camera_direction.X*-1*-BS/2;
my_cp.Z += m_camera_direction.Z*-1*-BS/2;
my_cp.Y += m_camera_direction.Y*-1*-BS/2;
abort = true;
break;
}
}

// If node blocks camera position don't move y to heigh
if (abort && my_cp.Y > player_position.Y+BS*2)
my_cp.Y = player_position.Y+BS*2;
}

// Update offset if too far away from the center of the map
m_camera_offset.X += CAMERA_OFFSET_STEP*
(((s16)(m_camera_position.X/BS) - m_camera_offset.X)/CAMERA_OFFSET_STEP);
(((s16)(my_cp.X/BS) - m_camera_offset.X)/CAMERA_OFFSET_STEP);
m_camera_offset.Y += CAMERA_OFFSET_STEP*
(((s16)(m_camera_position.Y/BS) - m_camera_offset.Y)/CAMERA_OFFSET_STEP);
(((s16)(my_cp.Y/BS) - m_camera_offset.Y)/CAMERA_OFFSET_STEP);
m_camera_offset.Z += CAMERA_OFFSET_STEP*
(((s16)(m_camera_position.Z/BS) - m_camera_offset.Z)/CAMERA_OFFSET_STEP);
(((s16)(my_cp.Z/BS) - m_camera_offset.Z)/CAMERA_OFFSET_STEP);

// Set camera node transformation
m_cameranode->setPosition(m_camera_position-intToFloat(m_camera_offset, BS));
m_cameranode->setPosition(my_cp-intToFloat(m_camera_offset, BS));
m_cameranode->setUpVector(abs_cam_up);
// *100.0 helps in large map coordinates
m_cameranode->setTarget(m_camera_position-intToFloat(m_camera_offset, BS) + 100 * m_camera_direction);
m_cameranode->setTarget(my_cp-intToFloat(m_camera_offset, BS) + 100 * m_camera_direction);

// update the camera position in front-view mode to render blocks behind player
if (current_camera_mode == CAMERA_MODE_THIRD_FRONT)
m_camera_position = my_cp;

// Get FOV setting
f32 fov_degrees = g_settings->getFloat("fov");
Expand Down
5 changes: 4 additions & 1 deletion src/camera.h
Expand Up @@ -27,6 +27,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "util/numeric.h"
#include <ICameraSceneNode.h>

#include "client.h"

class LocalPlayer;
struct MapDrawControl;
class IGameDef;
Expand Down Expand Up @@ -113,7 +115,8 @@ class Camera
// Update the camera from the local player's position.
// busytime is used to adjust the viewing range.
void update(LocalPlayer* player, f32 frametime, f32 busytime,
v2u32 screensize, f32 tool_reload_ratio);
v2u32 screensize, f32 tool_reload_ratio,
int current_camera_mode, ClientEnvironment &c_env);

// Render distance feedback loop
void updateViewingRange(f32 frametime_in, f32 busytime_in);
Expand Down
14 changes: 14 additions & 0 deletions src/client.cpp
Expand Up @@ -1914,6 +1914,20 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
event.override_day_night_ratio.ratio_f = day_night_ratio_f;
m_client_event_queue.push_back(event);
}
else if(command == TOCLIENT_LOCAL_PLAYER_ANIMATIONS)
{
std::string datastring((char *)&data[2], datasize - 2);
std::istringstream is(datastring, std::ios_base::binary);

LocalPlayer *player = m_env.getLocalPlayer();
assert(player != NULL);

player->local_animations[0] = readV2F1000(is);
player->local_animations[1] = readV2F1000(is);
player->local_animations[2] = readV2F1000(is);
player->local_animations[3] = readV2F1000(is);
player->local_animation_speed = readF1000(is);
}
else
{
infostream<<"Client: Ignoring unknown command "
Expand Down
6 changes: 5 additions & 1 deletion src/clientmap.cpp
Expand Up @@ -29,6 +29,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "mapblock.h"
#include "profiler.h"
#include "settings.h"
#include "game.h" // CameraModes
#include "util/mathconstants.h"
#include <algorithm>

Expand Down Expand Up @@ -866,13 +867,16 @@ void ClientMap::renderPostFx()
v3f camera_position = m_camera_position;
m_camera_mutex.Unlock();

LocalPlayer *player = m_client->getEnv().getLocalPlayer();

MapNode n = getNodeNoEx(floatToInt(camera_position, BS));

// - If the player is in a solid node, make everything black.
// - If the player is in liquid, draw a semi-transparent overlay.
// - Do not if player is in third person mode
const ContentFeatures& features = nodemgr->get(n);
video::SColor post_effect_color = features.post_effect_color;
if(features.solidness == 2 && !(g_settings->getBool("noclip") && m_gamedef->checkLocalPrivilege("noclip")))
if(features.solidness == 2 && !(g_settings->getBool("noclip") && m_gamedef->checkLocalPrivilege("noclip")) && player->camera_mode == CAMERA_MODE_FIRST)
{
post_effect_color = video::SColor(255, 0, 0, 0);
}
Expand Down
10 changes: 10 additions & 0 deletions src/clientserver.h
Expand Up @@ -530,6 +530,16 @@ enum ToClientCommand
u8 do_override (boolean)
u16 day-night ratio 0...65535
*/

TOCLIENT_LOCAL_PLAYER_ANIMATIONS = 0x51,
/*
u16 command
v2f1000 stand/idle
v2f1000 walk
v2f1000 dig
v2f1000 walk+dig
f1000 frame_speed
*/
};

enum ToServerCommand
Expand Down
82 changes: 76 additions & 6 deletions src/content_cao.cpp
Expand Up @@ -41,6 +41,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "util/mathconstants.h"
#include "map.h"
#include "main.h" // g_settings
#include "game.h" // CameraModes
#include <IMeshManipulator.h>
#include <IAnimatedMeshSceneNode.h>
#include <IBoneSceneNode.h>
Expand Down Expand Up @@ -858,7 +859,7 @@ class GenericCAO : public ClientActiveObject

m_visuals_expired = false;

if(!m_prop.is_visible || m_is_local_player)
if(!m_prop.is_visible)
return;

//video::IVideoDriver* driver = smgr->getVideoDriver();
Expand Down Expand Up @@ -1078,6 +1079,60 @@ class GenericCAO : public ClientActiveObject

void step(float dtime, ClientEnvironment *env)
{
// Handel model of local player instantly to prevent lags
if(m_is_local_player) {
LocalPlayer *player = m_env->getLocalPlayer();

if (player->camera_mode > CAMERA_MODE_FIRST) {
int old_anim = player->last_animation;
float old_anim_speed = player->last_animation_speed;
m_is_visible = true;
m_position = player->getPosition() + v3f(0,BS,0);
m_velocity = v3f(0,0,0);
m_acceleration = v3f(0,0,0);
pos_translator.vect_show = m_position;
m_yaw = player->getYaw();
PlayerControl controls = player->getPlayerControl();

bool walking = false;
if(controls.up || controls.down || controls.left || controls.right)
walking = true;

m_animation_speed = player->local_animation_speed;
if(controls.sneak && walking)
m_animation_speed = player->local_animation_speed/2;

player->last_animation_speed = m_animation_speed;

if(walking && (controls.LMB || controls.RMB)) {
m_animation_range = player->local_animations[3];
player->last_animation = WD_ANIM;
} else if(walking) {
m_animation_range = player->local_animations[1];
player->last_animation = WALK_ANIM;
} else if(controls.LMB || controls.RMB) {
m_animation_range = player->local_animations[2];
player->last_animation = DIG_ANIM;
}

// reset animation when no input detected
if (!walking && !controls.LMB && !controls.RMB) {
player->last_animation = NO_ANIM;
if (old_anim != NO_ANIM) {
m_animation_range = player->local_animations[0];
updateAnimation();
}
}

// Update local player animations
if ((player->last_animation != old_anim && player->last_animation != NO_ANIM) || m_animation_speed != old_anim_speed)
updateAnimation();

} else {
m_is_visible = false;
}
}

if(m_visuals_expired && m_smgr && m_irr){
m_visuals_expired = false;

Expand Down Expand Up @@ -1701,6 +1756,7 @@ class GenericCAO : public ClientActiveObject
bool sneak = !readU8(is);
bool sneak_glitch = !readU8(is);


if(m_is_local_player)
{
LocalPlayer *player = m_env->getLocalPlayer();
Expand All @@ -1713,11 +1769,25 @@ class GenericCAO : public ClientActiveObject
}
else if(cmd == GENERIC_CMD_SET_ANIMATION)
{
m_animation_range = readV2F1000(is);
m_animation_speed = readF1000(is);
m_animation_blend = readF1000(is);

updateAnimation();
if (!m_is_local_player) {
m_animation_range = readV2F1000(is);
m_animation_speed = readF1000(is);
m_animation_blend = readF1000(is);
updateAnimation();
} else {
LocalPlayer *player = m_env->getLocalPlayer();
if(player->last_animation == NO_ANIM) {
m_animation_range = readV2F1000(is);
m_animation_speed = readF1000(is);
m_animation_blend = readF1000(is);
}
// update animation only if object is not player
// or the received animation is not registered
if(m_animation_range.X != player->local_animations[1].X &&
m_animation_range.X != player->local_animations[2].X &&
m_animation_range.X != player->local_animations[3].X)
updateAnimation();
}
}
else if(cmd == GENERIC_CMD_SET_BONE_POSITION)
{
Expand Down
1 change: 1 addition & 0 deletions src/defaultsettings.cpp
Expand Up @@ -53,6 +53,7 @@ void set_default_settings(Settings *settings)
settings->setDefault("keymap_toggle_update_camera", "KEY_F4");
settings->setDefault("keymap_toggle_debug", "KEY_F5");
settings->setDefault("keymap_toggle_profiler", "KEY_F6");
settings->setDefault("keymap_camera_mode", "KEY_F7");
settings->setDefault("keymap_increase_viewing_range_min", "+");
settings->setDefault("keymap_decrease_viewing_range_min", "-");
settings->setDefault("anaglyph", "false");
Expand Down

0 comments on commit a1db924

Please sign in to comment.