インディーゲーム開発の道のり:Flying Gorillaが400万ダウンロードに至るまで
こんにちは、Flying Gorilla StudiosのKazutaka Tottoriです。今日は、私たちの代表作『Flying Goril...
こんにちは、Flying Gorilla StudiosのKazutaka Tottoriです。今回は、Unityで開発してきた私たちがRobloxプラットフォームに挑戦して学んだことを共有します。『Flying Gorilla Obby』の開発は、予想以上に挑戦的で、そして楽しい経験でした。
まず、なぜ私たちがRobloxに参入したのか。理由は3つ:
でも正直、最初は戸惑いました。「え、Luaって何…?」
UnityのC#に慣れていた私にとって、Luaは最初、少し原始的に感じました。でも使ってみると…
public class PlayerController : MonoBehaviour {
private float speed = 10f;
private Rigidbody rb;
void Start() {
rb = GetComponent<Rigidbody>();
}
void Update() {
float horizontal = Input.GetAxis("Horizontal");
float vertical = Input.GetAxis("Vertical");
Vector3 movement = new Vector3(horizontal, 0, vertical);
rb.MovePosition(transform.position + movement * speed * Time.deltaTime);
}
}
local player = script.Parent
local humanoid = player:WaitForChild("Humanoid")
local speed = 16 -- Humanoidのデフォルト速度
local function onCharacterAdded(character)
humanoid.WalkSpeed = speed
end
player.CharacterAdded:Connect(onCharacterAdded)
シンプル!最初は「機能が少ない」と思ったけど、実は「必要十分」でした。
Roblox Studioは、Unityとは全く違うアプローチです。
Unityの「GameObject」に相当するのが「Part」。でも、こっちの方が直感的かも。
-- パートを作成
local part = Instance.new("Part")
part.Size = Vector3.new(4, 1, 4)
part.Position = Vector3.new(0, 10, 0)
part.BrickColor = BrickColor.new("Bright red")
part.Parent = workspace
-- 触れたらジャンプ
part.Touched:Connect(function(hit)
local humanoid = hit.Parent:FindFirstChild("Humanoid")
if humanoid then
humanoid.Jump = true
end
end)
Robloxのサービスシステムは最初は戸惑いましたが、慣れると整理されていて使いやすい:
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local TweenService = game:GetService("TweenService")
これが最大の違い!Unityでマルチプレイヤーを実装するのは大変ですが、Robloxではデフォルト。
-- ServerScriptService内のスクリプト(サーバー側)
local Players = game:GetService("Players")
Players.PlayerAdded:Connect(function(player)
print(player.Name .. " joined the game!")
-- プレイヤーにコインを与える
local leaderstats = Instance.new("Folder")
leaderstats.Name = "leaderstats"
leaderstats.Parent = player
local coins = Instance.new("IntValue")
coins.Name = "Coins"
coins.Value = 0
coins.Parent = leaderstats
end)
-- StarterPlayer > StarterPlayerScripts内のスクリプト(クライアント側)
local player = game.Players.LocalPlayer
local gui = player:WaitForChild("PlayerGui")
-- ローカルでのみUIを更新
-- サーバー側
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local remoteEvent = Instance.new("RemoteEvent")
remoteEvent.Name = "CoinCollected"
remoteEvent.Parent = ReplicatedStorage
remoteEvent.OnServerEvent:Connect(function(player, coinValue)
-- 検証重要!クライアントを信用しない
if coinValue > 0 and coinValue <= 10 then
player.leaderstats.Coins.Value += coinValue
end
end)
-- StreamingEnabled を使用
workspace.StreamingEnabled = true
workspace.StreamingMinRadius = 64
workspace.StreamingTargetRadius = 128
-- パートの最適化
for _, part in pairs(workspace:GetDescendants()) do
if part:IsA("BasePart") then
-- 不要な場合はCanCollideをfalseに
if part.Name == "Decoration" then
part.CanCollide = false
part.CanQuery = false
part.CanTouch = false
end
end
end
Robloxコミュニティの協力的な雰囲気に驚きました。
問題にぶつかったとき、DevForumで質問すると数分で回答が!
-- コミュニティから教わった便利な関数
local function waitForChild(parent, childName, timeout)
local child = parent:FindFirstChild(childName)
local startTime = tick()
timeout = timeout or 5
while not child and tick() - startTime < timeout do
child = parent:FindFirstChild(childName)
wait(0.1)
end
return child
end
多くの開発者がコードを共有していて、学習が加速しました。
local TweenService = game:GetService("TweenService")
local function createMovingPlatform(platform)
local startPos = platform.Position
local endPos = startPos + Vector3.new(20, 0, 0)
local tweenInfo = TweenInfo.new(
3, -- 時間
Enum.EasingStyle.Sine,
Enum.EasingDirection.InOut,
-1, -- 無限ループ
true -- 往復
)
local tween = TweenService:Create(
platform,
tweenInfo,
{Position = endPos}
)
tween:Play()
end
local function activateSuperJump(character)
local humanoid = character:FindFirstChild("Humanoid")
if not humanoid then return end
local originalJumpPower = humanoid.JumpPower
humanoid.JumpPower = originalJumpPower * 2
-- エフェクト追加
local effect = script.JumpEffect:Clone()
effect.Parent = character.HumanoidRootPart
wait(10) -- 10秒間有効
humanoid.JumpPower = originalJumpPower
effect:Destroy()
end
Obbyに「レベルエディタ」機能を追加したら、プレイヤーが作ったステージの方が面白いものも!
ただクリアするだけでなく、「友達と一緒に」が重要。協力ギミックが大人気。
Robloxは更新が即座に反映。これは開発サイクルを大幅に短縮。
Flying Gorilla Obby の現在の統計:
UnityとRoblox、どちらが優れているという話ではありません。それぞれに強みがあります:
私たちは今、両方のプラットフォームで開発を続けています。Flying GorillaはUnityで、Flying Gorilla ObbyはRobloxで。
それぞれのプラットフォームの特性を理解し、適材適所で使い分けることが重要だと学びました。
次回は「Flying Gorilla Obbyのレベルデザイン哲学」について書く予定です。「難しいけど理不尽じゃない」バランスの取り方とは?
それまで、Happy Developing! 🦍🎮
Kazutaka Tottori
Founder & Lead Developer, Flying Gorilla Studios
P.S. Robloxで「oof」音が変わったときの衝撃は忘れられません…懐かしい「oof」よ、永遠に。
ご意見、ご感想、お仕事のご依頼など、お気軽にお問い合わせください。