自己写的贪吃蛇(3)

A*算法网上很多介绍了,在此就不详细介绍了。

首先是计算一个格子的(start)的相邻4个方向上的G,F,H值等
每个格子有一个index属性来标识在cells数组中的位置
target表示要到达的目标格子
opened是要将要搜寻的数组
closed是已经搜寻了的数组
snakes看着障碍物

function SnakeGame:calculateCell(start, dir, target, opend, closed, snakes)
    local cell = nil
    local index = start.index
    local b = false
    if dir == SnakeGame.Dir.LEFT then
        cell = index - 1
    elseif dir == SnakeGame.Dir.RIGHT then
        cell = index + 1
    elseif dir == SnakeGame.Dir.UP then
        cell = index + self.column_num
    elseif dir == SnakeGame.Dir.DOWN then
        cell = index - self.column_num
    end
    if self.cells[cell] then
        for k, v in ipairs(closed) do 
            if cell == v.index then
                -- 已经在搜寻过了的路径里则不作处理
                b = true
                break
            end
        end
        if not b then
            for k, v in ipairs(snakes) do 
                if cell == v.index and v ~= target then
                    -- 障碍物
                    b = true
                    break
                end
            end            
        end
        if not b then
            -- 跳行的判断
            if dir == SnakeGame.Dir.LEFT then
                b = self.cells[index].x > self.cells[cell].x
            elseif dir == SnakeGame.Dir.RIGHT then
                b = self.cells[index].x < self.cells[cell].x
            elseif dir == SnakeGame.Dir.UP then
                b = self.cells[index].y < self.cells[cell].y
            elseif dir == SnakeGame.Dir.DOWN then
                b = self.cells[index].y > self.cells[cell].y
            end
            if b then
                local G = start.G + 1 --G值是上一个的G+1
                local H = math.abs(self.cells[target.index].x - self.cells[cell].x) / self.cell_width + math.abs(self.cells[target.index].y - self.cells[cell].y) / self.cell_width
                -- H是当前到目标的最短距离(其实就是横向和竖向的直线距离和)
                local F = G + H
                for k, v in ipairs(opend) do 
                    if v.index == cell then
                        if F < v.F then
                            -- 如果在待搜索的里面并且F值更小则替换F值和parent
                            v.F = F
                            v.parent = start
                        end
                        return nil
                    end
                end
                -- 返回dir方向上的搜寻
                return {index = cell, G = G, H = H, F = F, parent = start, dir = dir}
            end
        end
    end
    return nil
end

在opend里找到最小F值的

function SnakeGame:findMinF(opend)
    local key = #opend
    for k, v in ipairs(opend) do 
        if k < #opend then
            if v.F <= opend[key].F then
                key = k
            end
        end
    end
    return key
end

搜寻一条最短的路径

-- 返回蛇的头部到达target的最短路径或者不存在
function SnakeGame:checkAWay(snakes, target)
    local opend = {}
    local closed = {}
    -- 用蛇的头部作为搜寻的起点
    local start = {index = snakes[1].index, G = 0}
    table.insert(closed, start)
    local left = self:calculateCell(start, SnakeGame.Dir.LEFT, target, opend, closed, snakes)
    local right = self:calculateCell(start, SnakeGame.Dir.RIGHT, target, opend, closed, snakes)
    local up = self:calculateCell(start, SnakeGame.Dir.UP, target, opend, closed, snakes)
    local down = self:calculateCell(start, SnakeGame.Dir.DOWN, target, opend, closed, snakes)

    -- 存在则插入到opend数组里面
    if left then
        table.insert(opend, left)
    end
    if right then
        table.insert(opend, right)
    end
    if up then
        table.insert(opend, up)
    end
    if down then
        table.insert(opend, down)
    end
    local find_a_way = false
    while opend[1] do
        local key = self:findMinF(opend)
        -- 最小F值的放入closed里面
        table.insert(closed, opend[key])
        table.remove(opend, key)
        -- 到达目标则找到最短路径
        if closed[#closed].index == target.index then     
            find_a_way = true       
            break
        end
        local left = self:calculateCell(closed[#closed], SnakeGame.Dir.LEFT, target, opend, closed, snakes)
        local right = self:calculateCell(closed[#closed], SnakeGame.Dir.RIGHT, target, opend, closed, snakes)
        local up = self:calculateCell(closed[#closed], SnakeGame.Dir.UP, target, opend, closed, snakes)
        local down = self:calculateCell(closed[#closed], SnakeGame.Dir.DOWN, target, opend, closed, snakes)
        if left then
            table.insert(opend, left)
        end
        if right then
            table.insert(opend, right)
        end
        if up then
            table.insert(opend, up)
        end
        if down then
            table.insert(opend, down)
        end

    end
    if find_a_way then        
        return closed
    else
        print("not find a way!")
        return nil
    end
end

在ctor里面初始化一个数组self.targetLines = {} 用于放置最短路径每一步的方向,即蛇移动的方向

function SnakeGame:doAI(target)
    if #self.targetLines > 0 then
        return
    end
    target = target or self.tail      
    local closed = self:checkAWay(self.snakes, target)
    if closed then
        self.targetLines = {}
        table.insert(self.targetLines, closed[#closed].dir)
        local parent = closed[#closed].parent
        local ii = 1

        while parent and parent ~= closed[1] do
            local index = parent.index            
            local x = self.cells[index]
            table.insert(self.targetLines, parent.dir)  
            parent = parent.parent
        end          
    else
        print("not find a way!")
    end
end

在generateBody末尾增加一个self:doAI()的调用,让每次生成目标tail的时候生成最短路径!

最后修改onEnter函数中的update让它沿AI最短路径跑起来

function SnakeGame:onEnter()
    local time1 = tsixi.THelper:currentMilliseconds()
    local update = function(dt)
        if not self.is_failed then
            local now = tsixi.THelper:currentMilliseconds()
            if not self.parse and (now - time1 >= 50 or self.must) then
                self.must = false
                time1 = now
                self.direction = self.targetLines[#self.targetLines]
                table.remove(self.targetLines)                  
                self:doMove()                
            end     
        end
    end
    self:scheduleUpdateWithPriorityLua(update, 0) 
end

现在蛇可以自己去吃目标物了
这里写图片描述

现在这个AI还有很多问题,如果生成的红块在蛇本身的身体里时就找不到,下一节再优化这个问题

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值