Skip to content

Instantly share code, notes, and snippets.

@tnlogy
Created February 6, 2014 15:54
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save tnlogy/8846921 to your computer and use it in GitHub Desktop.
Save tnlogy/8846921 to your computer and use it in GitHub Desktop.
--# Main
function setup()
parameter.boolean("FILL")
parameter.integer("RANGE", 1,20,3)
parameter.boolean("LINE")
parameter.boolean("FOV")
parameter.boolean("MOVE")
hs = Hexagons():createMesh():set(0,0,color(207, 67, 67))
u = Unit(hs:pos(0,0))
end
function draw()
background(78, 78, 94, 255)
translate(WIDTH/2,HEIGHT/2)
hs:draw()
u:draw()
end
function add(q,r,d)
local c = color(d*50+math.random(0,50), 90, 94)
hs:set(q,r,c)
end
function touched(touch)
local x,y = touch.x-WIDTH/2,touch.y-HEIGHT/2
local q,r = hs:axial(x,y)
if not hs:get(q,r) then
if touch.state == BEGAN and FILL then
hs:range(q,r,RANGE):each(add)
elseif touch.state == BEGAN and FOV then
hs:fov(q,r,RANGE):each(add)
elseif touch.state == BEGAN and LINE then
hs:line(0,0,q,r, function (lq,lr)
hs:set(lq,lr,color(200))
end)
elseif touch.state == BEGAN and MOVE then
local uq,ur = hs:axial(u.x,u.y)
local path = hs:search(uq,ur,q,r)
if not path then return end
u:move(hs, path)
elseif not FILL and not MOVE then
hs:set(q,r,color(math.random(60,255), 152, 33))
end
end
end
--# Hexagons
Hexagons = class()
function Hexagons:init(size)
self.size, self.tiles = size or 30, {}
end
function Hexagons:createMesh()
local vs = {}
for i=1,6 do
local a = i/6 * math.pi * 2
table.insert(vs, vec2(math.cos(a), math.sin(a)) * self.size)
end
self.hexagon = mesh()
self.hexagon.vertices = triangulate(vs)
self.hexagon.texture = readImage("Cargo Bot:Starry Background")
self.hexagon.shader = hexShader
return self
end
function Hexagons:set(q,r,keyOrValue,value)
local rs = self.tiles[q]
if not rs then rs = {}; self.tiles[q] = rs end
if value ~= nil then
local t = rs[r]
if not t then t = {}; rs[r] = t end
t[keyOrValue] = value
else
rs[r] = keyOrValue
end
return self
end
function Hexagons:get(q,r)
local rs = self.tiles[q]
return rs and rs[r]
end
function Hexagons:empty()
for q,rs in pairs(self.tiles) do
for r,v in pairs(rs) do return false end
end
return true
end
function Hexagons:sortBy(fn) self.sortFn = fn end
function Hexagons:pop()
local q,r,v
self:each(function (iq,ir,iv)
if not v or self.sortFn(iv, v) then
q,r,v = iq,ir,iv
end
end)
self:set(q,r,nil)
return q,r,v
end
function Hexagons:pos(q,r)
return self.size * 3/2 * q, self.size * math.sqrt(3) * (r + q/2)
end
function Hexagons:round(q,r,z)
local rx,ry,rz = math.floor(q+.5),math.floor(r+.5),math.floor(z+.5)
local dx,dy,dz = math.abs(rx-q),math.abs(ry-r),math.abs(rz-z)
if dx>dy and dx>dz then rx = -ry-rz
elseif dy>dz then ry = -rx-rz
else rz = -rx-ry end
return rx,ry,rz
end
function Hexagons:axial(x,y)
local q, r= 2/3*x/self.size, (math.sqrt(3)/3*y-x/3)/self.size
local z = -q-r
return self:round(q,r,z)
end
function Hexagons:each(fn)
for q,rs in pairs(self.tiles) do
for r,v in pairs(rs) do fn(q,r,v) end
end
end
function Hexagons:draw()
self:each(function (q,r,c)
pushMatrix()
translate(self:pos(q,r))
self.hexagon:setColors(c)
self.hexagon.shader.m = modelMatrix()
self.hexagon:draw()
popMatrix()
end)
end
function Hexagons:neighbors(q,r,fn)
local ns = {vec2(1,0), vec2(1,-1), vec2(0,-1),
vec2(-1,0), vec2(-1,1), vec2(0,1)}
for i,v in ipairs(ns) do fn(q+v.x,r+v.y) end
end
function Hexagons:distance(q,r,q2,r2)
local z,z2 = -q-r,-q2-r2
return math.max(math.abs(q-q2),math.abs(r-r2),math.abs(z-z2))
end
function Hexagons:line(q,r,q2,r2,fn)
local a,b = vec3(q,r,-q-r),vec3(q2,r2,-q2-r2)
local d = self:distance(q,r,q2,r2)
for i=0,d do
local p = a*(1-i/d) + b*i/d
fn(self:round(p.x,p.y,p.z))
end
end
function Hexagons:range(q,r,n)
local h, added = Hexagons():set(q,r,0), true
while added do
added = false
h:each(function (q,r,d)
if d == n then return end
h:neighbors(q,r, function (nq,nr)
if not self:get(nq,nr) then
local nd = h:get(nq,nr)
if not nd or nd > d+1 then
h:set(nq,nr,d+1)
added = true
end
end
end)
end)
end
return h
end
function Hexagons:fov(q,r,n)
local h = Hexagons()
self:range(q,r,n):each(function (q2,r2,d)
local add = true
self:line(q,r,q2,r2, function (lq,lr)
if self:get(lq,lr) then add = false end
end)
if add then h:set(q2,r2,d) end
end)
return h
end
function Hexagons:search(q,r,q2,r2)
local sv, path = {cost=0,rank=0,q=q,r=r}, {}
local open, closed = Hexagons():set(q,r,sv), Hexagons()
open:sortBy(function (a,b) return a.rank < b.rank end)
while not open:empty() do
local cq,cr,cv = open:pop()
if q2 == cq and r2 == cr then
while cv do
table.insert(path, 1, vec2(cv.q,cv.r))
cv = cv.parent
end
return path
end
closed:set(cq,cr,true)
self:neighbors(cq,cr,function (nq,nr)
if not self:get(nq,nr) then
local cost = cv.cost + 1
local t = open:get(nq,nr)
if t and cost < t.cost then
open:set(nq, nr, nil)
elseif not t and not closed:get(nq,nr) then
open:set(nq,nr,{
q=nq, r=nr,
cost=cost, parent=cv,
rank=cost + self:distance(nq,nr,q2,r2)
})
end
end
end)
end
end
--# Unit
Unit = class()
function Unit:init(x,y)
self.x,self.y = x,y
end
function Unit:draw()
rectMode(CENTER)
fill(52, 52, 52, 255)
rect(self.x,self.y,8,16)
fill(211, 211, 211, 255)
rect(self.x-2,self.y+1,8,16)
end
function Unit:move(hs, path)
local i = 0
function m()
i = i + 1
if not path[i] then return end
local x,y = hs:pos(path[i].x,path[i].y)
tween(.2, self, {x=x,y=y}, tween.easing.linear, m)
end
m()
end
--# Shader
hexShader = shader([[
uniform mat4 modelViewProjection;
uniform mat4 m;
attribute vec4 position;
attribute vec4 color;
varying lowp vec4 vColor;
varying highp vec2 vTexCoord;
void main() {
vColor = color;
vTexCoord = (m*normalize(position)).xy*.5;
gl_Position = modelViewProjection * position;
}
]], [[
uniform lowp sampler2D texture;
varying lowp vec4 vColor;
varying highp vec2 vTexCoord;
void main() {
lowp vec4 res = texture2D(texture, vTexCoord);
gl_FragColor = res * vColor;
}
]])
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment