Created
February 6, 2014 15:54
-
-
Save tnlogy/8846921 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
--# 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