summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorubq323 <ubq323@ubq323.website>2023-02-13 01:18:57 +0000
committerubq323 <ubq323@ubq323.website>2023-02-13 01:18:57 +0000
commit0abc0b9b7928cd72b1c92b3af9f30674397013d1 (patch)
treeeda521067eb30240aa17a8cac6dfe74a361ea671
parent24b06ededb117588adab64af1c60a0c53e2a8feb (diff)
add collisions and sliding for player movement
-rw-r--r--client/drawing.lua2
-rw-r--r--client/main.lua21
-rw-r--r--client/movement.lua92
-rw-r--r--common/coords.lua10
4 files changed, 117 insertions, 8 deletions
diff --git a/client/drawing.lua b/client/drawing.lua
index 5334a93..31c5893 100644
--- a/client/drawing.lua
+++ b/client/drawing.lua
@@ -93,7 +93,7 @@ local function draw_map(camera,map)
end
end
- if _G.debugmode then
+ if false and _G.debugmode then
love.graphics.setColor(0,1,0)
local function p(q,r) return coords.Hex:make(q,r):to_pos() end
diff --git a/client/main.lua b/client/main.lua
index d58551e..4941814 100644
--- a/client/main.lua
+++ b/client/main.lua
@@ -15,6 +15,7 @@ local camera = require"camera".Camera:make()
local Chunk = require"common.chunk".Chunk
local util = require"util"
local Map = require"common.map".Map
+local movement = require"movement"
-- local pprint=require"common.pprint"
-- pprint.setup{show_all=true}
@@ -56,26 +57,26 @@ local function update_local_player(pl,dt)
local dy = kd"s"-kd"w"
if dx == 0 and dy == 0 then
- pl.pos_dirty = false
return
end
if dx ~= 0 and dy ~= 0 then
+ -- 60degrees direction, to follow hex grid
+ -- instead of 45degrees diagonal
dx = dx * 0.5
dy = dy * (math.sqrt(3)/2)
end
- pl.pos.x = pl.pos.x + SPEED * dt * dx
- pl.pos.y = pl.pos.y + SPEED * dt * dy
+ local try_pos = Pos:make(pl.pos.x + SPEED*dt*dx, pl.pos.y + SPEED*dt*dy)
+ pl.pos = movement.collide_with_terrain(pl.pos,try_pos,map)
pl.pos_dirty = true
-
-
end
local function sync_local_player(pl)
-- send updated info about local player to server
if pl.pos_dirty then
peer:send(json.encode{t="ppos",x=pl.pos.x,y=pl.pos.y})
+ pl.pos_dirty = false
end
end
@@ -95,9 +96,7 @@ function love.update(dt)
local mh = camera:screen_to_world(Pos:make(love.mouse.getPosition())):to_hex():round()
if false== map:at(mh) and love.mouse.isDown(1) then
- print("place at",mh)
map:set_at(mh,true)
- -- print(mh,true)
send_settile(mh,true)
elseif map:at(mh) and love.mouse.isDown(2) then
map:set_at(mh,false)
@@ -185,6 +184,8 @@ function love.draw()
local wm = camera:screen_to_world(sm)
local hm = wm:to_hex()
+ sdf_d,sdf_gx,sdf_gy = movement.hex_sdgf(wm, coords.Hex:make(3,3))
+
love.graphics.origin()
if _G.debugmode and local_player then
util.print_good({
@@ -198,7 +199,13 @@ function love.draw()
"voob "..tostring(camera.zoom),
"-",
"fps "..tostring(love.timer.getFPS()),
+ "-",
+ "sdf "..tostring(sdf_d)
+
},10,10)
+ love.graphics.setColor(0,1,0)
+ love.graphics.setLineWidth(5)
+ love.graphics.line(sm.x,sm.y, sm.x+50*sdf_gx, sm.y+50*sdf_gy)
end
end
diff --git a/client/movement.lua b/client/movement.lua
new file mode 100644
index 0000000..78af5f0
--- /dev/null
+++ b/client/movement.lua
@@ -0,0 +1,92 @@
+local Pos = require"common.coords".Pos
+
+local function sign(x)
+ if x == 0 then return 0
+ elseif x < 0 then return -1
+ elseif x > 0 then return 1
+ end
+end
+local function clamp(x,minv,maxv)
+ return math.min(math.max(x,minv),maxv)
+end
+
+
+
+-- https://iquilezles.org/articles/distgradfunctions2d/
+local function iqz_hex_sdgf(px,py, r)
+ local kx,ky,kz = -0.866025404,0.5,0.577350269
+ local sx,sy = sign(px),sign(py)
+ px = math.abs(px)
+ py = math.abs(py)
+ local w = kx*px+ky*py
+
+ local _1 = 2*math.min(w,0)
+ px = px - _1*kx
+ py = py - _1*ky
+
+ px = px - clamp(px,-kz*r,kz*r)
+ py = py - r
+
+ d = math.sqrt(px*px+py*py)*sign(py)
+
+ local gx,gy
+ if w<0 then
+ gx = -ky*px - kx*py
+ gy = -kx*px + ky*py
+ else
+ gx,gy = px,py
+ end
+
+ -- dist, gradx, grady
+ return d, sx*gx/d, sy*gy/d
+
+end
+
+
+-- rotate by 30 degrees
+local c30,s30 = math.cos(math.rad(30)), math.sin(math.rad(30))
+local function t_in(x,y) return c30*x-s30*y, s30*x+c30*y end
+local function t_out(x,y) return c30*x+s30*y, -s30*x+c30*y end
+
+-- above sdf has flat top not pointy-top hexagons
+-- so need to rotate
+-- also, 'r' parameter in the above seems to be distance to side
+-- but in our unit system, 1 unit is distance to vertex
+-- conversion factor between these is also cos(30deg)
+-- this is distance to hex at 0,0
+local function hex_sdgf_00(pos)
+ local tpx,tpy = t_in(pos.x,pos.y)
+ local d,gx,gy = iqz_hex_sdgf(tpx,tpy,c30)
+ return d, t_out(gx,gy)
+end
+
+local function hex_sdgf(pos, hex)
+ return hex_sdgf_00(pos-hex:to_pos())
+end
+
+local PLAYER_SIZE = 0.35
+local function collide_with_terrain(old_pos, try_pos, map, tries_remaining)
+ tries_remaining = tries_remaining or 3
+ if tries_remaining <= 0 then return old_pos end
+ local try_h = try_pos:to_hex():round()
+ for near_h in try_h:iter_neighbours(1) do
+ local tile = map:at(near_h)
+ if tile then
+ local d,gx,gy = hex_sdgf(try_pos, near_h)
+ if d < PLAYER_SIZE then
+ local push_dist = PLAYER_SIZE - d
+ local push_dir = Pos:make(gx,gy)
+ local new_try_pos = try_pos + (push_dist*push_dir)
+ return collide_with_terrain(old_pos,new_try_pos,map,tries_remaining-1)
+ end
+ end
+ end
+
+ return try_pos
+end
+
+
+return {
+ collide_with_terrain = collide_with_terrain,
+ hex_sdgf=hex_sdgf
+}
diff --git a/common/coords.lua b/common/coords.lua
index 49c2bf2..420b287 100644
--- a/common/coords.lua
+++ b/common/coords.lua
@@ -75,6 +75,16 @@ function Hex.offset_in_chunk(self)
local cp,offs = self:chunk_and_offset()
return offs
end
+function Hex.iter_neighbours(self,radius)
+ assert(radius > 0,"radius must be at least 1")
+ return coroutine.wrap(function()
+ for q = -radius,radius do
+ for r = math.max(-radius,-q-radius), math.min(radius,-q+radius) do
+ coroutine.yield(self+Hex:make(q,r))
+ end
+ end
+ end)
+end
function Hex.__add(self,other) return Hex:make(self.q+other.q, self.r+other.r, self.s+other.s) end
function Hex.__sub(self,other) return Hex:make(self.q-other.q, self.r-other.r, self.s-other.s) end
function Hex.__tostring(self) return string.format("H(%.2f,%.2f)",self.q,self.r) end