--!strict
-- src/Client/Systems/FlightSystem.lua
local RunService = game:GetService("RunService")
local UserInputService = game:GetService("UserInputService")
type FlightState = {
Velocity: Vector3,
Acceleration: Vector3,
Wind: {
Direction: Vector3,
Strength: number,
},
Altitude: {
Target: number,
Smoothness: number,
},
Thrust: {
Power: number,
MaxSpeed: number,
},
Drag: number,
}
type InputState = {
Thrust: number, -- 0.0〜1.0
}
local FlightSystem = {}
FlightSystem.__index = FlightSystem
-- ユーティリティ:ベクトルを最大長でクランプ
local function clampMagnitude(v: Vector3, maxLen: number): Vector3
local mag = v.Magnitude
if mag > maxLen then
return v.Unit * maxLen
end
return v
end
-- コンストラクタ
function FlightSystem.new(player: Player)
local self = setmetatable({}, FlightSystem)
self.Player = player
self.Character = player.Character or player.CharacterAdded:Wait()
self.RootPart = self.Character:WaitForChild("HumanoidRootPart") :: BasePart
self.Humanoid = self.Character:WaitForChild("Humanoid") :: Humanoid
-- 飛行用に Humanoid の制御を弱める(必要に応じて調整)
self.Humanoid.PlatformStand = true
self.State = {
Velocity = Vector3.new(),
Acceleration = Vector3.new(),
Wind = {
Direction = Vector3.new(1, 0, 0),
Strength = 0.0,
},
Altitude = {
Target = self.RootPart.Position.Y + 20,
Smoothness = 0.1,
},
Thrust = {
Power = 80,
MaxSpeed = 140,
},
Drag = 0.05,
} :: FlightState
self.Input = {
Thrust = 0.0,
} :: InputState
self._connInputBegan = UserInputService.InputBegan:Connect(function(input, processed)
if processed then
return
end
self:_onInputBegan(input)
end)
self._connInputEnded = UserInputService.InputEnded:Connect(function(input, processed)
if processed then
return
end
self:_onInputEnded(input)
end)
self._connStepped = RunService.RenderStepped:Connect(function(dt)
self:Update(dt)
end)
return self
end
-- 入力処理(例:Space で推力オン)
function FlightSystem:_onInputBegan(input: InputObject)
if input.KeyCode == Enum.KeyCode.Space then
self.Input.Thrust = 1.0
end
end
function FlightSystem:_onInputEnded(input: InputObject)
if input.KeyCode == Enum.KeyCode.Space then
self.Input.Thrust = 0.0
end
end
-- 外部 API:風向き設定
function FlightSystem:SetWindDirection(dir: Vector3)
if dir.Magnitude > 0 then
self.State.Wind.Direction = dir.Unit
else
self.State.Wind.Direction = Vector3.new(0, 0, 0)
end
end
-- 外部 API:風の強さ設定
function FlightSystem:SetWindStrength(strength: number)
self.State.Wind.Strength = strength
end
-- 外部 API:目標高度設定
function FlightSystem:SetAltitudeTarget(height: number)
self.State.Altitude.Target = height
end
-- 外部 API:推力の強さ(0〜1)を直接指定したい場合
function FlightSystem:ApplyThrust(amount: number)
self.Input.Thrust = math.clamp(amount, 0, 1)
end
-- メイン更新処理
function FlightSystem:Update(dt: number)
local state = self.State
local root = self.RootPart
if not root or not root.Parent then
return
end
state.Acceleration = Vector3.new()
-- カメラの向きを取得(前方方向を飛行方向とする)
local camera = workspace.CurrentCamera
if not camera then
return
end
local look = camera.CFrame.LookVector
-- 1. 推力(Thrust)
if self.Input.Thrust > 0 then
local thrustForce = look * state.Thrust.Power * self.Input.Thrust
state.Acceleration += thrustForce
end
-- 2. 滑空(Glide)=重力の一部だけ適用
local glideForce = Vector3.new(0, -workspace.Gravity * 0.3, 0)
state.Acceleration += glideForce
-- 3. 風の影響(WindInfluence)
local windForce = state.Wind.Direction * state.Wind.Strength
state.Acceleration += windForce
-- 4. 高度制御(AltitudeControl)
local currentY = root.Position.Y
local diff = state.Altitude.Target - currentY
local altitudeForce = Vector3.new(0, diff * state.Altitude.Smoothness, 0)
state.Acceleration += altitudeForce
-- 5. 速度更新
state.Velocity += state.Acceleration * dt
-- Drag:Lerp で徐々に減速
state.Velocity = state.Velocity:Lerp(Vector3.new(), state.Drag)
-- 最大速度制限
state.Velocity = clampMagnitude(state.Velocity, state.Thrust.MaxSpeed)
-- 6. 位置更新
-- CFrame にベクトルを足すとその方向に平行移動
root.CFrame = root.CFrame + state.Velocity * dt
end
-- クリーンアップ
function FlightSystem:Destroy()
if self._connInputBegan then
self._connInputBegan:Disconnect()
end
if self._connInputEnded then
self._connInputEnded:Disconnect()
end
if self._connStepped then
self._connStepped:Disconnect()
end
if self.Humanoid then
self.Humanoid.PlatformStand = false
end
end
return FlightSystem
使い方(Client 側)
-- 例: src/Client/Controllers/PlayerController.lua
local Players = game:GetService("Players")
local FlightSystem = require(path.to.FlightSystem)
local player = Players.LocalPlayer
local flight = FlightSystem.new(player)
-- 風や高度を外部から制御したいとき
flight:SetWindDirection(Vector3.new(1, 0, 0))
flight:SetWindStrength(0.8)
flight:SetAltitudeTarget(80)
-- 不要になったら
-- flight:Destroy()
このまま ModuleScript として貼れば、
「Space キーで前方に推力をかけつつ、
滑空+風+高度制御を併用した空中戦の物理レイヤー」が動きます。
次にやるなら:
- 敵(巨大蚊)の FlightSystem 版(AI 用)
- BowController と組み合わせた空中射撃
- FlightCarrierService との連携(高度ターゲット=空母周りに固定)
どこを続きで詰めたいか教えてください。