Esempio n. 1
0
        /// <summary>
        /// 移动固定的位置
        /// </summary>
        /// <param name="offset">移动的偏移数值</param>
        /// <param name="on_ground">移动时是否贴近地面</param>
        /// <param name="slider">移动时是否沿着边界滑动</param>
        public void Move(Vector3 offset, bool on_ground, bool slider = true)
        {
//             MoveAgent(offset, on_ground, slider);
//             return;

            if (offset == Vector3.zero || mOwner.DisableMoveState)
            {
                return;
            }

            move_data.pos = new PkgNwarPos();

            // 减少Trans.position 这样的调用,会显著影响性能
            Vector3 ownerPos = mOwnerTrans.position;

            // 当移动不贴近地面(浮空等)时,需要先计算贴近地面的高度,不然NavMesh的碰撞检测可能检测不到
            if (on_ground == false)
            {
                float height = RoleHelp.GetHeightInScene(mOwner.ActorId, ownerPos.x, ownerPos.z);
                ownerPos.y = height;
            }

            Vector3 origin = ownerPos;        // 碰撞检测的起点
            Vector3 newPos = origin + offset; // 移动后的新位置

            Vector3 move     = offset;        // 偏移量
            float   offset_y = move.y;        // 记录原有的高度偏移

            move.y = 0;                       // 碰撞检测时将高度偏移设置为0

            bool touchEdge = false;           // 已经触碰到边界

            bool is_localplayer = mOwner.IsLocalPlayer;

            bool collide_check = true;
            bool is_monster    = mOwner.IsMonster();//怪物不进行碰撞检测

            if (is_monster)
            {
                collide_check = false;
            }
            else
            {
                collide_check = true;
            }

            if (collide_check)
            {
                Vector3     final_move = move;
                XNavMeshHit hit;
                if (XNavMesh.Raycast(origin, origin + move * (1.0f + Radius / move.magnitude), out hit, LevelManager.GetInstance().AreaExclude))
                {
                    touchEdge = true;

                    if (slider)// 需要沿着边界滑动时
                    {
                        float sameDir = Vector3.Dot(hit.normal, final_move);
                        if (sameDir > 0)// 法线与移动方向相同,说明角色在边界外
                        {
                            final_move.y = offset_y;
                            newPos       = origin + final_move;
                        }
                        else
                        {
                            if (hit.normal == Vector3.zero)// NavMesh获得的法线数值可能为0
                            {
                                Debug.DrawLine(origin, origin + final_move, Color.yellow, 5.0f);

                                final_move.y = offset_y;
                                newPos       = origin + final_move;
                                //final_move = Vector3.zero;
                                //newPos = origin;
                            }
                            else
                            {
                                // 碰到边界进行滑动
                                Vector3 tanget = Vector3.Cross(Vector3.up, hit.normal);
                                final_move = tanget * Vector3.Dot(tanget, final_move);
                                float sMoveLen = final_move.magnitude;
                                if (sMoveLen < DBActor.MinDisToGround)// 移动方向垂直于法线
                                {
                                    final_move = Vector3.zero;
                                    newPos     = origin;
                                }
                                else
                                {
                                    // 沿着切线方向再次做检测,以免滑动的时候移动到另一个边界外
                                    if (XNavMesh.Raycast(origin, origin + final_move * (1.0f + Radius / sMoveLen), out hit, LevelManager.GetInstance().AreaExclude))
                                    {
                                        final_move = Vector3.zero;
                                        newPos     = origin;
                                    }
                                    else
                                    {
                                        final_move.y = offset_y;
                                        newPos       = origin + final_move;
                                    }
                                }
                            }
                        }
                    }
                    else// 不滑动,则直接移动到碰撞点
                    {
                        Vector3 radius_pos = PhysicsHelp.BoundaryHitPos(origin, hit.position);
                        newPos.x = radius_pos.x;
                        newPos.z = radius_pos.z;
                    }
                }
            }

            float terrain_height = RoleHelp.GetHeightInScene(mOwner.ActorId, newPos.x, newPos.z);

            if (newPos.y < terrain_height + DBActor.MinDisToGround)// 如果当前位置已经贴近地面,则设置m_IsGround为true
            {
                m_IsGround = true;
                newPos.y   = terrain_height;
            }
            else
            {
                if (on_ground || touchEdge) // 如果角色已经触碰到边界,则让其掉到地上
                {
                    newPos.y   = terrain_height;
                    m_IsGround = true;
                }
                else
                {
                    m_IsGround = false;
                }
            }

            // 在多人副本、野外地图中,本地玩家碰到障碍物的时候需要通知服务端
            if (is_localplayer && slider)
            {
                if (touchEdge)
                {
                    m_IsTouchEdge = true;

                    Vector3 totalMove = newPos - origin;
                    totalMove.y = 0;
                    Vector3 moveDir = totalMove.normalized;

                    move_data.id     = mOwner.UID.obj_idx;
                    move_data.pos.px = (int)(origin.x * 100.0f);
                    move_data.pos.py = (int)(origin.z * 100.0f);
                    move_data.dir    = Maths.Util.VectorToAngle(moveDir);

                    float   totalMoveLen = totalMove.magnitude;
                    Vector3 xz_offset    = offset;
                    xz_offset.y = 0;
                    float ortMoveLen = xz_offset.magnitude;
                    if (totalMoveLen > 0 && ortMoveLen > 0)
                    {
                        move_data.speed = (uint)(mOwner.MoveSpeed * (totalMoveLen / ortMoveLen) * 100);
                    }
                    else
                    {
                        move_data.speed = 0;
                    }

                    // 数据发生变化时才发送滑动协议
                    if (!mSliderData.Equal(move_data))
                    {
                        mSliderData.Assign(move_data);

                        slider_data.slide = move_data;
                        NetClient.GetCrossClient().SendData <C2SNwarSlide>(NetMsg.MSG_NWAR_SLIDE, slider_data);
                    }
                }
                // 当滑动结束时,需要同步一次方向和位置
                else if (m_IsTouchEdge)
                {
                    m_IsTouchEdge = false;

                    Vector3 totalMove = newPos - origin;
                    totalMove.y = 0;
                    Vector3 moveDir = totalMove.normalized;

                    move_data.id     = mOwner.UID.obj_idx;
                    move_data.pos.px = (int)(origin.x * 100.0f);
                    move_data.pos.py = (int)(origin.z * 100.0f);
                    move_data.dir    = Maths.Util.VectorToAngle(moveDir);

                    float   totalMoveLen = totalMove.magnitude;
                    Vector3 xz_offset    = offset;
                    xz_offset.y = 0;
                    float ortMoveLen = xz_offset.magnitude;
                    if (totalMoveLen > 0 && ortMoveLen > 0)
                    {
                        move_data.speed = (uint)(mOwner.MoveSpeed * (totalMoveLen / ortMoveLen) * 100);
                    }
                    else
                    {
                        move_data.speed = 0;
                    }

                    mSliderData.Assign(move_data);
                    slider_data.slide = move_data;
                    NetClient.GetCrossClient().SendData <C2SNwarSlide>(NetMsg.MSG_NWAR_SLIDE, slider_data);
                }
            }

            mOwnerTrans.position = newPos;
            OnMove();
        }
        /// <summary>
        /// 开始
        /// </summary>
        public override bool Begin(SkillAction action)
        {
            base.Begin(action);

            m_DynamicStageTime = mSkillAction.ActionData.CastingStageTime;
            m_RealTargetPos    = Vector3.zero;

            // 判定是否要进入持续施法阶段
            if (mSkillAction.ActionData.SkillInfo.CastingTime <= 0.0f)
            {
                return(false);
            }

            Actor src_actor = mSkillAction.SkillParent.SrcActor;

            // 技能的隐身
            if (mSkillAction.ActionData.SkillInfo.Invisible)
            {
                if (src_actor.mVisibleCtrl.VisibleMode == EVisibleMode.Visible)
                {
                    mSkillAction.HideActor = true;
                    src_actor.mVisibleCtrl.SetActorVisible(false, true, false, VisiblePriority.SKILL);
                }
            }

            // 播放动画
            string casting_ani = mSkillAction.ActionData.CastingAnimation;

            if (casting_ani != string.Empty && casting_ani != mSkillAction.ActionData.SkillAnimation)
            {
                src_actor.Play(mSkillAction.ActionData.CastingAnimation);
            }
            src_actor.SetAnimationSpeed(mSkillAction.SkillParent.SpeedScale);

            // 施法阶段的位移
            MoveCtrl move_ctrl = src_actor.MoveCtrl;

            mSkillAction.SkillParent.MovingSpeed = mSkillAction.ActionData.SkillInfo.CastingSpeed;
            src_actor.MoveSpeed = mSkillAction.ActionData.SkillInfo.CastingSpeed;
            mSkillAction.BeginMove();

            uint target_id = mSkillAction.SkillParent.TargetID;     // 目标玩家的id

            if (target_id == 0)                                     // 无目标玩家
            {
                move_ctrl.MoveDirInAttacking(src_actor.ForwardDir); // 沿当前方向移动
                Vector3 src_pos = src_actor.Trans.position;
                m_RealTargetPos = src_pos + mSkillAction.SkillParent.AttackDir * mSkillAction.ActionData.SkillInfo.CastingSpeed * mSkillAction.ActionData.CastingStageTime;
                XNavMeshHit hit;
                if (XNavMesh.Raycast(src_pos, m_RealTargetPos, out hit, xc.Dungeon.LevelManager.GetInstance().AreaExclude))
                {
                    m_RealTargetPos = PhysicsHelp.BoundaryHitPos(src_pos, hit.position);
                }
            }
            else// 有目标玩家
            {
                Vector3 src_pos      = src_actor.Trans.position;
                Actor   target_actor = ActorManager.Instance.GetPlayer(target_id);// 获取目标玩家

                Vector3 target_pos = Vector3.zero;
                if (target_actor != null)
                {
                    target_pos = target_actor.Trans.position;
                    Vector3 vec = target_pos - src_pos;
                    float   len = vec.magnitude;

                    if (len > mSkillAction.RushTargetRange)
                    {
                        float real_len = len - mSkillAction.RushTargetRange;
                        target_pos = src_pos + vec * real_len / len;
                        XNavMeshHit hit;
                        if (XNavMesh.Raycast(src_pos, target_pos, out hit, xc.Dungeon.LevelManager.GetInstance().AreaExclude))
                        {
                            target_pos = PhysicsHelp.BoundaryHitPos(src_pos, hit.position);
                        }

                        if (mSkillAction.ActionData.SkillInfo.CastingSpeed != 0)
                        {
                            m_RealTargetPos = target_pos;
                            float calc_castingTime = real_len / mSkillAction.ActionData.SkillInfo.CastingSpeed;// 根据距离和速度计算施法阶段的时间
                            float fix_castingTime  = mSkillAction.ActionData.CastingStageTime;
                            if (calc_castingTime < fix_castingTime)
                            {
                                m_DynamicStageTime = calc_castingTime;
                            }
                        }
                    }
                    else
                    {
                        target_pos         = src_pos;
                        m_DynamicStageTime = 0;
                    }

                    move_ctrl.MoveDirInAttacking(vec);// 冲到目标点的方向
                }
                else
                {
                    target_pos = src_pos + mSkillAction.SkillParent.AttackDir * mSkillAction.ActionData.SkillInfo.CastingSpeed * mSkillAction.ActionData.CastingStageTime;
                    XNavMeshHit hit;
                    if (XNavMesh.Raycast(src_pos, target_pos, out hit, xc.Dungeon.LevelManager.GetInstance().AreaExclude))
                    {
                        target_pos      = PhysicsHelp.BoundaryHitPos(src_pos, hit.position);
                        m_RealTargetPos = target_pos;
                    }
                }

                if (src_actor.AttackCtrl.mIsSendMsg)
                {
                    C2SNwarChargeStop charge_stop = new C2SNwarChargeStop();
                    charge_stop.skill_id = mSkillAction.ActionData.SkillInfo.Id;
                    PkgNwarMove move = new PkgNwarMove();
                    move.id = src_actor.UID.obj_idx;
                    PkgNwarPos pos = new PkgNwarPos();
                    pos.px           = (int)(target_pos.x * 100);
                    pos.py           = (int)(target_pos.z * 100);
                    move.pos         = pos;
                    move.speed       = 0;
                    move.time        = 0;
                    charge_stop.move = move;

                    NetClient.GetCrossClient().SendData <C2SNwarChargeStop>(NetMsg.MSG_NWAR_CHARGE_STOP, charge_stop);
                }
            }


            return(true);
        }