この記事はアドカレに参加しています。
ベジェ曲線で遊ぶ
多くのソフトでは曲線を描画するのにベジェ曲線というものが使われたりします。三次関数とか制御点とか、めんどくさい言葉が出てきますが、実装はとても簡単です。
理論
なんとなくでも知っておくと楽しいです。
ベジェ曲線の詳しい原理は以下のサイトなどが参考になります。
ベジェ曲線
一から学ぶベジェ曲線
実装
以下は4点をもとにベジェ曲線を描画するスクリプトです。
核はOrbitという関数で、t(0~1)に対する(x,y)を返します。
--[[
ベジェ軌道_M.obj
単純なベジェ軌道です。
]]
--dialog:座標,pos={};
--アンカー
obj.setanchor("pos",2,"xyz")
--p1~p4に、x2,y2,x3,y3を代入(x1,y1=0,0とx2,y2=1,1のような状態と仮定)
local p1,p2,p3,p4=(pos[1]+50)/100,(-pos[2]+50)/100,(pos[4]+50)/100,(-pos[5]+50)/100
--[[ティムさんの関数
時間t(0~1)と、x2,y2,x3,y3からx,y座標を求める。]]
local Orbit=function(t,x1,y1,x2,y2)
local s=1-t
x1=(3*s*s*x1+(3*s*x2+t)*t)*t
y1=(3*s*s*y1+(3*s*y2+t)*t)*t
return x1,y1
end
--背景枠
obj.setoption("drawtarget","tempbuffer",106,106)
obj.load("figure","四角形",0x39352e,106,3)
obj.draw(0,0,0,1,0.7)
--背景
obj.setoption("drawtarget","tempbuffer")
obj.load("figure","四角形",0x373737,100)
obj.draw(0,0,0,1,0.5)
--グラフ
local x,y
for i=0,40 do
obj.setoption("drawtarget","tempbuffer")
obj.load("figure","円",0x55a75b,4)
x,y=Orbit(i/40,p1,p2,p3,p4)
obj.draw(x*100-50,-y*100+50)
end
--現在位置
x,y=Orbit(obj.time/obj.totaltime,p1,p2,p3,p4)
obj.setoption("drawtarget","tempbuffer")
obj.load("figure","円",0xe0d95a,10)
obj.draw(x*100-50,-y*100+50)
--アンカー1
obj.setoption("drawtarget","tempbuffer")
obj.load("figure","円",0x25aeff,10)
obj.draw(pos[1],pos[2])
--アンカー2
obj.setoption("drawtarget","tempbuffer")
obj.load("figure","円",0x25aeff,10)
obj.draw(pos[4],pos[5])
--仮想バッファをロード
obj.load("tempbuffer")
--[[とりあえず、Bのグローバル変数に流す。
個人で使うぶんにはこれでよいが、
スクリプトを配布する際は誰も使わないグローバル変数の名前にする。
あと、イージングスクリプトは作らないほうがいいかも。
https://scrapbox.io/ePi5131/【やめてくれ】「イージングを使いやすくするため」に新しくトラックバースクリプトを起こすな
余談ですが、ベジェ系ではこれ好き
https://youtu.be/B9qRuz_gBgI ]]
B=y
実装2
テキストボックスに貼り付けて使います。
xy座標が入った一次元配列a(グロ変)からベジェ曲線を描きます。
<?
local Orbit=function(t,x1,y1,x2,y2)
local s=1-t
x1=(3*s*s*x1+(3*s*x2+t)*t)*t
y1=(3*s*s*y1+(3*s*y2+t)*t)*t
return x1,y1
end
local function draw_Line(a,b,c,d)
b[1]=b[1]-a[1]
c[1]=c[1]-a[1]
b[2]=b[2]-a[2]
c[2]=c[2]-a[2]
b[1]=b[1]/(d[1]-a[1])
c[1]=c[1]/(d[1]-a[1])
b[2]=b[2]/(d[2]-a[2])
c[2]=c[2]/(d[2]-a[2])
local n=100--[[精度(てきとうなので、本当は計算して調整したほうがいいみたい]]
for i=0,n do
local x,y
x,y=Orbit(i/n,b[1],b[2],c[1],c[2])
x=x*(d[1]-a[1])+a[1]
y=y*(d[2]-a[2])+a[2]
obj.load("figure","円",0xf9de2f,10)
obj.draw(x,y)
end
end
local p={}
for i=0,#a/2-1 do
p[i+1]={a[i*2+1],a[i*2+2]}
end
local e=#p
local c=1
while 1 do
if(c+3>#p)then break end
draw_Line(p[c],p[c+1],p[c+2],p[c+3])
c=c+3
end
?>
※(d[1]-a[1])の結果が0になったとき、0除算になってしまうため正常に描画されません。これを防ぐにはgithubにあるコードのように0の場合に小さい値(0.001とか)を足して近似的に求めるなどの方法が考えられます。
おわりに
なんだか、discordにあるコードをそのまま貼り付けただけな気がします。手抜き記事ですね!(全部そう