Created
November 25, 2019 00:41
-
-
Save raystudio9236/b0b8dcd8565d7b0b703b44d32fc7f553 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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