• 风暴幻想游戏-家园系统设计


    之前做过一个家园系统,今天和大家分享的是,关于在做家园系统的时候遇到的一些问题和当时的解决的方法。

    遇到的几个问题:

    1. 地图层问题。

        (1)这些东西如何在场景中摆放:地面,围墙,小窝,人,未解锁区域等等。

        (2)地图大小限制和地图最小单位的大小等因素。

        (3)我们需要保存的数据有哪些。

          当时的解决方法:

          1)幻想的地图层,把地图分成好几块加载的。策划根据地图编辑器生成了对应的文件,底层加载地图的时候会加载这些地图。但是家园地图是一个全新的地图。而且不是地图编辑器编辑的。但是底层有不提供修改支持。因此原先那几块地图就用了空的文件进行修改。相当于进入这个场景的时候,是一个黑的世界。

           2)地面,围墙,小窝,人,未解锁区域等,所有的家园场景的东西,我们通过不同的层加载到场景里。写了一个HomeMapDrawObject.lua 下面是它的初始化函数

     1 function HomeMapDrawObject:__init()
     2     HomeMapDrawObject.number = HomeMapDrawObject.number + 1
     3     self.core_pos = cc.vec2(0, 0)
     4 
     5     --集合
     6     self.coreNodes = {}
     7  
     8     --保持对象应用,方可访问其成员方法
     9     self.spriteLayers = {}
    10     -- self.spriteLayers[cc.RenderQueue.GRQ_SHADOW] = {}
    11     -- self.spriteLayers[cc.RenderQueue.GRQ_BUILD_AND_PLAYER] = {}
    12 
    13     --草地
    14     local gressNode = cc.Node:create()
    15     self.coreNodes[HomeMapDrawObject.Layer.GRESS] = gressNode
    16     HandleRenderUnit:GetCoreScene():addToRenderGroup(gressNode, cc.RenderQueue.GRQ_SHADOW)
    17 
    18     --阴影
    19     local shadowNode = cc.Node:create()
    20     self.coreNodes[HomeMapDrawObject.Layer.SHOADOW] = shadowNode
    21     HandleRenderUnit:GetCoreScene():addToRenderGroup(shadowNode, cc.RenderQueue.GRQ_SHADOW + 1)
    22 
    23     --身体
    24     local bodyNode = cc.Node:create()
    25     self.coreNodes[HomeMapDrawObject.Layer.BODY] = bodyNode
    26     HandleRenderUnit:GetCoreScene():addToRenderGroup(bodyNode, cc.RenderQueue.GRQ_BUILD_AND_PLAYER - 2)
    27 
    28     --其他
    29     local otherNode = cc.Node:create()
    30     self.coreNodes[HomeMapDrawObject.Layer.OTHER] = otherNode
    31     HandleRenderUnit:GetCoreScene():addToRenderGroup(otherNode, cc.RenderQueue.GRQ_BUILD_AND_PLAYER - 1)
    32 
    33 end
    View Code

      我们将家园场景中的对象都称做家园碎片,用一个lua去维护。对于不同的类型,不同的点击效果做不同的处理等等。

    下面是HomeMapPiece.lua

     1 PriorityQueue = PriorityQueue or BaseClass()
     2 
     3 function PriorityQueue:__init(infoVo)
     4     self.list     = {}
     5     self.hash     = {}    
     6     self.L         = bit.lshift
     7     self.And     = bit.band
     8     self.R         = bit.rshift
     9 
    10     if infoVo then
    11         self:Push(infoVo)
    12     end
    13 end
    14 
    15 function PriorityQueue:__delete()
    16     self.list = nil
    17     self.hash = nil
    18 end
    19 
    20 function PriorityQueue:Push(infoVo)
    21     table.insert(self.list, infoVo)
    22 
    23     local child = #self.list
    24     local root = self.R(child, 1)
    25     while child > 1 and self.list[root].F > self.list[child].F do
    26         self.list[root], self.list[child] = self.list[child], self.list[root]
    27 
    28         self:SetHash(self.list[root].value, root)
    29         self:SetHash(self.list[child].value, child)
    30         child = root
    31         root = self.R(child, 1)
    32     end    
    33 end
    34 
    35 function PriorityQueue:Pop()
    36     local firstInfoVo = self.list[1]
    37     local length = #self.list
    38     --特判
    39     if not self.list[length] then return firstInfoVo end
    40     if length == 1 then
    41         self.list = {}
    42         return firstInfoVo
    43     end
    44 
    45     local lastInfoVo = self.list[length]
    46     table.remove(self.list, #self.list)
    47     length = length - 1
    48 
    49     local root, child = 1, 2
    50     while child <= length do
    51         --找出左右最小的值
    52         if child + 1 <= length and self.list[child + 1].F < self.list[child].F then
    53             child = child + 1
    54         end
    55         if lastInfoVo.F < self.list[child].F then
    56             break
    57         else
    58             self.list[root] = self.list[child]
    59             self:SetHash(self.list[root].value, root)
    60 
    61             root = child
    62             child = self.L(child, 1)
    63         end
    64     end
    65     self.list[root] = lastInfoVo
    66     self:SetHash(self.list[root].value, root)
    67 
    68     return firstInfoVo
    69 end
    70 
    71 function PriorityQueue:SetHash(value, root)
    72     self.hash[value] = root
    73 end
    74 
    75 function PriorityQueue:GetInfoVo(index)
    76     return self.list[self.hash[index]]
    77 end
    78 
    79 function PriorityQueue:IsEmpty()
    80     if self.list[1] then
    81         return false
    82     end
    83     return true
    84 end
    View Code

    下面是HomePieceVo.lua

      1 --家园地图碎片vo
      2 
      3 HomePieceVo = HomePieceVo or BaseClass()
      4 
      5 function HomePieceVo:__init()
      6     self.insId = 0                             --家具唯一id
      7     self.type = HomeMapManager.TYPE.GRASS     --碎片类型
      8     self.typeId = 0                            --类型id
      9     self.name = ""                             --家具名字
     10     self.resId = 0                            --形象id
     11     self.sideType = 0                        --布置区域(1室内2室外3任意)
     12     self.width = 0                            --
     13     self.height = 0                            --
     14     self.direction = 3                         --方向
     15     self.logicPosX = 0                         --逻辑坐标点x(和服务端交互的)
     16     self.logicPosY = 0                        --逻辑坐标点y
     17 
     18     self.leftNum = 0                         --左边的数字
     19     self.rightNum = 0                        --右边数字
     20     self.upNum = 0                            --上方数字
     21     self.bottomNum = 0                        --下方数字
     22 
     23     self.pointIndex = 0                     --x,y转化成的数字
     24     self.containPos = {}                    --覆盖的坐标点
     25     self.shadowPos = {}                     --阴影区的坐标点(当人物走到这个点的时候,他会显示成半透明)
     26 
     27     self.caveType = 1                        --类型1坐骑/2宠物/3精灵
     28     self.animalTypeId = 0                      --牲口id
     29     self.caveResId = 0                        --资源id
     30     self.masterId = 0                         --牲口主人id
     31     self.foodId = 0                            --口粮id
     32     self.feedRoleId = 0                        --饲养员id
     33     self.harvestTime = 0                     --收获时间
     34     self.expReward = 0                        --经验奖励
     35     self.propArr = {}                         --道具奖励
     36 end
     37 
     38 function HomePieceVo:__delete()
     39 end
     40 
     41 function HomePieceVo:ReadFromProtocal()
     42     self.insId,
     43     self.typeId,
     44     self.name,
     45     self.resId,
     46     self.logicPosX,
     47     self.logicPosY,
     48     self.direction,
     49     self.height,
     50     self.width 
     51     = UserMsgAdapter.ReadFMT("IIsICCCHH")
     52         
     53     local length = UserMsgAdapter.ReadFMT("h")
     54 
     55     --处理占据的点
     56     for i = 1, length do
     57         local vo = {}
     58         vo.x,
     59         vo.y 
     60         = UserMsgAdapter.ReadFMT("cc")
     61         self.containPos[i] = vo
     62     end
     63 
     64     --功能建筑部分(小窝)
     65     self.caveType,            --类型1坐骑/2宠物/3精灵
     66     self.animalTypeId,      --牲口(坐骑/宠物/精灵)id
     67     self.caveResId,            --牲口资源id
     68     self.masterId,             --牲口主人id
     69     self.foodId,            --口粮id
     70     self.feedRoleId,        --饲养员id
     71     self.harvestTime,         --收获时间
     72     self.expReward             --经验奖励
     73         = UserMsgAdapter.ReadFMT("ciiiiiii")
     74     length = UserMsgAdapter.ReadFMT("h")
     75     for i = 1, length do
     76         local tmp = {}
     77         tmp.propId,            --道具id
     78         tmp.propNumber,     --道具数量
     79         tmp.bind             --绑定
     80             = UserMsgAdapter.ReadFMT("iic")
     81         self.propArr[i] = tmp
     82     end
     83 
     84     local configPiece = Config.HomeFurniture[self.typeId]
     85     --处理阴影区的点
     86     local shadowHeight = configPiece.hight or 0
     87     for i = 1, shadowHeight do
     88         for k = 1, #self.containPos do
     89             local vo = {}
     90             vo.x = self.containPos[k].x
     91             vo.y = self.containPos[k].y - i
     92 
     93             table.insert(self.shadowPos, vo)
     94         end
     95     end
     96     local homeMapManager = HomeMapManager:getInstance()
     97     --家具类型
     98     if configPiece then
     99         self.type = homeMapManager:getPieceType(configPiece.type)
    100     end
    101     --寻路的时候构图
    102     self.pointIndex = homeMapManager:getPointIndex(self.logicPosX, self.logicPosY)
    103 end
    104 
    105 --[[
    106     进入场景初始化处理草地信息
    107 ]]
    108 function HomePieceVo:sceneInitDispose(configVo)
    109     self.logicPosX = configVo[1]
    110     self.logicPosY = configVo[2]
    111     self.typeId = configVo[3]
    112     self.insId     = configVo[4]
    113 
    114     local configPiece = Config.HomeFurniture[self.typeId]
    115     self.resId = configPiece.res_id
    116     self.sideType = configPiece.sideType
    117     self.width = configPiece.width
    118     self.height = configPiece.length
    119     self.name = configPiece.name
    120 
    121     local homeMapManager = HomeMapManager:getInstance()
    122     --碎片类型
    123     self.type = homeMapManager:getPieceType(configPiece.type)
    124     self.pointIndex = homeMapManager:getPointIndex(self.logicPosX, self.logicPosY)
    125     
    126     --占据的格子
    127     local posVo = {}
    128     posVo.x = self.logicPosX
    129     posVo.y = self.logicPosY
    130     self.containPos[1] = posVo
    131 end
    132 
    133 function HomePieceVo:getHomeLogicPos()
    134     return self.homeLogicPosX, self.homeLogicPosY
    135 end
    136 
    137 function HomePieceVo:setHomeLogicPos(x, y)
    138     self.homeLogicPosX = x
    139     self.homeLogicPosY = y
    140 end
    141 
    142 function HomePieceVo:getLogicPos()
    143     return self.logicPosX, self.logicPosY
    144 end
    145 
    146 function HomePieceVo:setLogicPos(x, y)
    147     self.logicPosX = x
    148     self.logicPosY = y
    149 end
    150 
    151 function HomePieceVo:getVar(var)
    152     return self[var]
    153 end
    154 
    155 function HomePieceVo:setVar(var, value)
    156     if not self[var] then
    157         print("ERROR HomePieceVo no has var:", var)
    158         return
    159     end
    160     self[var] = value
    161 end
    View Code

      3)地图大小限制和地图最小单位的大小等因素。当时策划的需求是最小的地图是3600*3600,以后可能会扩大道7200*7200的地图。

     幻想的原先的地图的逻辑块大小是60*30代表一个格子。所有如果在原先基础上进行寻路和拾取就变成了60*120, 120*240的地图。

       当时美术那边提出说,要使用菱形的地板,从美术角度来说,看起来的效果会好一些。最后使用的方案是这样的:

     图中的坐标系是服务器的坐标系,一个菱形面积 等于 二个坐标系格子面积。这样的摆放,通过观察会发现一些规律。

     规律1:例如第一排的点A, B 他们的坐标分表是(1, 1),(3,1);第二排的点C,D 他们的坐标分别是(2,2),(4,2);x,y满足奇偶性。

      因为我们摆放的点不存在例如 (2,3),(5,6)类似这样的点。

    规律2:因为我们需要进行拾取判定,我们的点击可能落在任意坐标系格子内。但是可分成8种情况进行讨论(一个菱形区域中)。

      下面讨论其中的1种情况。

      1.例如图中E点,根据图中可以看出,当我们点击E点的时候,实际上我们要算出,当前我们点击的是(7,3)这个点的菱形区域。

      E点的周围4个点分别是(min_x, min_y), (min_x, max_y), (max_x, min_y), (max_x, max_y)。(这些点都可以通过e点向上取整或者向下取整得出)

      这4个点中的一个点就是当前我们想求出的菱形区域的中心点

      但是此时,连接的是(min_x, max_y), (max_x, min_y)这两个点,构成了菱形的一条边。

      经过观察,我们知道

      E点的min_x = 6, max_y = 3, 和 E点相类的点F ,它的情况是 min_x = 7, max_y = 4, 可再根据几个点进行观察总结。

      我们可以得出

      当 min_x, max_y 不是同奇数或者同偶数的时候,连接的是 (min_x, max_y), (max_x, min_y)这两个点,构成了菱形的一条边。

      当 min_x, max_y 是同奇数或者同偶数的时候,连接的是 (min_x, min_y), (max_x, max_y)这两个点,构成了菱形的一条边。  

      2.由于1.得出的判断,我们可以排除2个点(因为已经构成了菱形的一条边了),剩下2个点,我们要如何判断呢?

      使用线性规划,根据1.求出的这2个点,我们构建直线,判断E点是在这条线段上方还说下方。这样,我们就可以得出需要找到的那个点了。

      剩下的几种情况类似,同理进行讨论。

      通过这样,我们就可以进行对拾取和放置场景碎片(草地,小窝等)进行操作。

      4)我们需要保存和维护的数据有哪些呢?

    1     self.pieceList = {}    --家园碎片对象(草地上的东西等)
    2     self.map = {}         --家园地图
    3     self.roadMap = {}     --可行走的区域维护
    4     self.shadowMap = {} --阴影区(人行走在这个区域会调整透明度)
    5     self.tmpList = {}   --临时展示的区域
    6     self.lockList = {}  --解锁格子信息

    2.拾取问题。

           如果通过模拟点击能判断到是具体哪一个地图最小元素。

    下面代码是 通过服务端逻辑坐标,计算出当前点击的是哪一个地图逻辑块的中心位置的坐标

     1 --[[
     2     @brief: 逻辑坐标转像家园地图坐标
     3 
     4     @param: logic_x        逻辑横坐标
     5             logic_y        逻辑纵坐标
     6             scale_size  缩放比例
     7     @return: 逻辑坐标
     8 ]]
     9 function TerrainHelper:ToHomeMapPos(logic_x, logic_y, scale_size)
    10     --对特殊点的判断。
    11     local home_logic_x, home_logic_y = self:logicToHomePos(logic_x, logic_y, scale_size)
    12 
    13     local min_x, max_x = math.floor(home_logic_x), math.ceil(home_logic_x)
    14     local min_y, max_y = math.floor(home_logic_y), math.ceil(home_logic_y)
    15 
    16     if GameMath.getEvenAndOdd(min_x) == GameMath.getEvenAndOdd(max_y) then
    17         local k = (max_y - min_y) / (max_x - min_x) --斜率
    18         local b = max_y - k * max_x
    19 
    20         local value = k * home_logic_x + b
    21 
    22         if home_logic_y < value then --在线性规划区域下方
    23             home_logic_x = max_x
    24             home_logic_y = min_y
    25         else                     --在线性规划区域上方
    26             home_logic_x = min_x
    27             home_logic_y = max_y
    28         end
    29     else
    30         local k = (max_y - min_y) / (min_x - max_x)
    31         local b = max_y - k * min_x 
    32         local value = k * home_logic_x + b
    33 
    34         if home_logic_y < value then
    35             home_logic_x = min_x 
    36             home_logic_y = min_y
    37         else
    38             home_logic_x = max_x
    39             home_logic_y = max_y
    40         end
    41     end
    42     return home_logic_x, home_logic_y 
    43 end
    View Code

    下面代码是 家园中对场景拾取操作的处理

    1 function HomeController:homePiecePick(location)
    2     local pos = HandleRenderUnit:ViewToWorld(location)
    3     pos = HandleRenderUnit:WorldToLogic(pos) --服务端的逻辑坐标
    4     local scaleSize = HomeMapManager:getInstance():getScaleSize() --缩放比
    5     local homeLogicX, homeLogicY = self.handleTerrainHandler:ToHomeMapPos(pos.x, pos.y, scaleSize)
    6 
    7     self:modelHander(homeLogicX, homeLogicY)
    8 end
    View Code

    3.寻路问题。

        (1)使用一个怎么样的寻路算法。迪杰斯特拉,或者A*, 或者其他方式。

        (2)如何维护一个动态地图。

      首先要解决的是一个动态维护的过程。其实按照前面的铺垫,这个动态地图的维护并不难,等同于维护一个可行走区域。当加入一个逻辑快的时候,

    我们会对这个数据进行分析,加入的是什么。是草地,还说小窝或者是其他什么东西。这里就可以需要添加一个判定函数,这个东西是行走有否。

    然后分别对这个区域,和这个区域的相邻区域进行设置。这样加入和删除一个地图里的元素,我们都可以动态处理。

    下面是动态删减的维护代码,其中SCENE_DIRECTION是当前地图最小格子,周围8个方向的table

     1 --[[
     2     维护可行走的区域信息
     3     pointIndex: x, y转化后的序号
     4     x, y:    逻辑坐标x, y
     5     types:      类型  1 添加 2 删除
     6 ]]
     7 function HomeMapManager:updateRoadMap(pointIndex, x, y, types)
     8     local index = pointIndex
     9     --无信息又要删除
    10     if types == 2 and not self.roadMap[index] then
    11         return
    12     end
    13 
    14     if types == 1 then --添加
    15         self.roadMap[index] = {}
    16         for i = 1, #SCENE_DIRECTION do
    17             local newIndex = self:getPointIndex(SCENE_DIRECTION[i][1] + x, SCENE_DIRECTION[i][2] + y)
    18             if self.roadMap[newIndex] then
    19                 self.roadMap[index][newIndex] = true
    20                 self.roadMap[newIndex][index] = true
    21             end
    22         end
    23     elseif types == 2 then --删除
    24         for newIndex, _ in pairs(self.roadMap[index]) do--删除和当前有关的信息
    25             if self.roadMap[newIndex] then
    26                 self.roadMap[newIndex][index] = nil
    27                 local length = 0
    28                 for _, _ in pairs(self.roadMap[newIndex]) do
    29                     length = length + 1
    30                     break
    31                 end
    32                 if length == 0 then
    33                     self.roadMap[newIndex] = nil
    34                 end
    35             end
    36         end
    37         self.roadMap[index] = nil
    38     end
    39 end
    40 
    41 function HomeMapManager:getPointIndex(x, y)
    42     return bit.lshift(x, HomeMapManager.PointLineBitLen) + y
    43 end
    View Code

      有了动态地图后,就是对地图进行搜索。我们需要快速计算出,从一个坐标(x, y)到另一个坐标(x1,y1)的行走路径。

    原先使用的方案是迪杰斯特拉。刚刚说起,这个最小的地图是3600*3600,然后根据我们铺的菱形他的大小是120*60的。所以最小的行走地图是

    30*60 = 1800 个点。但是大多数情况下这个地图并不是稀疏的地图。极端情况可能存在路径是1800*8个方向 = 14400条路径。每一次行走,我们需要形成1800个点的最小生成树,这样消耗比较大。这仅仅是3600*3600的地图。后面扩展成7200*7200,会更明显。

      A*算法。详细的这里不介绍了。详细请谷歌百度一下。

      A*的实现

      1 --[[
      2     A*寻路          
      3     map:            地图
      4     startPoint:     开始点    
      5     endPoint:         结束点
      6 ]]
      7 
      8 AStar = AStar or {}
      9 AStar.INF = 0xffffffff
     10 
     11 function AStar.findWay(map, startPoint, endPoint)
     12     local preList = AStar.BFS(map, startPoint, endPoint)
     13     local tmpList = {}
     14     local x = endPoint
     15     while(preList[x] and preList[x] ~= 0 ) do
     16         table.insert(tmpList, x)
     17         x = preList[x]
     18     end
     19     table.insert(tmpList, startPoint)
     20 
     21     local pointList = {}
     22     for i = #tmpList, 1, -1 do
     23         table.insert(pointList, tmpList[i])
     24     end
     25     -- PrintTable(pointList)
     26     return pointList
     27 end
     28 
     29 function AStar.BFS(map, startPoint, endPoint)
     30     local hash = {}        --标记已经被用过的点
     31     local preList = {}  --标记前继点
     32 
     33     local Queue = PriorityQueue.New(AStar.getTable(0, 0, startPoint, 0, 0)) --优先队列
     34 
     35     local homeManager = HomeMapManager:getInstance()
     36     local endx, endy = homeManager:getPointXY(endPoint)
     37 
     38     while not Queue:IsEmpty() do
     39         local nowInfoVo = Queue:Pop()
     40         local tmpPoint = nowInfoVo.value
     41 
     42         if tmpPoint == endPoint then
     43             Queue:DeleteMe()
     44             return preList
     45         end
     46 
     47         if not hash[tmpPoint] then
     48             hash[tmpPoint] = true
     49             local x, y = homeManager:getPointXY(tmpPoint)
     50             if map[tmpPoint] then
     51 
     52                 --枚举可以由当前点走向的点
     53                 for point, _ in pairs(map[tmpPoint]) do 
     54                     if not hash[point] then
     55                         local x1, y1 = homeManager:getPointXY(point)
     56                         local H = AStar.max(AStar.abs(endx - x1), AStar.abs(endy - y1))
     57                         local G = nowInfoVo.G
     58                         if x1 == x or y1 == y then
     59                             G = 2 + G
     60                         else
     61                             G = 1 + G
     62                         end
     63 
     64                         --不同方向权重增加(鼓励尽可能走直线,不要走弯曲的路线)
     65                         local dirx = x - x1
     66                         local diry = y - y1
     67                         if nowInfoVo.dirx ~= dirx or nowInfoVo.diry ~= diry then
     68                             G = G + 1.41
     69                         end
     70 
     71                         local tmpInfoVo = Queue:GetInfoVo(point)
     72                         if not tmpInfoVo then
     73                             local infoVo = AStar.getTable(G,H,point,dirx,diry)
     74                             Queue:Push(infoVo)
     75                             preList[point] = tmpPoint
     76                         else
     77                             --如果当前坐标的F值小于已经压入队列里面的F值
     78                             if tmpInfoVo.F > G + H then
     79                                 local infoVo = AStar.getTable(G,H,point,dirx,diry)
     80                                 Queue:Push(infoVo)
     81                                 preList[point] = tmpPoint
     82                             end
     83                         end
     84                     end
     85                 end
     86             end
     87         end
     88     end
     89     Queue:DeleteMe()
     90     return preList
     91 end
     92 
     93 function AStar.init(Queue, startPoint)
     94     local infoVo = AStar.getTable(0, 0, startPoint, 0, 0)
     95     Queue.Push(infoVo)
     96 end
     97 
     98 function AStar.getTable(g, h, point, x, y)
     99     return {G = g, H = h, F = g + h, value = point, dirx = x, diry = y}
    100 end
    101 
    102 function AStar.abs(a)
    103     if a >= 0 then
    104         return a
    105     else
    106         return -a
    107     end
    108 end
    109 
    110 function AStar.max(a, b)
    111     return a > b and a or b
    112 end
    View Code

      最小堆

     1 PriorityQueue = PriorityQueue or BaseClass()
     2 
     3 function PriorityQueue:__init(infoVo)
     4     self.list     = {}
     5     self.hash     = {}    
     6     self.L         = bit.lshift
     7     self.And     = bit.band
     8     self.R         = bit.rshift
     9 
    10     if infoVo then
    11         self:Push(infoVo)
    12     end
    13 end
    14 
    15 function PriorityQueue:__delete()
    16     self.list = nil
    17     self.hash = nil
    18 end
    19 
    20 function PriorityQueue:Push(infoVo)
    21     table.insert(self.list, infoVo)
    22 
    23     local child = #self.list
    24     local root = self.R(child, 1)
    25     while child > 1 and self.list[root].F > self.list[child].F do
    26         self.list[root], self.list[child] = self.list[child], self.list[root]
    27 
    28         self:SetHash(self.list[root].value, root)
    29         self:SetHash(self.list[child].value, child)
    30         child = root
    31         root = self.R(child, 1)
    32     end    
    33 end
    34 
    35 function PriorityQueue:Pop()
    36     local firstInfoVo = self.list[1]
    37     local length = #self.list
    38     --特判
    39     if not self.list[length] then return firstInfoVo end
    40     if length == 1 then
    41         self.list = {}
    42         return firstInfoVo
    43     end
    44 
    45     local lastInfoVo = self.list[length]
    46     table.remove(self.list, #self.list)
    47     length = length - 1
    48 
    49     local root, child = 1, 2
    50     while child <= length do
    51         --找出左右最小的值
    52         if child + 1 <= length and self.list[child + 1].F < self.list[child].F then
    53             child = child + 1
    54         end
    55         if lastInfoVo.F < self.list[child].F then
    56             break
    57         else
    58             self.list[root] = self.list[child]
    59             self:SetHash(self.list[root].value, root)
    60 
    61             root = child
    62             child = self.L(child, 1)
    63         end
    64     end
    65     self.list[root] = lastInfoVo
    66     self:SetHash(self.list[root].value, root)
    67 
    68     return firstInfoVo
    69 end
    70 
    71 function PriorityQueue:SetHash(value, root)
    72     self.hash[value] = root
    73 end
    74 
    75 function PriorityQueue:GetInfoVo(index)
    76     return self.list[self.hash[index]]
    77 end
    78 
    79 function PriorityQueue:IsEmpty()
    80     if self.list[1] then
    81         return false
    82     end
    83     return true
    84 end
    View Code

    最后我们得到了一组行走的序列。(坐标集合),传给原先幻想的处理行走的逻辑部分,然后人物就可以走动了。

    4.其他问题。

        (1)进入家园场景的时间比较短,如何生成和维护这些大量的对象。

      因为家园场景中对象太多,进入场景的时候,一次创建会卡帧。体验很不好。有一台比较老的安卓机子,等了好久才加载完这个场景。后面采取的方式是分帧加载。一帧创建几个对象。然后在x秒后能够完成创建完这个场景。这里的x需要各种尝试,应该多大,肯定不行,玩家进入场景的时候明显感觉到到周围是黑色的。如果过小也不行,代表一帧需要加载的数量太多,会卡帧。而且不同的手机性能不同,也会有不一样的效果。

     (2)编辑模式下的各种操作。

  • 相关阅读:
    在Centos7下源代码安装配置Nginx
    mysql5.7.21源码安装
    数据库设计三大范式
    电商项目中使用Redis实现秒杀功能
    PHP和Redis实现在高并发下的抢购及秒杀功能示例详解
    PHP面向对象(抽象类与抽象方法、接口的实现)
    php面向对象 封装继承多态 接口、重载、抽象类、最终类总结
    利用VHD虚拟文件加密自己的个人信息
    Chrome常用快捷键
    stl本子
  • 原文地址:https://www.cnblogs.com/tom987690183/p/7250003.html
Copyright © 2020-2023  润新知