--[[@------------------------------------------------------------------ 说明: 移动源操作包, 用于产生控制角色移动到场景指定位置的操作包 作者: deadline ----------------------------------------------------------------------]] SourceOperateMove = SourceOperateMove or BaseClass(SourceOperate) local SourceOperateMove = SourceOperateMove SourceOperateMove.MoveType = { MoveToTarget = 1, MoveToDirection = 2, InitedPath = 3, } SourceOperateMove.operate_move_id = 0 --沿着两个点的方向寻找离起点最近的一个非障碍点 start_pos,end_pos为真实像素点 function SourceOperateMove.FindNearestPos(start_pos,end_pos,jump_state) local start_logic_pos = co.TableXY(start_pos.x / SceneObj.LogicRealRatio.x, start_pos.y / SceneObj.LogicRealRatio.y) local end_logic_pos = co.TableXY(end_pos.x / SceneObj.LogicRealRatio.x, end_pos.y / SceneObj.LogicRealRatio.y) local tem_dir = co.TableXY(end_logic_pos.x - start_logic_pos.x,end_logic_pos.y - start_logic_pos.y) local dist = co.NormaliseXYTable(tem_dir) local r = Scene.Instance:DetectLastUnblockPoint(Vector2(start_logic_pos.x, start_logic_pos.y), Vector2(tem_dir.x, tem_dir.y), dist, jump_state) --dist是逻辑坐标系的 if r.z == 1 then return r.x * SceneObj.LogicRealRatio.x, r.y * SceneObj.LogicRealRatio.y end return end_pos.x, end_pos.y end --沿着两个点的方向寻找离起点最远的一个非障碍点 start_pos,end_pos为真实像素点 function SourceOperateMove.FindFastestPos(start_pos,end_pos, user_len) local len = user_len or 20 local tem_dir = nil local dist = nil tem_dir = co.TableXY(start_pos.x - end_pos.x,start_pos.y - end_pos.y) dist = co.NormaliseXYTable(tem_dir) if not user_len then len = math.ceil(dist / 60) end local x, y = 0, 0 for i = 1,len do x = end_pos.x + tem_dir.x * i / len * dist y = end_pos.y + tem_dir.y * i / len * dist if not SceneManager:getInstance():IsBlockXY(math.floor(x / SceneObj.LogicRealRatio.x), math.floor(y / SceneObj.LogicRealRatio.y)) then local result = true if i >= (len - 1) then result = false else --退后一格 --x = x + tem_dir.x * SceneObj.LogicRealRatio.x-- * 0.5 --y = y + tem_dir.y * SceneObj.LogicRealRatio.y-- * 0.5 end return x, y, result end end return start_pos.x, start_pos.y, false end function SourceOperateMove.FindNoBlockPos(now_pos) now_pos = co.TableXY(math.floor(now_pos.x), math.floor(now_pos.y)) local width = math.floor(Scene.Instance:GetSceneSize().x / SceneObj.LogicRealRatio.x) local height = math.floor(Scene.Instance:GetSceneSize().y / SceneObj.LogicRealRatio.y) if now_pos.x < 0 then now_pos.x = 0 elseif now_pos.x > width then now_pos.x = width end if now_pos.y < 0 then now_pos.y = 0 elseif now_pos.y > height then now_pos.y = height end local max_offset = math.max(math.ceil(width/2), math.ceil(height/2)) local new_pos = nil local offset = 0 while offset < max_offset do offset = offset + 1 for x = now_pos.x - offset, now_pos.x + offset do --上 local y = now_pos.y - offset if y >= 0 and not SceneManager:getInstance():IsBlockXY(x, y) then new_pos = co.TableXY(x, y) break end --下 y = now_pos.y + offset if y < height and not SceneManager:getInstance():IsBlockXY(x, y) then new_pos = co.TableXY(x, y) break end end if new_pos ~= nil then break end for y = now_pos.y - offset + 1, now_pos.y + offset - 1 do --左 local x = now_pos.x - offset if x >= 0 and not SceneManager:getInstance():IsBlockXY(x, y) then new_pos = co.TableXY(x, y) break end --右 x = now_pos.x + offset if x < width and not SceneManager:getInstance():IsBlockXY(x, y) then new_pos = co.TableXY(x, y) break end end if new_pos ~= nil then break end end if new_pos then new_pos.x = new_pos.x + 0.5 new_pos.y = new_pos.y + 0.5 end return new_pos end --[[@ 功能: 从起始点到结束点之间找到没有障碍的点 参数: start_logic_pos 长路径起始位置 Game.Vector2 end_logic_pos 终点位置 Game.Vector2 返回值: 无 其它: 无 作者: zsm ]] function SourceOperateMove.FindNoBlockPath(start_logic_pos, end_logic_pos) local logic_dir = co.SubtractXYTable(end_logic_pos, start_logic_pos) local max_dist = co.NormaliseXYTable(logic_dir) local r = Scene.Instance:DetectFirstUnblockPoint(Vector2(start_logic_pos.x, start_logic_pos.y), Vector2(logic_dir.x, logic_dir.y), max_dist) return r end --[[@ 功能: A*寻路 参数: start_pos 起点逻辑坐标 Game.Vector2 end_pos 终点逻辑坐标 Game.Vector2 range 离终点的修正距离(到达离终点的该范围内算作寻路完成) numeric 返回值: 寻路是否成功 bool 返回的路径 table 其它: 无 作者: deadline ]] function SourceOperateMove.FindPathList(obj_type,start_pos, end_pos, range) local path_info = Scene.Instance:FindWay(Vector2(start_pos.x, start_pos.y), Vector2(end_pos.x, end_pos.y), range) if not path_info then return false, {} end local is_path_valid = false local path_list = {} local total_point = #path_info if path_info and total_point >= 2 then is_path_valid = true --将返回的路径转换为起点终点对的形式,方便使用 local tmp_start_pos = path_info[1] local now_index = 2 while now_index <= total_point do local tmp_end_pos = path_info[now_index] local now_pair = {} now_pair.start_point = co.TableXY(tmp_start_pos.x, tmp_start_pos.y) now_pair.end_point = co.TableXY(tmp_end_pos.x, tmp_end_pos.y) path_list[now_index-1] = now_pair now_index = now_index + 1 tmp_start_pos = tmp_end_pos end end if not obj_type or obj_type == SceneBaseType.MainRole then if is_path_valid then EventSystem.Fire(GlobalEventSystem,EventName.BROADCAST_ROLE_WAY_POINT,path_info) end end return is_path_valid, path_list end --[[ * @param startPoint 起始点 * @param time 秒 * @return * ]] function SourceOperateMove.findRandomPath(startPoint, time) local range = time * Scene.Instance.GetMainRole().move_speed range = range * range local dis = 0; --方向加减坐标,2个为一组,分别对应方向1,2,3,4,5,6,7,8,9 local point = {0, 0, -1, 1, 0, 1, 1, 1, -1, 0, 0, 0, 1, 0, -1, -1, 0, -1, 1, -1} local dirList = {2,1,4,7,8,9,6,3} local endPoint; local tx; local ty; local flag; local list = {}; while dis < range do local dir = math.ceil(math.random() * #dirList) tx = startPoint.x + point[dirList[dir]*2 + 1] ty = startPoint.y + point[dirList[dir]*2 + 2] endPoint = co.TableXY(tx, ty); if SceneManager:getInstance():IsBlockXY(endPoint.x, endPoint.y) then table.remove(dirList, dir) if dirList.length == 0 then break; end else dirList = {2,1,4,7,8,9,6,3} local start_real_pos = co.MulXYTable(startPoint, SceneObj.LogicRealRatio) local end_real_pos = co.MulXYTable(endPoint, SceneObj.LogicRealRatio) dis = dis + GameMath.GetDistance(start_real_pos.x, start_real_pos.y, end_real_pos.x, end_real_pos.y) local path_point = {} path_point.start_point = startPoint path_point.end_point = endPoint startPoint = co.TableXY(endPoint.x, endPoint.y) table.insert(list, path_point) end end if #list == 0 then return nil; end return list; end function SourceOperateMove:__init(end_pos, action_func, arg_list) self.type = OperateManager.SourceOperateType.Move self.init_time = 0 -- print("TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT", type(end_pos)) if type(end_pos)=="table" then self.end_pos = co.TableXY(end_pos.x, end_pos.y) end self.action_func = action_func self.arg_list = arg_list self.is_path_valid = false self.path_list = nil self.now_use_pair = nil self.total_pair = nil self.move_type = SourceOperateMove.MoveType.MoveToTarget SourceOperateMove.operate_move_id = SourceOperateMove.operate_move_id + 1 self.id = SourceOperateMove.operate_move_id end function SourceOperateMove:__delete( ) -- GlobalEventSystem:Fire(SceneEventType.MAIN_ROLE_PATH_FINISHED, self.id) end function SourceOperateMove:SetPathList(path) self.path_list = path self.total_pair = #(self.path_list) self.now_use_pair = 1 self.is_path_valid = true self.move_type = SourceOperateMove.MoveType.InitedPath self.is_init_finish = true end --[[@ 功能: 重新根据设定的起始值和终点值计算路径信息 参数: start_pos 起点逻辑坐标 Game.Vector2 end_pos 终点逻辑坐标 Game.Vector2 range 离终点的修正距离(到达离终点的该范围内算作寻路完成) numeric 返回值: 是否成功生成路径信息 bool 其它: 无 作者: deadline ]] function SourceOperateMove:RecalcPathInfo( start_pos, end_pos, range ) -- 增加直线的判断 local start_logic_pos = co.TableXY(start_pos.x, start_pos.y) local end_logic_pos = co.TableXY(end_pos.x, end_pos.y) local dir = co.TableXY(end_logic_pos.x - start_logic_pos.x, end_logic_pos.y - start_logic_pos.y) local dist = co.NormaliseXYTable(dir) --对目标点进行直线探测 local rlt = Scene.Instance:IsStraightLine(Vector2(start_logic_pos.x, start_logic_pos.y), Vector2(end_logic_pos.x, end_logic_pos.y)) if rlt then --直线探测成功 local real_end = end_logic_pos if dist <= range then real_end = start_logic_pos else real_end = co.TableXY(end_logic_pos.x - dir.x * range, end_logic_pos.y - dir.y * range) end local path_point = {} path_point.start_point = co.TableXY(start_logic_pos.x, start_logic_pos.y) path_point.end_point = co.TableXY(real_end.x, real_end.y) table.insert(self.path_list, path_point) self.total_pair = #self.path_list self.now_use_pair = 1 self.is_path_valid = true else --A*寻路 local is_path_valid, path_list = SourceOperateMove.FindPathList(nil,start_logic_pos, end_logic_pos, range) if is_path_valid then --分拆路径 self.path_list = path_list --设置初始化状态, 当前待执行的路径为第一个小路径 self.total_pair = #self.path_list self.now_use_pair = 1 self.is_path_valid = true elseif SceneManager:getInstance():IsBlockXY(end_logic_pos.x, end_logic_pos.y) then local r = Scene.Instance:DetectLastUnblockPoint(Vector2(start_logic_pos.x, start_logic_pos.y), Vector2(dir.x, dir.y), dist) --dist是逻辑坐标系的 if r.z == 1 then local pair = {} pair.start_point = co.TableXY(start_logic_pos.x, start_logic_pos.y) local gv2 = r pair.end_point = co.TableXY(gv2.x, gv2.y) self.end_pos = co.TableXY(gv2.x, gv2.y) table.insert(self.path_list, pair) self.total_pair = 1 self.now_use_pair = 1 self.is_path_valid = true end end end if self.is_path_valid then EventSystem.FireNextFrame(GlobalEventSystem,SceneEventType.CREATE_FINDWAY_POINT, self.path_list) end return self.is_path_valid end --[[@ 功能: 执行初始化操作, 产生一些基准数据 参数: 无 返回值: 为true表示初始化成功, 为false表示初始化失败 其它: 无 作者: deadline ]] function SourceOperateMove:Init() self.path_list = {} local main_role = Scene.Instance:GetMainRole() if not main_role then return false end local start_logic_pos = co.TableXY(main_role:GetLogicPos()) --如果正在飞行,就直接直线走过去 if main_role:IsFlying() then local path_point = {} path_point.start_point = start_logic_pos path_point.end_point = self.end_pos table.insert(self.path_list, path_point) self.total_pair = 1 self.now_use_pair = 1 self.is_path_valid = true return true end --如果当前点在障碍内,就先走出来,再从走出来的点进行寻路 if SceneManager:getInstance():IsBlockXY(start_logic_pos.x, start_logic_pos.y) then local unblock_pos = SourceOperateMove.FindNoBlockPos(start_logic_pos) if unblock_pos then local path_point = {} path_point.start_point = start_logic_pos path_point.end_point = unblock_pos table.insert(self.path_list, path_point) --把走出来的点作为起始点 start_logic_pos = unblock_pos end end if self.move_type == SourceOperateMove.MoveType.MoveToTarget then self.init_time = Status.NowTime if not self.end_pos then return false end local end_logic_pos = self.end_pos --根据设定的起点终点重置路径信息 local is_get_path_suc = self:RecalcPathInfo(start_logic_pos, end_logic_pos, 0) -- print("= = = SourceOperateMove:Init:") -- for i=1,self.total_pair do -- local pt = self.path_list[i] -- print(string.format("= = = = [%.2f,%.2f], [%.2f,%.2f]", pt.start_point.x, pt.start_point.y, pt.end_point.x, pt.end_point.y)) -- end return is_get_path_suc end return false end function SourceOperateMove:BeforeDelete() if not self.is_finish and self.now_use_pair and self.total_pair and self.now_use_pair <= self.total_pair then OperateManager.Instance:CheckJumpAction(self.now_use_pair,self.path_list,self.action_func,self.arg_list) end end --[[@ 功能: 用于从SourceOperate中获取一个NowOperate控制角色行为 参数: 无 返回值: 当前操作包 NowOperate 其它: 无 作者: deadline ]] function SourceOperateMove:GetOperImpl() local now_oper = nil local now_time = Status.NowTime if not self.now_use_pair or not self.total_pair then return end if self.now_use_pair > self.total_pair then --行走完成直接执行相关动作 self.is_finish = true if self.action_func then self.action_func(unpack(self.arg_list)) --print("self.action_func(unpack(self.arg_list))",self.action_func," ",unpack(self.arg_list)) end now_oper = self:GenerateNop(0.2) else --取出下一个小路径执行 local move_pair = self.path_list[self.now_use_pair] if move_pair ~= nil then now_oper = NowOperateMove.New(now_time, move_pair.start_point, move_pair.end_point, self.now_use_pair==self.total_pair) self.now_use_pair = self.now_use_pair + 1 end end return now_oper end