🚀 スクリプトの最適化
一般診療
関数と変数をローカライズする
- Luaはローカル変数や関数にグローバル変数や関数よりも高速にアクセスします。常に
local明示的にグローバルである必要がない限り、変数または関数を宣言するとき
myVariable = false -- Don't use this
local myVariable = false -- Use this
function someFunction() -- Don't use this
print('Im a global function!')
end
local function someFunction() -- Use this
print('Im a local function!')
end代わりにテーブルインデックスを使用するtable.insert
table.insert若干のオーバーヘッドが発生します。値を直接割り当てる方が効率的です。
function someFunction()
local table = {}
table.insert(table, {}) -- Don't use this
table[#table+1] = {} -- Use this
end条件チェックを簡素化する
- 使用
if something thenの代わりにif something ~= nil両方を確認するnilそしてfalse
function someFunction()
local bool = nil
if bool ~= nil then -- Don't use this
print('bool was not nil but also could be false!')
end
if bool then -- Use this
print('bool was neither nil or false!')
end
end関数を普遍的に保つ
- パラメータを渡すことで複数のシナリオに対応できる関数やイベントを記述します。これによりコードの再利用性が向上します。
local function someFunction(param1, param2, param3)
print('Im a function that accepts 3 parameters which allows for multiple conditions!')
if param1 == 'something' then
print('I met condition number one!')
elseif param2 == 'somethingelse' then
print('I met condition number two!')
elseif param3 == 'somethingelsemore' then
print('I met condition number three!')
end
end
RegisterNetEvent('someEvent', function(param1, param2, param3)
print('Im an event that accepts 3 parameters which allows for multiple conditions!')
if param1 == 'something' then
print('I met condition number one!')
elseif param2 == 'somethingelse' then
print('I met condition number two!')
elseif param3 == 'somethingelsemore' then
print('I met condition number three!')
end
end)ショートリターン
- 使用 ショートリターン条件が満たされない場合に関数を早期に終了する。これによりコードが整理され、不要なネストが回避される。
ifブロック
local function someFunction(param1, param2, param3)
if not param1 then return end
print('I met condition number one!')
if not param2 then return end
print('I met condition number two!')
if not param3 then return end
print('I met condition number three!')
endテーブルや変数を繰り返し再作成しないようにする
- ループや頻繁に呼び出される関数内でテーブルや変数を繰り返し作成するのではなく、一度初期化して再利用します。
local reusableTable = {}
local function someFunction()
for i = 1, 10 do
reusableTable[i] = i -- Reuse the same table instead of creating a new one
end
end使用 nilメモリを解放する
- 未使用の変数を割り当てる
nilLuaのガベージコレクターがメモリを解放できるようにする
local largeData = {1, 2, 3, 4}
-- Process data...
largeData = nil -- Free up memory when doneハードコーディングを避ける
- 設定可能な値(座標、アイテム名、支払金額など)を一元管理します。
config.lua管理を容易にするファイル
例 config.lua:
Config = {
Zones = {
PoliceStation = vector3(441.1, -981.1, 30.7),
Hospital = vector3(1151.21, -1529.62, 34.84)
},
Payments = {
Police = 150,
EMS = 120
}
}ログとデバッグ
- スクリプト内でデバッグモードの切り替えを使用すれば、ログを削除せずに動的にログを有効化または無効化できます。スクリプトにオプションとして追加することもできます。
config.lua上から!
local DEBUG = true
local function debugLog(message)
if DEBUG then
print(message)
end
end
debugLog('This is a debug message!')トラックパフォーマンス
- パフォーマンスが重要なセクションの実行時間を測定します。
os.clock()またはFiveMネイティブ
local start = os.clock()
-- Code to measure
print("Execution time:", os.clock() - start)local startTime = GetGameTimer()
-- Simulate a delay
Wait(1000)
local endTime = GetGameTimer()
print("Execution time (ms):", endTime - startTime) -- Output: 1000 (approx)ネットワークイベントの過剰な使用を避ける
- 共有状態を使用する(例:
state bagsまたはentity states)スパムではなく、頻繁なデータ同期が必要な場合TriggerEventまたはTriggerServerEvent
-- Set state
Entity(playerPed).state:set('exampleData', 123, true)
-- Get state
local data = Entity(playerPed).state.exampleData
print(data) -- Outputs: 123データ転送の最適化
- テーブル全体や大きなペイロードではなく、必要なデータのみを送信します
TriggerServerEvent('exampleEvent', { x = 100, y = 200 }) -- Only send necessary fieldsコードの読みやすさ
コードにコメントを付ける
- 特に複雑な部分やわかりにくい部分には、ロジックを説明するコメントを追加します。
-- Check if the player is in range of the target zone
if #(playerCoords - targetCoords) < 10 then
print('Player is in range')
endスクリプトを整理する
- スクリプトを論理的に構造化し、変数、関数、イベント ハンドラー、コア ロジックを個別のセクションに分離します。
-- Variables
local QBCore = exports['qb-core']:GetCoreObject()
-- Functions
local function calculateDistance(pos1, pos2)
return #(pos1 - pos2)
end
-- Events
RegisterNetEvent('exampleEvent', function()
print('Event triggered!')
end)
-- Main Logic
CreateThread(function()
print('Script started!')
end)フォルダ構造
- すべてを 1 つのファイルに記述するのではなく、スクリプトをより小さく管理しやすい部分に分割します。
my_script/
├── client/
│ ├── main.lua
│ ├── utils.lua
├── server/
│ ├── main.lua
│ ├── events.lua
├── shared/
│ ├── config.lua
└── fxmanifest.luaネイティブの使用法
- 常に交換する
GetPlayerPed(-1)とPlayerPedId()
local function someFunction()
local ped = GetPlayerPed(-1) -- Don't use this
local ped = PlayerPedId() -- Use this
end- 常に交換する
GetDistanceBetweenCoordslua math 別名#(vector3 - vector3)
local function someFunction()
local ped = PlayerPedId()
local pCoords = GetEntityCoords(ped)
local coords = vector3(-29.53, -1103.67, 26.42)
local dist = GetDistanceBetweenCoords(pCoords, coords, true) -- Don't use this
local dist = #(pCoords - coords) -- Use this
if dist < 5 then
print('Im within 5 distance units of the coords!')
end
endループ
- whileループとその実行タイミングを制御する
local function exampleLoop()
CreateThread(function()
while listen do
print('running while loop only when needed')
Wait(0)
end
end)
end
local listen = false
CreateThread(function()
LoopZone = CircleZone:Create(vector3(-851.63, 74.36, 51.86), 5.0, {
name = "ExampleLoop",
debugPoly = true,
})
LoopZone:onPlayerInOut(function(isPointInside)
if isPointInside then
listen = true
exampleLoop() -- Initiate loop
else
listen = false -- turns off when your outside the zone
end
end)
end)- 「while」ループを含むスレッドを作成する必要がある場合は、可能な限り「while true do」の使用を避けてください。どうしても使用する必要がある場合は、次のヒントに従うと、パフォーマンスへの影響はそれほど大きくありません。
- スレッドの時間を制御するには、待機時間を遡及的に変更する変数を使用します。例えば、スレッドの待機時間を1000ミリ秒に設定し、if文を1秒ごとにチェックします。if文が文中に現れた場合は、変数の値を変更するだけで待機時間を短縮できます。Wait(sleep)
CreateThread(function()
while true do
local sleep = 2500 -- Default wait time
local ped = PlayerPedId()
local pos = GetEntityCoords(ped)
local inRange = #(pos - vector3(-829.11, 75.03, 52.73)) < 10.0
if inRange then
sleep = 0 -- Reduce wait time if condition is met
print('I am in range!')
else
print('I am out of range.')
end
Wait(sleep)
end
end)- ジョブ固有のループがある場合は、そのジョブのプレイヤーにのみ適用されるようにしてください。警察官ではないプレイヤーが、自分には適用されないループを自分のマシンで実行する理由はありません。
local function exampleJobLoop()
local job = QBCore.Functions.GetPlayerData().job.name
CreateThread(function()
while job == 'police' do
print('im a policeman!')
Wait(0)
end
end)
end安全
- コードに過剰なセキュリティ対策を施すことは悪いことではありません。複数のif文を追加したり、イベントにランダム変数を渡すことをためらわないでください。
- リソースのクライアント側で、お金やアイテムに関してplayerとのいかなる種類の取引も行わないでください。
Event ハンドラー
- リソース内で変数を設定する場合、ハンドラーは、常にチェックを実行する必要がないため、特に便利です。
-- These are client-side examples
local isLoggedIn = false
local PlayerData = {}
AddStateBagChangeHandler('isLoggedIn', nil, function(_, _, value) -- FiveM native method
if value then
isLoggedIn = true
PlayerData = QBCore.Functions.GetPlayerData()
else
isLoggedIn = false
PlayerData = {}
end
end)
AddEventHandler('QBCore:Client:OnPlayerLoaded', function() -- Don't use this with the native method
isLoggedIn = true
PlayerData = QBCore.Functions.GetPlayerData()
end)
RegisterNetEvent('QBCore:Client:OnPlayerUnload', function() -- Don't use this with the native method
isLoggedIn = false
PlayerData = {}
end)
RegisterNetEvent('QBCore:Client:OnJobUpdate', function(JobInfo)
PlayerData.job = JobInfo
end)
RegisterNetEvent('QBCore:Player:SetPlayerData', function(val)
PlayerData = val
end)Last updated on