OSDN Git Service

衝突判定を修正
authorangeart <angeart@git.sourceforge.jp>
Mon, 3 Sep 2012 15:13:45 +0000 (00:13 +0900)
committerangeart <angeart@git.sourceforge.jp>
Mon, 3 Sep 2012 15:13:45 +0000 (00:13 +0900)
PlayMotionの追加

client/3d/FieldPlayer.cpp
client/3d/FieldPlayer.hpp
client/3d/PlayerCharacter.cpp
client/3d/PlayerCharacter.hpp
client/3d/Stage.cpp
client/3d/Stage.hpp
client/3d/dx_vector.hpp
client/3d/model.cpp

index 149d0c0..b14d547 100644 (file)
@@ -35,6 +35,7 @@ FieldPlayer::FieldPlayer(CharacterDataProvider& data_provider, const StagePtr& s
                jump_height_(1.0f),
                prev_mouse_pos_y_(0.0f),
         motion_player_(),
+               additional_motion_(false,-1),
         timer_(timer),
         model_handle_(),
         stage_(stage),
@@ -131,7 +132,11 @@ void FieldPlayer::Update()
         }
 
         motion_player_->Play(current_stat_.motion, connect_prev, 200, -1, false);
-    }
+       }else if(additional_motion_.first)
+       {
+               bool connect_prev = true;
+               motion_player_->Play(additional_motion_.second, connect_prev, 200, -1, false);
+       }
     // モーション再生時刻更新
     motion_player_->Next(timer_->Delta());
 
@@ -176,20 +181,24 @@ void FieldPlayer::Move()
         }
     }
 
-    // 50mの深さまで床検出
-    auto floor_exists = stage_->FloorExists(current_stat_.pos, model_height_, 50);
 
     // 移動方向に障害物があるか、または床がない場合は移動不可能
-    bool front_collides = stage_->FrontCollides(
-            0.2, current_stat_.pos, prev_stat_.pos, 0.4 * stage_->map_scale(), (model_height_ - 0.1) * stage_->map_scale(), 128) ||
-        !floor_exists.first;
+       auto front_collides = stage_->FrontCollides(
+            0.4, current_stat_.pos, prev_stat_.pos,1.0 * stage_->map_scale(), (model_height_ - 0.1) * stage_->map_scale() ,128);
 
-    if (front_collides)
-    {
-        current_stat_.pos.x = prev_stat_.pos.x;
-        current_stat_.pos.z = prev_stat_.pos.z;
+       if(front_collides.first)
+       {
+               current_stat_.pos = front_collides.second;
         current_stat_.vel.x = current_stat_.vel.z = 0;
-    }
+       }
+    // 50mの深さまで床検出
+    auto floor_exists = stage_->FloorExists(current_stat_.pos, model_height_, 50);
+       if(!floor_exists.first)
+       {
+               current_stat_.pos.x = front_collides.second.x;
+        current_stat_.pos.z = front_collides.second.z;
+        current_stat_.vel.x = current_stat_.vel.z = 0;
+       }
 
     // 足が地面にめり込んでいるか
     auto foot_floor_exists = stage_->FloorExists(current_stat_.pos, model_height_, 0);
@@ -206,74 +215,69 @@ void FieldPlayer::Move()
             // 前回接地していた
             // std::cout << "  previous on the ground" << std::endl;
 
-            if (!front_collides)
-            {
-
-                // 登ったり下ったりできる段差の大きさの制限を求める
-                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 * pos_diff_length;
-                const float y_min_limit = y_min_limit_factor * pos_diff_length;
-
-                // 接地点計算
-                //std::cout << "  ground collision check: current pos = " << current_stat_.pos << std::endl;
-
-                auto coll_info = MV1CollCheck_Line(stage_->map_handle().handle(), -1,
-                        current_stat_.pos + VGet(0, y_max_limit, 0),
-                        current_stat_.pos + VGet(0, y_min_limit, 0));
-                if (coll_info.HitFlag && NearlyEqualRelative(coll_info.HitPosition.y, floor_exists.second.y, 0.001))
-                {
-                    // 今回も接地できる
-                    //std::cout << "    current on the ground" << std::endl;
-                    auto diff = coll_info.HitPosition - prev_stat_.pos;
-
-                    // 角度が急になるほどdiffの長さが大きくなるから、補正する
-                    if (VSize(diff) > 0)
-                    {
-                        current_stat_.pos = prev_stat_.pos + pos_diff_length * VNorm(diff);
-                    }
-                }
-                else if (floor_exists.first)
-                {
-                    if (floor_exists.second.y < current_stat_.pos.y)
-                    {
-                        // 床はあるし、自分より低い位置なので落ちる
-                        current_stat_.acc.y = -9.8 * stage_->map_scale();
-                    }
-                    else if (floor_exists.second.y < current_stat_.pos.y + 0.6 * stage_->map_scale())
-                    {
-                        // 床があり、平らなので登る
-                        auto delta = prev_stat_.pos - current_stat_.pos;
-                        delta.y = floor_exists.second.y - current_stat_.pos.y;
-                        float xz_size = VSize(VGet(delta.x, 0, delta.z));
-
-                        if (xz_size > 0)
-                        {
-                            // 床の傾斜
-                            double angle = delta.y / xz_size;
-                            if (angle < 1.0)
-                            {
-                                current_stat_.pos.y = floor_exists.second.y;
-                                // current_stat_.pos = prev_stat_.pos + (current_stat_.pos - prev_stat_.pos) * (1.0 - angle);
-                            } else
-                            {
-                                current_stat_.pos = prev_stat_.pos;
-                            }
-                        }
-                    }
-                    else
-                    {
-                        // 床があるが、高すぎるので移動不可能
-                        current_stat_.pos = prev_stat_.pos;
-                    }
-                }
-                else
-                {
-                    // 接地できない(移動可能範囲に地面が見つからない)
-                    current_stat_.pos = prev_stat_.pos;
-                }
-
-            }
+                       // 登ったり下ったりできる段差の大きさの制限を求める
+                       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 * pos_diff_length;
+                       const float y_min_limit = y_min_limit_factor * pos_diff_length;
+
+                       // 接地点計算
+                       //std::cout << "  ground collision check: current pos = " << current_stat_.pos << std::endl;
+
+                       auto coll_info = MV1CollCheck_Line(stage_->map_handle().handle(), -1,
+                               current_stat_.pos + VGet(0, y_max_limit, 0),
+                               current_stat_.pos + VGet(0, y_min_limit, 0));
+                       if (coll_info.HitFlag && NearlyEqualRelative(coll_info.HitPosition.y, floor_exists.second.y, 0.001))
+                       {
+                               // 今回も接地できる
+                               //std::cout << "    current on the ground" << std::endl;
+                               auto diff = coll_info.HitPosition - prev_stat_.pos;
+
+                               // 角度が急になるほどdiffの長さが大きくなるから、補正する
+                               if (VSize(diff) > 0)
+                               {
+                                       current_stat_.pos = prev_stat_.pos + pos_diff_length * VNorm(diff);
+                               }
+                       }
+                       else if (floor_exists.first)
+                       {
+                               if (floor_exists.second.y < current_stat_.pos.y)
+                               {
+                                       // 床はあるし、自分より低い位置なので落ちる
+                                       current_stat_.acc.y = -9.8 * stage_->map_scale();
+                               }
+                               else if (floor_exists.second.y < current_stat_.pos.y + 0.6 * stage_->map_scale())
+                               {
+                                       // 床があり、平らなので登る
+                                       auto delta = prev_stat_.pos - current_stat_.pos;
+                                       delta.y = floor_exists.second.y - current_stat_.pos.y;
+                                       float xz_size = VSize(VGet(delta.x, 0, delta.z));
+
+                                       if (xz_size > 0)
+                                       {
+                                               // 床の傾斜
+                                               double angle = delta.y / xz_size;
+                                               if (angle < 1.0)
+                                               {
+                                                       current_stat_.pos.y = floor_exists.second.y;
+                                                       // current_stat_.pos = prev_stat_.pos + (current_stat_.pos - prev_stat_.pos) * (1.0 - angle);
+                                               } else
+                                               {
+                                                       current_stat_.pos = prev_stat_.pos;
+                                               }
+                                       }
+                               }
+                               else
+                               {
+                                       // 床があるが、高すぎるので移動不可能
+                                       current_stat_.pos = prev_stat_.pos;
+                               }
+                       }
+                       else
+                       {
+                               // 接地できない(移動可能範囲に地面が見つからない)
+                               current_stat_.pos = prev_stat_.pos;
+                       }
         }
         else if (prev_stat_.acc.y < 0)
         {
@@ -389,6 +393,7 @@ void FieldPlayer::InputFromUser()
         current_stat_.vel = VGet(sin(roty), 0, cos(roty)) * (-move_dir * move_speed * stage_->map_scale());
         current_stat_.motion =
             current_stat_.is_walking ? motion.walk_ : motion.run_;
+               additional_motion_.first = false;
     }
     else if (current_stat_.acc.y != 0)
     {
@@ -453,6 +458,12 @@ void FieldPlayer::InputFromUser()
     }
 }
 
+void FieldPlayer::PlayMotion(const tstring& name)
+{
+       additional_motion_.second = MV1GetAnimIndex(model_handle_.handle(),name.c_str());
+       additional_motion_.first = true;
+}
+
 const ModelHandle& FieldPlayer::model_handle() const
 {
     return model_handle_;
index a788e52..5974315 100644 (file)
Binary files a/client/3d/FieldPlayer.hpp and b/client/3d/FieldPlayer.hpp differ
index 85df997..330adf0 100644 (file)
@@ -22,6 +22,7 @@ public:
           prev_motion_(-1),
           current_speed_(0),
           motion_player_(),
+                 additional_motion_(false, -1),
           timer_(timer),
           stage_(stage)
     {
@@ -85,7 +86,11 @@ public:
             {
                 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);
+                       }
 
             // TODO: Y下方向については重力加速度
             if (distance_to_target > 2.0){
@@ -122,6 +127,12 @@ public:
         motion_player_->Next(timer_->Delta());
     }
 
+       void Impl::PlayMotion(const tstring& name)
+       {
+               additional_motion_.second = MV1GetAnimIndex(model_handle_,name.c_str());
+               additional_motion_.first = true;
+       }
+
 private:
     CharacterDataProvider& data_provider_;
     int model_handle_;
@@ -133,6 +144,7 @@ private:
     int prev_motion_;
     float current_speed_;
     std::unique_ptr<MotionPlayer> motion_player_;
+       std::pair<bool, int> additional_motion_;
     TimerPtr timer_;
     StagePtr stage_;
 
@@ -157,3 +169,8 @@ void PlayerCharacter::Update()
 {
     impl_->Update();
 }
+
+void PlayerCharacter::PlayMotion(const tstring& name)
+{
+       impl_->PlayMotion(name);
+}
index cc74543..47a7318 100644 (file)
@@ -17,6 +17,7 @@ public:
     void Update();
 
     void SetModel();
+       void PlayMotion(const tstring& name);
 
 private:
     class Impl;
index 8ce32e9..a3fabaa 100644 (file)
@@ -104,30 +104,68 @@ bool Stage::IsFlatFloor(const VECTOR& foot_pos, const VECTOR& direction) const
 }
 
 // 移動方向に障害物があるかどうか(当たり判定)
-bool Stage::FrontCollides(float collision_length, const VECTOR& current_pos, const VECTOR& prev_pos,
+std::pair<bool,VECTOR> Stage::FrontCollides(float collision_length, const VECTOR& current_pos, const VECTOR& prev_pos,
         float height_begin, float height_end, size_t num_division) const
 {
-    const auto height_diff = (height_end - height_begin) / num_division;
-
-    auto direction = current_pos - prev_pos;
-    direction.y = 0; // 水平な進行方向を求める
-    const auto collision_vector =
-        //VNorm(direction) * (collision_length * map_scale_); // 体中心から15cm前方までの線分で当たり判定
-        VAdjustLength(direction, collision_length * map_scale_);
-
-    for (size_t i = 0; i <= num_division; ++i)
-    {
-        auto collision_vector_pos = prev_pos + VGet(0, height_begin + height_diff * i, 0);
-        auto coll_info = MV1CollCheck_Line(map_handle_.handle(), -1,
-                collision_vector_pos,
-                collision_vector_pos + collision_vector);
-        if (coll_info.HitFlag)
-        {
-            return true;
-        }
-    }
-
-    return false;
+       auto direction = current_pos - prev_pos;
+       direction.y = 0; // 水平な進行方向を求める
+       const auto collision_vector =
+               //VNorm(direction) * (collision_length * map_scale_); // 体中心から15cm前方までの線分で当たり判定
+               VAdjustLength(direction, collision_length * map_scale_);
+
+       auto tmp_pos = prev_pos + VGet(0,height_begin,0);
+       auto coll_info = MV1CollCheck_Capsule(map_handle_.handle(), -1,
+               tmp_pos + collision_vector,
+               prev_pos + collision_vector + VGet(0,height_end,0),VSize(collision_vector));
+
+       auto NowPos = prev_pos;
+
+       if (coll_info.HitNum)
+       {
+               int i = 0;
+               for(i = 0;i < coll_info.HitNum; ++i)
+               {
+                       if( coll_info.Dim[i].Normal.y > 0.000002f && coll_info.Dim[i].Normal.y < -0.000002f && 
+                               coll_info.Dim[i].Position[0].y < tmp_pos.y &&
+                               coll_info.Dim[i].Position[1].y < tmp_pos.y &&
+                               coll_info.Dim[i].Position[2].y < tmp_pos.y )continue;
+                       auto SlideVec = VCross( coll_info.Dim[i].Normal, VCross( current_pos - prev_pos ,coll_info.Dim[i].Normal));
+                       NowPos += SlideVec;
+
+                       const auto slide_collision_vector =
+                               //VNorm(direction) * (collision_length * map_scale_); // 体中心から15cm前方までの線分で当たり判定
+                               VAdjustLength(NowPos - prev_pos, collision_length * map_scale_);
+                       auto flag = false;
+                       auto slide_coll_info = MV1CollCheck_Capsule(map_handle_.handle(), -1,
+                               NowPos + VGet(0,height_begin,0),
+                               NowPos + VGet(0,height_end,0),VSize(collision_vector));
+                       if(slide_coll_info.HitNum)
+                       {
+                               for(int j = 0; j < slide_coll_info.HitNum; ++j)
+                               {
+                                       auto angle = (acos(VDot(slide_coll_info.Dim[j].Normal,current_pos - prev_pos) / (VSize(slide_coll_info.Dim[j].Normal) * VSize(current_pos - prev_pos)))*180.0f)/PHI_F;
+                                       if(angle < 90.0f || angle > 270.0f)
+                                       {
+                                               NowPos += VScale(slide_coll_info.Dim[j].Normal, 0.1f * map_scale_);
+                                               flag = true;
+                                               break;
+                                       }else{
+                                               continue;
+                                       }
+                               }
+                               if(!flag)NowPos = prev_pos;
+                       }
+                       // 当たり判定情報の後始末
+                       MV1CollResultPolyDimTerminate(slide_coll_info);
+                       break;
+               }
+               // 当たり判定情報の後始末
+               MV1CollResultPolyDimTerminate(coll_info);
+               return std::make_pair(true,NowPos);;
+       }
+       // 当たり判定情報の後始末
+       MV1CollResultPolyDimTerminate(coll_info);
+       return std::make_pair(false,prev_pos);
 }
 
 bool Stage::IsVisiblePoint(const VECTOR& point) const
index 69561a3..a13d292 100644 (file)
@@ -21,8 +21,8 @@ class Stage {
 
         std::pair<bool, VECTOR> FloorExists(const VECTOR& foot_pos, float model_height, float collision_depth_limit) const;
         bool IsFlatFloor(const VECTOR& foot_pos, const VECTOR& direction) const;
-        bool FrontCollides(float collision_length, const VECTOR& current_pos, const VECTOR& prev_pos,
-                float height_begin, float height_end, size_t num_division) const;
+        std::pair<bool,VECTOR> FrontCollides(float collision_length, const VECTOR& current_pos, const VECTOR& prev_pos,
+        float height_begin, float height_end, size_t num_division) const;
 
         bool IsVisiblePoint(const VECTOR& point) const;
 
index 68a470a..f46b6ba 100644 (file)
@@ -3,6 +3,8 @@
 
 #include <ostream>
 
+#define TORADIAN(DEGREE)       ((DEGREE*PHI_F)/180.0f)
+
 inline VECTOR operator +(const VECTOR& lhs, const VECTOR& rhs)
 {
     return VAdd(lhs, rhs);
index 6c3ae09..a59c660 100644 (file)
@@ -14,8 +14,6 @@
 #include "Stage.hpp"
 #include "../../common/Logger.hpp"
 
-#define TORADIAN(DEGREE)       ((DEGREE*PHI_F)/180.0f)
-
 int KeyChecker::Check()
 {
     std::array<char, 256> key_state;