2019/12/25(水) [n年前の日記]
#1 [love2d] love2dで多関節
love2d を使って、多関節の触手っぽい動きを書いてみたり。動作確認環境は、Windows10 x64 1909 + love2d 11.3。
こんな感じになった。マウスカーソルの位置で曲がり方が変わるようにしてみたり。
こんな感じになった。マウスカーソルの位置で曲がり方が変わるようにしてみたり。
◎ ソース。 :
_conf.lua
_main.lua
動作に必要な画像は以下。CC0 / Public Domain ってことで。

_circle02_64x64_take1_05_5bit32col_edit.png
この3つのファイル、conf.lua、main.lua、*.png を適当なフォルダに置いて、「love フォルダ名」で実行できる。
function love.conf(t) t.version = "11.3" -- love2d version t.window.title = "Arm - love2d" t.window.vsync = 1 t.window.width = 1280 t.window.height = 720 -- t.window.fullscreen = true -- t.window.fullscreentype = "exclusive" end
_main.lua
-- Arm on love2d
function love.load()
love.graphics.setDefaultFilter("nearest", "nearest")
img = love.graphics.newImage("circle02_64x64_take1_05_5bit32col_edit.png")
scrw = love.graphics.getWidth()
scrh = love.graphics.getHeight()
bx = scrw / 2
by = scrh / 2
angles = {}
pos_buf = {}
for i = 1, 16 do
angles[i] = 0
pos_buf[i] = {bx, by}
end
ang = 0
a0 = 15
a1 = 30
end
function love.update(dt)
ang = ang + 90 * dt
mx, my = love.mouse.getPosition()
a0 = 45 * (mx - (scrw / 2)) / (scrw / 2)
a1 = 45 * (my - (scrh / 2)) / (scrh / 2)
-- angles[1] = 0
angles[1] = ang
for i = 2, #angles do
-- angles[i] = a1 + a1 * math.sin(math.rad(a0 * (i - 2)))
angles[i] = a1 * math.sin(math.rad(ang * 0.75 + (i - 1) * a0))
end
local x = pos_buf[1][1]
local y = pos_buf[1][2]
local a = angles[1]
-- local distance = 30
local distance = 24 + 12 * math.cos(math.rad(ang * 1.4))
for i = 2, #angles do
a = a + angles[i]
x = x + distance * math.cos(math.rad(a))
y = y + distance * math.sin(math.rad(a))
pos_buf[i] = {x, y}
end
end
function love.draw()
-- fill window background
love.graphics.clear(0.4, 0.7, 0.8, 1.0)
-- draw arm
local ox, oy = img:getWidth() / 2, img:getHeight() / 2
love.graphics.setColor(1.0, 1.0, 1.0, 1.0)
for i = 1, #pos_buf do
local px = pos_buf[i][1]
local py = pos_buf[i][2]
love.graphics.draw(img, px, py, 0, 1.0, 1.0, ox, oy)
end
love.graphics.print("a0=" .. tostring(a0), 2, 16)
love.graphics.print("a1=" .. tostring(a1), 2, 32)
-- draw FPS txet
love.graphics.print("FPS: " .. tostring(love.timer.getFPS()), 2, 2)
end
function love.keypressed(key, isrepeat)
if key == "escape" then
-- ESC key to exit
love.event.quit()
end
end
動作に必要な画像は以下。CC0 / Public Domain ってことで。

この3つのファイル、conf.lua、main.lua、*.png を適当なフォルダに置いて、「love フォルダ名」で実行できる。
◎ 解説。 :
仕組みは…。DXRuby で多関節のソレを書いた際の記事が参考になるはず。アレと同じ仕組みだし。
_mieki256's diary - DXRubyで例の多関節を実験
各関節が角度を持っていて、親の角度+自分の持ってる角度を使って位置を決めていく、という説明でいいのかな。
余談。class を作って書いたほうがいいのかなと思ったけれど、この程度の処理なら、各関節の角度を保持しておく配列さえあれば動かせるなと思えてきたので、だらだらと書いてしまったり。
_mieki256's diary - DXRubyで例の多関節を実験
各関節が角度を持っていて、親の角度+自分の持ってる角度を使って位置を決めていく、という説明でいいのかな。
余談。class を作って書いたほうがいいのかなと思ったけれど、この程度の処理なら、各関節の角度を保持しておく配列さえあれば動かせるなと思えてきたので、だらだらと書いてしまったり。
[ ツッコむ ]
#2 [love2d] love2dでcubic bezierの触手を描画
love2d を使って、cubic bezier 曲線の触手を描画してみたり。動作確認環境は、Windows10 x64 1909 + love2d 11.3。
こんな感じになった。
以下のページを参考にさせてもらいました。ありがたや。
_Flashゲーム講座&ASサンプル集【曲線について】
こんな感じになった。
- マウスカーソル座標が触手の先端になる。
- Cキーを押すと、制御点を表示できる。
以下のページを参考にさせてもらいました。ありがたや。
_Flashゲーム講座&ASサンプル集【曲線について】
◎ ソース。 :
_conf.lua
_main.lua
動作に必要な画像は以下。CC0 / Public Domain ってことで。

_circle02_64x64_take1_05_5bit32col_edit.png
conf.lua、main.lua、*.png を適当なフォルダに置いて、「love フォルダ名」で実行できる。
余談。昔のCPUは、掛け算(乗算)を使うとクロック数が増えるし、固定小数点で演算してたので桁合わせが面倒だしで、掛け算を使いまくりのこういった処理は、ちと気分的に避けがちだったのだけど。今のCPUなら楽勝だろうなあ、と思ったので試しに書いてみたり。滑らかに動いてるし、さすがに全然余裕ですな…。
function love.conf(t) t.version = "11.3" -- love2d version t.window.title = "Cubic bezier - love2d" t.window.vsync = 1 t.window.width = 1280 t.window.height = 720 -- t.window.fullscreen = true -- t.window.fullscreentype = "exclusive" end
_main.lua
function get_cubic_bezier_point(p0x, p0y, v0x, v0y, v1x, v1y, p1x, p1y, t)
local q = 1.0 - t
local u0 = q * q * q
local u1 = 3.0 * t * q * q
local u2 = 3.0 * t * t * q
local u3 = t * t * t
local ox = u0 * p0x + u1 * v0x + u2 * v1x + u3 * p1x
local oy = u0 * p0y + u1 * v0y + u2 * v1y + u3 * p1y
return ox, oy
end
function love.load()
love.graphics.setDefaultFilter("nearest", "nearest")
img = love.graphics.newImage("circle02_64x64_take1_05_5bit32col_edit.png")
scrw = love.graphics.getWidth()
scrh = love.graphics.getHeight()
bx = scrw * 0.95
by = scrh / 2
ctrl_points = {
{100, 200},
{scrw * 0.3, scrh * 0.1},
{scrw * 0.6, scrh * 0.9},
{bx, by}
}
points = {}
ang = 0
draw_ctrl_points = false
end
function love.update(dt)
ang = ang + 180 * dt
-- set control points
mx, my = love.mouse.getPosition()
ctrl_points[1][1] = mx
ctrl_points[1][2] = my
local a0 = math.sin(math.rad(ang))
local a1 = math.sin(math.rad(ang * 0.6))
-- ctrl_points[2][1] = mx + (bx - mx) * 0.3
ctrl_points[2][2] = scrh * (a0 * 0.5 + 0.5)
-- ctrl_points[3][1] = mx + (bx - mx) * 0.6
ctrl_points[3][2] = scrh * (a1 * 0.7 + 0.5)
-- get cubic bezier points
local interpolate = 40
local spd = 1.0 / interpolate
local p0x, p0y, v0x, v0y, v1x, v1y, p1x, p1y
p0x = ctrl_points[1][1]
p0y = ctrl_points[1][2]
v0x = ctrl_points[2][1]
v0y = ctrl_points[2][2]
v1x = ctrl_points[3][1]
v1y = ctrl_points[3][2]
p1x = ctrl_points[4][1]
p1y = ctrl_points[4][2]
points = {}
local t, x, y
for t = 0, 1.0, spd do
x, y = get_cubic_bezier_point(p0x, p0y, v0x, v0y, v1x, v1y, p1x, p1y, t)
points[#points + 1] = {x, y}
end
t = 1.0
x, y = get_cubic_bezier_point(p0x, p0y, v0x, v0y, v1x, v1y, p1x, p1y, t)
points[#points + 1] = {x, y}
end
function love.draw()
-- fill window background
love.graphics.clear(0.2, 0.5, 0.6, 1.0)
-- draw arm
local ox, oy = img:getWidth() / 2, img:getHeight() / 2
love.graphics.setColor(1.0, 1.0, 1.0, 1.0)
for i = #points, 1, -1 do
local px = points[i][1]
local py = points[i][2]
love.graphics.draw(img, px, py, 0, 1.0, 1.0, ox, oy)
end
-- draw control points line
if draw_ctrl_points then
love.graphics.setColor(1.0, 1.0, 1.0, 0.7)
love.graphics.line(
ctrl_points[1][1],
ctrl_points[1][2],
ctrl_points[2][1],
ctrl_points[2][2],
ctrl_points[3][1],
ctrl_points[3][2],
ctrl_points[4][1],
ctrl_points[4][2]
)
for i = 1, 4 do
local px, py
px = ctrl_points[i][1]
py = ctrl_points[i][2]
love.graphics.circle("line", px, py, 16)
end
end
-- draw FPS
love.graphics.setColor(1.0, 1.0, 1.0, 1.0)
love.graphics.print("FPS: " .. tostring(love.timer.getFPS()), 2, 2)
love.graphics.print("C key : Draw control points", 2, 20)
end
function love.keypressed(key, isrepeat)
if key == "escape" then
-- ESC key to exit
love.event.quit()
elseif key == "c" then
draw_ctrl_points = not (draw_ctrl_points)
end
end
動作に必要な画像は以下。CC0 / Public Domain ってことで。

conf.lua、main.lua、*.png を適当なフォルダに置いて、「love フォルダ名」で実行できる。
余談。昔のCPUは、掛け算(乗算)を使うとクロック数が増えるし、固定小数点で演算してたので桁合わせが面倒だしで、掛け算を使いまくりのこういった処理は、ちと気分的に避けがちだったのだけど。今のCPUなら楽勝だろうなあ、と思ったので試しに書いてみたり。滑らかに動いてるし、さすがに全然余裕ですな…。
[ ツッコむ ]
#3 [nitijyou] 日記をアップロード
2019/12/11を最後に日記をアップロードしてなかったのでアップロード。
[ ツッコむ ]
以上、1 日分です。