ゲームデベで最適化が重要なのはなぜですか?
ゲームでは、すべてのフレームが重要です。コードの実行に時間がかかりすぎると、ゲームが「遅く」なり、FPSが低下し、アニメーションが引きつけられ、プレイヤーが否定的なレビューを書き始めます。特に、デバイスのリソースが限られているモバイルゲームの最適化は重要です。
良いニュースは、Luaはすでにかなり高速な言語であり、特にJITコンパイラLuaJITを使用していることです。しかし、スピーディなゲームをスライドショーに変える可能性のある典型的なミスがあります。
1. ローカル変数はあなたの親友です
問題: Luaのグローバル変数はローカル変数よりも遅く動作します。グローバル変数にアクセスするたびに、エンジンは特別なテーブルでそれを検索します。
悪い点:
function updatePlayer()
player.x = player.x + speed * deltaTime
player.y = player.y + gravity * deltaTime
end良い:
local function updatePlayer()
local px = player.x
local py = player.y
local spd = speed
local grav = gravity
local dt = deltaTime
px = px + spd * dt
py = py + grav * dt
player.x = px
player.y = py
endローカル変数はレジスタまたはスタックに格納され、それらへのアクセスは数倍速くなります。これは、フレームごとに呼び出される関数(update、render)にとって特に重要です。
2. 計算結果をキャッシュする
関数が同じ値を返す場合は、毎回再度呼び出さないでください。
悪い点:
function draw()
for i = 1, #enemies do
if distance(player, enemies[i]) < 100 then
drawEnemy(enemies[i])
end
end
end良い:
function draw()
local enemyCount = #enemies
local playerX, playerY = player.x, player.y
for i = 1, enemyCount do
local enemy = enemies[i]
local dx = enemy.x - playerX
local dy = enemy.y - playerY
if dx*dx + dy*dy < 10000 then -- избегаем sqrt
drawEnemy(enemy)
end
end
endここでは、敵の数、プレイヤーの座標をキャッシュし、さらに関数 distance を呼び出すのを避け、距離の平方数の比較に置き換えました。
3. ループ内でのオブジェクトの作成を避ける
新しいテーブルと行を作成するのは高価な操作です。その後、ガベージコレクターはそれらをクリーンアップするのに時間を費やします。
悪い点:
function update()
for i = 1, 1000 do
local temp = {x = 0, y = 0} -- каждый кадр 1000 новых таблиц!
processData(temp)
end
end良い:
local tempData = {x = 0, y = 0} -- создали один раз
function update()
for i = 1, 1000 do
tempData.x = 0
tempData.y = 0
processData(tempData)
end
endまたは、頻繁に作成されるエンティティ(プール、パーティクル、敵)にオブジェクトプールを使用します。
4. 文字列の正しい扱い
ループ内の .. を介した文字列の連結は、古典的なエラーです。
悪い点:
local result = ""
for i = 1, 1000 do
result = result .. tostring(i) .. "," -- O(n²) сложность!
end良い:
local parts = {}
for i = 1, 1000 do
parts[i] = tostring(i)
end
local result = table.concat(parts, ",") -- O(n) сложность5. サイクルの最適化
条件をチェックする順序が重要です。最も可能性の高い条件を最初に置いてください。
悪い点:
for i = 1, #entities do
if entities[i].isDead and entities[i].isVisible and entities[i].isEnemy then
removeEntity(entities[i])
end
end良い:
for i = 1, #entities do
local entity = entities[i]
if entity.isEnemy and entity.isVisible and entity.isDead then
removeEntity(entity)
end
end大多数のエンティティが敵でない場合、最初の isEnemy のチェックは残りの条件のチェックを節約します。

6.組み込み関数を使用する
組み込みの Lua 機能は C レベルで最適化されており、実装よりも高速に動作します。
悪い点:
function findMax(arr)
local max = arr[1]
for i = 2, #arr do
if arr[i] > max then
max = arr[i]
end
end
return max
end良い:
local max = math.max(unpack(scores)) -- для небольших массивов7. コードをプロファイリングする
盲目的に最適化しないでください!プロファイラーを使用して実際のボトルネックを見つけてください。
Love2D: 組み込みの
love.graphics.getStats()Defold: 組み込みプロファイラー
Roblox: MicroProfiler
問題は、あなたが思っているところにないことがよくあります。
8. ゲームの実践アドバイス
空間分割
すべてのオブジェクトの衝突をすべてチェックしないでください。これはO(n²)です。クアッドツリーまたはグリッドを使用します。
-- Вместо:
for i = 1, #bullets do
for j = 1, #enemies do
checkCollision(bullets[i], enemies[j])
end
end
-- Используйте пространственную сетку
local grid = createGrid(mapWidth, mapHeight, cellSize)
-- проверяйте коллизии только в соседних ячейках遅延評価
画面に表示されていないオブジェクトを更新しないでください。
function updateEnemy(enemy)
if not isOnScreen(enemy) and distanceToPlayer(enemy) > 500 then
return -- враг далеко и не виден — пропускаем
end
-- обычная логика обновления
endレンダリングのバッチ処理
エンジンがサポートしている場合は、1回の呼び出しで同様のオブジェクトを描画します。
-- Вместо 100 отдельных вызовов draw:
local batch = love.graphics.newSpriteBatch(texture, 100)
for i = 1, #sprites do
batch:add(sprites[i].quad, sprites[i].x, sprites[i].y)
end
batch:draw()最適化すべきではない場合
次の規則を覚えておいてください。 早すぎる最適化はすべての悪の根源ですまず、動作するコードを書き、次にパフォーマンスを測定し、問題がある場合にのみ、ボトルネックを最適化します。
コードの可読性は、マイクロ最適化よりも重要です。ゲームが60 FPSで動作している場合、コードの可読性を犠牲にして120 FPSを引き出す必要はありません。
結論
ゲームのLuaコードを最適化するには、パフォーマンスと読みやすさのバランスが重要です。次の簡単なルールに従ってください。
ローカル変数を使用する
計算をキャッシュする
ゴミを出さないようにする
最適化の前にプロファイリングする
アルゴリズムの最適化(空間分割、バッチ処理)を適用する
この知識があれば、弱いデバイスでもゲームをすばやくスムーズに実行できます。
これらすべて、そしてさらに多くのことを コディケ — 初心者向けの開発者教育プラットフォーム。Python、JavaScript、Lua、その他のプログラミング言語のわかりやすいコースを作成しています。
また、当社には 急な テレグラムチャンネル フレンドリーな開発者コミュニティと!志を同じくする人々とチャットし、質問をし、プロジェクトを共有し、経験豊富なプログラマーからアドバイスを受けましょう。
一緒に学びましょう。一緒に学ぶ方が楽しいです!
