Skip to content

Instantly share code, notes, and snippets.

@raystudio9236
Created November 25, 2019 00:41
Show Gist options
  • Save raystudio9236/b0b8dcd8565d7b0b703b44d32fc7f553 to your computer and use it in GitHub Desktop.
Save raystudio9236/b0b8dcd8565d7b0b703b44d32fc7f553 to your computer and use it in GitHub Desktop.
MapGenerator = UGameObject:extend()
function MapGenerator:new(scene, opts)
MapGenerator.super.new(self, scene, 'Prefabs/MapGenerator', opts)
self.transform.position = Vector3.new(-100, 0, 0)
self:clear()
--找到scene里GameObject
self.ball = self:find('Ball')
self.ballSpawnPoint = self:find('BallSpawnPoint').transform
self.line = self:find('Line')
self.camera = self:find('Camera')
end
function MapGenerator:start()
MapGenerator.super.start(self)
end
function MapGenerator:update(dt)
MapGenerator.super.update(self, dt)
end
function MapGenerator:destroy(dt)
MapGenerator.super.destroy(self, dt)
self:clear()
self.mouseEventComp.OnMouseDragHandler = nil
self.mouseEventComp = nil
self.ball = nil
self.ballSpawnPoint = nil
self.line = nil
self.camera = nil
end
---
---生成地图方法
---
function MapGenerator:genMap()
--各种球的尺寸和数量
local smallSize = 0.8
local middleSize = 1
local largeSize = 1.2
local smallCount = 32
local middleCount = 20
local largerCount = 12
self.balls = {}
self.lines = {}
--创建球
self:createBall(smallCount, smallSize)
self:createBall(middleCount, middleSize)
self:createBall(largerCount, largeSize)
self.timer:after(0.2, function()
--删除rigidbody避免球位置不断变化
for _, b in ipairs(self.balls) do
local rigidbody = b.o:GetComponent(typeof(Rigidbody2d.CS))
GameObjectUtil.destroy(rigidbody)
b.pos = b.o.transform.position
end
--按照y轴排序,将y轴大的放在前面,即上面的球在前面
table.sort(self.balls, function(node1, node2)
local ret = false
if not node1 or not node2 then
return ret
end
local pos1 = node1.pos
local pos2 = node2.pos
--一个参考阈值,多次尝试得出
if pos1.y - pos2.y > middleSize then
ret = true
end
return ret
end)
--找到每个球相邻的球,双重循环暴力做法,待优化
for i, node1 in ipairs(self.balls) do
for j, node2 in ipairs(self.balls) do
if i ~= j then
local pos1 = node1.pos
local pos2 = node2.pos
local len = Vector2.len(pos2.x - pos1.x, pos2.y - pos1.y)
if len < 0.8 * (node1.r + node2.r) then
node1.neighbors = node1.neighbors or {}
table.insert(node1.neighbors, node2)
end
end
end
end
--创建从上到下的路径
self:createPathFromTopToBottom(1)
self:createPathFromTopToBottom(2)
self:createPathFromTopToBottom(3)
self:createPathFromTopToBottom(4)
--下面是显示逻辑,以及划线逻辑
local bottoms = {}
for i = #self.balls, 1, -1 do
local node = self.balls[i]
if not node.selected then
GameObjectUtil.destroy(node.o)
table.remove(self.balls, i)
else
node.o.transform.localScale = node.o.transform.localScale * 0.6
local spriteRender = node.o:GetComponent(typeof(CS.UnityEngine.SpriteRenderer))
spriteRender.enabled = true
if node.isTop then
if node.to then
node.isTop = false
else
spriteRender.color = Color.red
end
elseif node.isDown then
spriteRender.color = Color.blue
table.insert(bottoms, node)
end
end
end
-- draw line
for _, b in ipairs(bottoms) do
for _, i in ipairs(b.selected) do
local l = GameObjectUtil.instantiate(self.line)
l.name = tostring('line' .. tostring(i))
l.transform.localScale = Vector3.one
local points = {}
local lineRenderer = l:GetComponent(typeof(CS.UnityEngine.LineRenderer))
table.insert(points, b.pos)
local to = b.to[i]
while to do
table.insert(points, to.pos)
to = to.to and to.to[i] or nil
end
lineRenderer.positionCount = #points
lineRenderer:SetPositions(points)
table.insert(self.lines, l)
end
end
local mapWall = self:find('MapWalls')
mapWall:SetActive(false)
if self.opts and self.opts.onFinished then
self.opts.onFinished()
end
end)
end
function MapGenerator:createBall(cnt, size)
for i = 1, cnt do
local b = GameObjectUtil.instantiate(self.ball)
b.transform:SetParent(self.ballSpawnPoint)
b.transform.localPosition = Vector3.new(random(-1, 1), random(-1, 1), 0)
b.transform.localScale = Vector3.new(size, size, 1)
table.insert(self.balls, { o = b, r = size * 4 })
end
end
---
---随机得到一个顶部的球
---暴力随机,6是经验值
---
function MapGenerator:getRandomTopNode()
local i = randint(1, 6)
local times = 0
while self.balls[i].selected do
i = randint(1, 6)
times = times + 1
if times > 500 then
Log.error('getRandomTopNode try more than 500 times')
break
end
end
return self.balls[i]
end
---
---得到一个向下相邻的球
---
function MapGenerator:getRandomNeighborDown(node)
local downNeighbors = {}
for _, n in ipairs(node.neighbors) do
if node.pos.y - n.pos.y > 1 then
table.insert(downNeighbors, n)
end
end
if #downNeighbors == 0 then
return nil
end
if #downNeighbors == 1 then
return downNeighbors[1]
end
local i = randint(1, #downNeighbors)
return downNeighbors[i]
end
---
---自顶向下创建路径
---
function MapGenerator:createPathFromTopToBottom(i)
local top = self:getRandomTopNode()
top.isTop = true
top.selected = top.selected or {}
table.insert(top.selected, i) --记录它是被几号路径连接
local down = self:getRandomNeighborDown(top)
down.to = down.to or {}
down.to[i] = top --记录它的去向,即谁连接了它
local times = 0
while true do
down.selected = down.selected or {}
table.insert(down.selected, i)
local d = self:getRandomNeighborDown(down)
if not d then
down.isDown = true
break
end
d.to = d.to or {}
d.to[i] = down
down = d
times = times + 1
if times > 500 then
--Log.error('createPathFromTopToBottom try more than 500 times')
break
end
end
end
function MapGenerator:clear()
if self.balls then
for _, b in ipairs(self.balls) do
GameObjectUtil.destroy(b.o)
end
self.balls = {}
end
if self.lines then
for _, l in ipairs(self.lines) do
GameObjectUtil.destroy(l)
end
self.lines = {}
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment