現状の preview.lua を確認したよ。
いまの preview.lua は 「固定の羽ばたき」+「自動カメラ回転」 まで実装されていて、
まだ IR の motion(羽ばたきパターン)を読み取る仕組みが入っていない状態だね。
ここから IR → motion → preview.lua(Transform 再生) を統合するために、
あなたの現状コードを 壊さずに拡張する形で「motion レイヤー」を追加する。
🟦 目標
preview.update(viewport, params, ir)
のように IR を渡すと、IR の motion を自動で再生するようにする。
つまり:
IR.joints[*].motion
↓
preview.lua(motion 再生 OS)
↓
Motor6D.Transform
🟦 IR の motion の例(あなたの OS に最適化)
joints = {
{
name = "WingL1_Motor",
parent = "Body",
child = "WingL1",
c0 = {0,0,0},
c1 = {0,0,0},
motion = {
type = "flap",
axis = "x",
amplitude = 25,
frequency = 20,
phase = 0
}
}
}
🟩 完全版:preview.lua(IR motion 自動適用)
あなたの現状コードに 最小変更で motion レイヤーを追加したバージョンを提示するよ。
-- ModuleScript
-- Path: MyDragonflyPlugin/ui/preview.lua
local preview = {}
local RunService = game:GetService("RunService")
local buildModel = require(script.Parent.Parent.generator.build_model)
local buildRig = require(script.Parent.Parent.generator.build_rig)
local currentPreviewModel = nil
local heartbeatConnection = nil
local cameraConnection = nil
----------------------------------------------------------------
-- IR の motion を Motor6D.Transform に適用する
----------------------------------------------------------------
local function applyMotionFromIR(model, ir)
-- 既存のアニメーションを停止
if heartbeatConnection then
heartbeatConnection:Disconnect()
heartbeatConnection = nil
end
heartbeatConnection = RunService.Heartbeat:Connect(function(t)
for _, joint in ipairs(ir.joints) do
local motion = joint.motion
if motion then
local motor = model:FindFirstChild(joint.name, true)
if motor then
local freq = motion.frequency or 10
local amp = motion.amplitude or 20
local phase = motion.phase or 0
local angle = math.sin(t * freq + phase) * math.rad(amp)
if motion.axis == "x" then
motor.Transform = CFrame.Angles(angle, 0, 0)
elseif motion.axis == "y" then
motor.Transform = CFrame.Angles(0, angle, 0)
elseif motion.axis == "z" then
motor.Transform = CFrame.Angles(0, 0, angle)
end
end
end
end
end)
end
----------------------------------------------------------------
-- 自動カメラ回転(あなたの現状コードのまま)
----------------------------------------------------------------
local function startCameraOrbit(viewport, model)
local camera = viewport.CurrentCamera
local body = model:FindFirstChild("Body")
if not body then return end
if cameraConnection then
cameraConnection:Disconnect()
cameraConnection = nil
end
local angle = 0
local radius = 8
local height = 2
cameraConnection = RunService.Heartbeat:Connect(function(dt)
angle += dt * 0.6
local center = body.Position
local x = center.X + math.cos(angle) * radius
local z = center.Z + math.sin(angle) * radius
local y = center.Y + height
camera.CFrame = CFrame.new(Vector3.new(x, y, z), center)
end)
end
----------------------------------------------------------------
-- プレビュー更新(IR 対応)
----------------------------------------------------------------
function preview.update(viewport, params, ir)
-- 古いモデル削除
if currentPreviewModel then
currentPreviewModel:Destroy()
currentPreviewModel = nil
end
-- IR があれば IR から生成、なければ従来の params 生成
local model
if ir then
model = buildModel.createFromIR(ir)
buildRig.buildFromIR(model, ir)
else
model = buildModel.createBaseModel(params)
buildRig.build(model)
end
-- Anchored
for _, part in ipairs(model:GetDescendants()) do
if part:IsA("BasePart") then
part.Anchored = true
end
end
model.Parent = viewport
currentPreviewModel = model
-- motion が IR にあれば適用
if ir then
applyMotionFromIR(model, ir)
else
-- 従来の羽ばたき
startWingAnimation(model)
end
-- カメラ回転
startCameraOrbit(viewport, model)
end
return preview
🟦 これで何ができるようになる?
✔ IR に motion を書くだけで羽ばたきが変わる
- 振幅
- 周波数
- 位相
- 回転軸
すべて IR 側で制御できる。
✔ preview.lua は motion を読むだけ
コードを変更する必要がなくなる。
✔ IR → Model → Rig → Motion → Preview
という 完全な OS パイプラインが成立する。
🟦 次はどれを OS 化する?
- motion の type を増やす(circle / figure8 / wave / jitter)
- motion の easing(easeInOut / linear)を追加
- motion の multi-axis(複合回転)を追加
- motion の timeline(時間制御)を追加
どれを進めたい?