OSDN Git Service

ver0.2.3 ジャンプ式の最終確定(恐らく)
authorangeart <angeart@git.sourceforge.jp>
Sat, 8 Sep 2012 12:49:44 +0000 (21:49 +0900)
committerangeart <angeart@git.sourceforge.jp>
Sat, 8 Sep 2012 12:49:44 +0000 (21:49 +0900)
client/3d/PlayerCharacter.cpp
client/version.hpp

index 06a0b55..aa6b5ef 100644 (file)
@@ -8,6 +8,18 @@
 #include "MotionPlayer.hpp"
 #include "../../common/Logger.hpp"
 
+
+namespace
+{
+
+template <typename T, typename U>
+inline bool NearlyEqualRelative(const T& lhs, const T& rhs, const U& ratio)
+{
+    return abs(lhs - rhs) <= ratio * abs(rhs);
+}
+
+}
+
 class PlayerCharacter::Impl
 {
 public:
@@ -16,8 +28,14 @@ public:
           model_handle_(-1),
           current_target_pos_(VGet(0, 1000, 0)),
           prev_target_pos_(VGet(0, 1000, 0)),
+                 current_target_vec_y_(0.0f),
           current_rot_(VGet(0, 0, 0)),
           prev_rot_(VGet(0, 0, 0)),
+                 move_vec_y_(0.0f),
+                 jump_flag_(false),
+                 flight_duration_ideal_(1.0f),
+                 model_height_(1.58f),
+                 jump_height_(sqrt(15.0f)*2.0f),
           current_motion_(-1),
           prev_motion_(-1),
           current_speed_(0),
@@ -32,7 +50,10 @@ public:
         motion.walk_ = MV1GetAnimIndex(model_handle_, _T("walk"));
         motion.run_ = MV1GetAnimIndex(model_handle_, _T("run"));
         motion_player_.reset(new MotionPlayer(model_handle_));
-    }
+
+               model_height_ = data_provider_.model().property().get<float>("character.height",1.58f);
+               flight_duration_ideal_ = sqrt((model_height_*2.0f)/9.8f) + sqrt((model_height_*0.8f)/9.8);      
+       }
 
     void Impl::Draw() const
     {
@@ -43,8 +64,16 @@ public:
 
     void Impl::Update()
     {
+               static auto time_now = 0.0f;
+               prev_target_pos_ = current_target_pos_;
         const auto current_target_pos = data_provider_.target_position();
+               const auto current_target_vec_y_ = data_provider_.vy();
         // if (current_target_pos.y == 0) return;
+               if(current_target_pos != prev_target_pos_ )
+               {
+                       time_now = 0.0f;
+               }
+               
 
         current_target_pos_ = current_target_pos;
         current_pos_ = MV1GetPosition(model_handle_);
@@ -73,50 +102,150 @@ public:
 
             //Logger::Debug("distance_to_target: %d %d", distance_to_target, current_speed_ * timer_->DeltaSec());
 
-            if (current_speed_ * timer_->DeltaSec() > 0.2)
-            {
-                current_motion_ = motion.run_;
-            }
-            else
-            {
-                current_motion_ = motion.stand_;
-            }
-
-            if (current_motion_ != prev_motion_ && current_motion_ != -1)
-            {
-                motion_player_->Play(current_motion_, false, 200, -1, false);
-                prev_motion_ = current_motion_;
-                       }else if(additional_motion_.first)
-                       {
-                               bool connect_prev = true;
-                               motion_player_->Play(additional_motion_.second, connect_prev, 200, -1, false);
-                               additional_motion_.first = false;
-                       }
-
             // TODO: Y下方向については重力加速度
             if (distance_to_target > 2.0){
-                const auto direction = current_target_pos_ - current_pos_;
+                auto direction = current_target_pos_ - current_pos_;
                 const auto diff_pos = VAdjustLength(direction, current_speed_ * timer_->DeltaSec());
                 const float roty = atan2(-direction.x, -direction.z);
+                               const auto time_entire = VSize(direction) / (current_speed_ * (float)timer_->DeltaSec());       // ターゲットまでの移動完了時間
+                               time_now += timer_->DeltaSec(); // タイマーのカウントアップ
 
                 current_rot_ = VGet(0, roty, 0);
                 //std::cout << "set pos to " << MV1GetPosition(model_handle_) + diff_pos << std::endl;
 
+                               /*
+                               const auto jump_result_y =
+                                       jump_height_ * stage_->map_scale() * (time_entire - time_now) * (jump_height_ / 5.0f) * 1.019952f + 
+                                       0.5f * -9.8f * (time_entire - time_now) * (time_entire - time_now) * (1.0f / flight_duration_ideal_) * (jump_height_ / 5.0f) * (jump_height_ / 5.0f);   // 今からジャンプした際の最終的な位置
+                               */
+                               static auto st_acc = -9.8f;
+                               auto acc = -6.5f;
+                               auto prediction_vector = 0.0f;
+                               
+                               for(acc;acc < -11.0f;acc-=0.1f){
+                                       prediction_vector = jump_height_ * stage_->map_scale() + (acc) * (time_entire - time_now) * (jump_height_ / 5.0f) * (1.0f / flight_duration_ideal_ );
+                                       if( current_target_vec_y_ != 0 && jump_flag_ == false )
+                                       {
+                                               // ターゲット座標ではジャンプを始めている
+                                               if( prediction_vector > current_target_vec_y_ - 1 && prediction_vector < current_target_vec_y_ + 1)
+                                               {
+                                                       // 目標座標でベクトルが上向きなら一致、ジャンプを始める
+                                                       move_vec_y_ = jump_height_ * stage_->map_scale();
+                                                       jump_flag_ = true;
+                                               }//     それ以外はそのまま
+                                       }
+                               }
+                               st_acc = acc;
+
+                VECTOR moved_pos;
+                               moved_pos = current_pos_ + diff_pos;
+                               if( jump_flag_ == true )
+                               {
+                                       move_vec_y_ += (st_acc * stage_->map_scale() * timer_->DeltaSec() * (1.0f/flight_duration_ideal_) * (jump_height_ / 5.0f));
+                                       moved_pos.y = current_pos_.y + move_vec_y_ * timer_->DeltaSec() * (jump_height_ / 5.0f);
+                               }
+                               Logger::Debug(_T("move_vec_y %.3f"), move_vec_y_);
+
                 // 床へのめり込みを防止
-                VECTOR moved_pos = current_pos_ + diff_pos;
                 float floor_y;
-                for (int i = 1;
-                        i < 10 && !(stage_->GetFloorY(moved_pos + VGet(0,10 * i,0), moved_pos + VGet(0,-10 * i,0), &floor_y));
-                        i+=2);
-                moved_pos.y = std::max(moved_pos.y, floor_y);
+                               std::pair<bool, VECTOR> floor_coll;
+                               if(jump_flag_ == false)
+                               {
+                                       // 延長線上で接地検査
+                                       floor_coll = stage_->FloorExists(moved_pos,model_height_,8.0f);
+                               }else if(jump_flag_ == true && current_pos_.y >= moved_pos.y)
+                               {
+                                       // 足で接地検査
+                                       floor_coll = stage_->FloorExists(moved_pos,model_height_,0);
+                               }
+                //moved_pos.y = std::max(moved_pos.y, floor_y); // 床にあたっているときは床の方がyが高くなる
+                               if(jump_flag_ == false){
+                                       // 登ったり下ったりできる段差の大きさの制限を求める
+                                       static const float y_max_limit_factor = sin(45 * PHI_F / 180);
+                                       static const float y_min_limit_factor = sin(-45 * PHI_F / 180);
+                                       const float y_max_limit = y_max_limit_factor * VSize(diff_pos);
+                                       const float y_min_limit = y_min_limit_factor * VSize(diff_pos);
+
+                                       // 接地点計算
+                                       //std::cout << "  ground collision check: current pos = " << current_stat_.pos << std::endl;
+
+                                       auto coll_info = MV1CollCheck_Line(stage_->map_handle().handle(), -1,
+                                               moved_pos + VGet(0, y_max_limit, 0),
+                                               moved_pos + VGet(0, y_min_limit, 0));
+                                       if(coll_info.HitFlag && NearlyEqualRelative(coll_info.HitPosition.y, floor_coll.second.y, 0.001)){
+                                               // 接地可能
+                                               auto diff = coll_info.HitPosition - current_pos_;
+
+                                               // 角度が急になるほどdiffの長さが大きくなるから、補正する
+                                               if (VSize(diff) > 0)
+                                               {
+                                                       moved_pos = current_pos_ + VSize(diff_pos) * VNorm(diff);
+                                               }
+
+                                       }
+                                       if( floor_coll.first )
+                                       {
+                                               if( floor_coll.second.y < moved_pos.y )
+                                               {
+                                                       jump_flag_ = true;
+                                               }
+                                       }
+                                       //move_vec_y_ = 0;
+                               }else{
+                                       if( moved_pos.y <= current_pos_.y )
+                                       {
+                                               if( floor_coll.first )
+                                               {
+                                                       moved_pos = floor_coll.second;
+                                                       move_vec_y_ = 0;
+                                               }
+                                       }else{
+                                               // 上昇している
+
+                                               const auto player_top = VGet(0, model_height_ * stage_->map_scale(), 0);
+                                               auto coll_info = MV1CollCheck_Line(stage_->map_handle().handle(), -1,
+                                                       current_pos_ + player_top,
+                                                       moved_pos + player_top);
+                                               if (coll_info.HitFlag)
+                                               {
+                                                       // 天井に到達した
+                                                       // std::cout << "    current collided to ceiling" << std::endl;
+
+                                                       moved_pos = coll_info.HitPosition - player_top;
+                                                       move_vec_y_ = -(move_vec_y_ - (st_acc * stage_->map_scale() * timer_->DeltaSec() * (1.0f/flight_duration_ideal_) * (jump_height_ / 5.0f))) * 1.0; // 反射
+                                               }
+                                       }
+                               }
 
                 data_provider_.set_position(moved_pos);
                 data_provider_.set_theta(current_rot_.y);
 
                 MV1SetPosition(model_handle_, moved_pos);
-                MV1SetRotationXYZ(model_handle_, current_rot_);
+                               MV1SetRotationXYZ(model_handle_, current_rot_);
+
+                               if (current_speed_ * timer_->DeltaSec() > 0.205f)
+                               {
+                                       current_motion_ = motion.run_;
+                               }
+                               else
+                               {
+                                       current_motion_ = motion.walk_;
+                               }
+            }else{
+                current_motion_ = motion.stand_;
             }
 
+            if (current_motion_ != prev_motion_ && current_motion_ != -1)
+            {
+                motion_player_->Play(current_motion_, false, 200, -1, false);
+                prev_motion_ = current_motion_;
+                       }else if(additional_motion_.first)
+                       {
+                               bool connect_prev = true;
+                               motion_player_->Play(additional_motion_.second, connect_prev, 200, -1, false);
+                               additional_motion_.first = false;
+                       }
+
         } else {
             // 離れすぎている場合は瞬間移動
 
@@ -138,9 +267,15 @@ private:
     CharacterDataProvider& data_provider_;
     int model_handle_;
     VECTOR current_target_pos_;
-    VECTOR prev_target_pos_;
+    VECTOR prev_target_pos_;   // ひとつ前のターゲット
     VECTOR current_pos_;
     VECTOR current_rot_, prev_rot_;
+       float current_target_vec_y_;
+       float move_vec_y_;
+       bool jump_flag_;
+       float flight_duration_ideal_;
+       float model_height_;
+       float jump_height_;
     int current_motion_;
     int prev_motion_;
     float current_speed_;
index 46297f8..a2da95e 100644 (file)
@@ -9,7 +9,7 @@
 
 #define MMO_VERSION_MAJOR 0
 #define MMO_VERSION_MINOR 2
-#define MMO_VERSION_REVISION 2
+#define MMO_VERSION_REVISION 3
 
 #ifdef MMO_VERSION_BUILD
 #define MMO_VERSION_BUILD_TEXT " Build " MMO_VERSION_TOSTRING(MMO_VERSION_BUILD)