public void LocalPlayerWalkToDestination(Vector3 targetPos, Task relateTask = null) { Actor player = Game.GetInstance().GetLocalPlayer(); if (player == null) { return; } targetPos.y = RoleHelp.GetHeightInScene(player.ActorId, targetPos.x, targetPos.z); targetPos = InstanceHelper.ClampInWalkableRange(targetPos, 10); // 判断是否可到达 XNavMeshPath walkMeshPath = new XNavMeshPath(); XNavMesh.CalculatePath(player.transform.position, targetPos, xc.Dungeon.LevelManager.GetInstance().AreaExclude, walkMeshPath); if (walkMeshPath.status != XNavMeshPathStatus.PathComplete) { // 如果通过任务导航寻路,且在新手副本的不可到达区域,则直接飞过去,以免因为配置错误而导致卡死 if (relateTask != null && SceneHelp.Instance.CurSceneID == GameConstHelper.GetUint("GAME_BORN_DUNGEON")) { GameDebug.LogWarning(DBConstText.GetText("MAP_POS_CAN_NOT_REACH") + ",该场景是新手场景,直接瞬移过去"); player.MoveCtrl.SendFly(targetPos); player.SetPosition(targetPos); } else { UINotice.Instance.ShowMessage(DBConstText.GetText("MAP_POS_CAN_NOT_REACH")); } return; } InstanceManager.Instance.IsAutoFighting = false; mPathWalker.WalkTo(targetPos); //player.MoveCtrl.TryWalkTo(targetPos); /* * uint instanceType = InstanceManager.Instance.InstanceType; * * if (instanceType == GameConst.WAR_TYPE_WILD || instanceType == GameConst.WAR_TYPE_HOLE || instanceType == GameConst.WAR_SUBTYPE_WILD_PUB || instanceType == GameConst.WAR_TYPE_MULTI) * { * if(mPathWalker == null) * { * return; * } * * mPathWalker.WalkTo(targetPos); * } * else * { * player.MoveCtrl.TryWalkTo(targetPos); * }*/ TaskNavigationActive(true); IsNavigating = true; }
/// <summary> /// 响应点击地面的消息 /// </summary> /// <param name="ent"></param> void OnClickCollision(CEventBaseArgs ent) { Actor local_player = Game.Instance.GetLocalPlayer(); if (local_player == null) { return; } if (GameInput.Instance.GetEnableInput() == false || UIInputEvent.TouchedUI()) /* || InstanceManager.Instance.IsAutoFighting == true*/ { return; } Vector3 hitPos = (Vector3)ent.arg; XNavMeshHit nesrestHit; if (XNavMesh.SamplePosition(hitPos, out nesrestHit, 5.0f, LevelManager.GetInstance().AreaExclude)) { hitPos = nesrestHit.position; } StopLocalPlayerWalkCoroutine(); mLocalPlayerWalkCoroutine = SafeCoroutine.CoroutineManager.StartCoroutine(LocalPlayerWalkCoroutine(hitPos)); if (m_ArrowEffectTemp == null) { MainGame.HeartBehavior.StartCoroutine(LoadEffect(m_ClickEffectPath, hitPos)); } //EffectManager.GetInstance().GetEffectEmitter(effect_path).CreateInstance(x => OnEffectResLoad(x, )); else { OnEffectResLoad(m_ArrowEffectTemp, hitPos); } }
/// <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> void CalcMovePath() { if (mWalkMode == EWalkMode.EWM_Dst)// 只有走到目标点的行走方式才需要寻路 { mDestList.Clear(); walkMeshPath.ClearCorners(); XNavMesh.CalculatePath(mOwnerTrans.position, mDst, LevelManager.GetInstance().AreaExclude, walkMeshPath); if (walkMeshPath.status == XNavMeshPathStatus.PathComplete && walkMeshPath.corners.GetLength(0) >= 2) { // 调整路径的拐弯点 Vector3[] adjuestCorners = walkMeshPath.corners; #if UNITY_EDITOR if (mOwner is LocalPlayer) { for (int j = 1; j < adjuestCorners.Length; ++j) { Debug.DrawLine(adjuestCorners[j - 1], adjuestCorners[j], Color.red, 1.0f * adjuestCorners.Length); } } #endif int len = adjuestCorners.Length; if (len > 3) { adjuestCorners = new Vector3[len]; adjuestCorners[0] = walkMeshPath.corners[0]; for (int i = 1; i < len; ++i) { if (i + 1 >= len) { adjuestCorners[i] = walkMeshPath.corners[i]; break; } Vector3 pre_vec = walkMeshPath.corners[i - 1] - walkMeshPath.corners[i]; pre_vec.y = 0; pre_vec.Normalize(); Vector3 next_vec = walkMeshPath.corners[i + 1] - walkMeshPath.corners[i]; next_vec.y = 0; next_vec.Normalize(); if (pre_vec.sqrMagnitude < minCornerDis || next_vec.sqrMagnitude < minCornerDis) { adjuestCorners[i] = walkMeshPath.corners[i]; continue; } // 先计算调整后的位置(增加MoveImpl.Radius) Vector3 middle_vec = pre_vec + next_vec; var adjuestCorner = walkMeshPath.corners[i] - middle_vec * (0.8f + MoveImpl.Radius * 2); // 在该位置点附近进行采样 XNavMeshHit nearestHit; if (XNavMesh.SamplePosition(adjuestCorner, out nearestHit, 5f, LevelManager.GetInstance().AreaExclude)) { // 如果调整后的位置可行走,则使用新位置,否则使用原始位置 var dis = nearestHit.position - adjuestCorner; if (dis.sqrMagnitude < 0.01f) { adjuestCorners[i] = walkMeshPath.corners[i] - middle_vec * 0.8f; } else { adjuestCorners[i] = walkMeshPath.corners[i]; } } else { adjuestCorners[i] = walkMeshPath.corners[i]; } } } mDst = adjuestCorners[1]; for (int j = 1; j < adjuestCorners.Length; ++j) { mDestList.Add(adjuestCorners[j]); } if (mOwner.IsLocalPlayer) { ClientEventMgr.GetInstance().FireEvent((int)ClientEvent.CE_ACTOR_PATH_POINTS_CHANGED, null); } #if UNITY_EDITOR if (mOwner is LocalPlayer) { for (int j = 1; j < adjuestCorners.Length; ++j) { Debug.DrawLine(adjuestCorners[j - 1], adjuestCorners[j], Color.green, 1f * adjuestCorners.Length); } } #endif } else { // 如果寻路不成功,则设置目标点为初始点 mDst = mOwnerTrans.position; } mWalkToPoint = false; } }
/// <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); }