تطوير HUD في FiveM: تصميم واجهة لاعب نظيفة وسريعة
ابنِ HUD عالي الأداء لـ FiveM باستخدام HTML و JS. الصحة، التحمل، الصوت، السرعة وطبقات الخريطة المصغرة بالإضافة إلى أفضل سكريبتات HUD للدراسة أو الشراء.
Agency Scripts
المؤسس والمطور الرئيسي في Agency Scripts
لماذا بناء HUD مخصص
واجهة HUD الافتراضية في GTA V صُممت للعب الفردي في لعبة أكشن، وليست للسيناريوهات المعقدة للعب التمثيلي التي تتطلبها خوادم FiveM. تتيح لك واجهة HUD المخصصة عرض معلومات خاصة باللعب التمثيلي مثل الجوع، العطش، التوتر، وحالة الوظيفة التي ببساطة غير موجودة في GTA العادية. إلى جانب الوظائف، تحدد واجهة HUD المخصصة هوية خادمك البصرية وتحدد النغمة منذ لحظة ظهور اللاعب. يلاحظ اللاعبون فورًا الفرق في الجودة بين خادم يستخدم عناصر واجهة المستخدم الافتراضية وآخر بواجهة HUD مصقولة ومصممة خصيصًا تتناسب مع علامة الخادم وموضوعه. بناء HUD خاص بك من الصفر يعني أيضًا أنك تتحكم في كل جانب من جوانب الأداء، مما يضمن تشغيل الطبقة التراكبية بأقل تكلفة موارد مع توفير المعلومات التي يحتاجها اللاعبون بالضبط.
هيكل مورد NUI
يستخدم FiveM NUI (واجهة المستخدم الجديدة) لعرض HTML و CSS و JavaScript داخل عميل اللعبة. يحتاج مورد HUD الخاص بك إلى هيكل مجلد محدد ليعمل بشكل صحيح. ال fxmanifest.lua الملف يعلن بيانات المورد، ال client.lua السكريبت يرسل بيانات اللعبة إلى طبقة NUI، و html/ المجلد يحتوي على واجهتك المستندة إلى الويب. إليك بيان مورد بسيط للبدء:
fx_version 'cerulean'
game 'gta5'
description 'Custom HUD'
author 'YourName'
version '1.0.0'
ui_page 'html/index.html'
client_script 'client.lua'
files {
'html/index.html',
'html/style.css',
'html/script.js',
'html/fonts/*.woff2'
}
ال ui_page التوجيه يخبر FiveM بملف HTML الذي يعرض كطبقة NUI، و files جدول يسرد كل أصل يحتاج المتصفح إلى الوصول إليه. إذا نسيت تضمين ملف CSS أو خط في هذه القائمة، يفشل المتصفح في تحميله بصمت دون أي رسالة خطأ، وهو مصدر شائع للارتباك للمطورين الجدد على تطوير NUI. حافظ على هيكل مواردك نظيفاً بفصل الاهتمامات: HTML للتخطيط، CSS للتصميم، وJavaScript للمنطق والرسوم المتحركة.
إرسال بيانات اللعبة إلى واجهة المستخدم
يتولى سكريبت Lua على جانب العميل قراءة حالة اللعبة ودفعها إلى طبقة NUI على فترات منتظمة. تحتاج إلى جمع الصحة، الدرع، وأي قيم حالة خاصة بالإطار مثل الجوع والعطش. الوظيفة الأساسية هي SendNUIMessage()، التي ترسل حمولة JSON إلى جافا سكريبت التي تعمل في إطار NUI. كن استراتيجيًا بشأن تكرار التحديث لأن إرسال البيانات في كل إطار يهدر دورات وحدة المعالجة المركزية بينما التحديث البطيء جدًا يجعل HUD يبدو متأخرًا. معدل تحديث بين 200-500 مللي ثانية يحقق التوازن الصحيح لأشرطة الحالة:
CreateThread(function()
while true do
local ped = PlayerPedId()
local health = GetEntityHealth(ped) - 100 -- GTA health starts at 100
local maxHealth = GetEntityMaxHealth(ped) - 100
local armor = GetPedArmour(ped)
-- Framework-specific data (QBCore example)
local playerData = QBCore.Functions.GetPlayerData()
local hunger = playerData.metadata['hunger'] or 100
local thirst = playerData.metadata['thirst'] or 100
local stress = playerData.metadata['stress'] or 0
SendNUIMessage({
action = 'updateStatus',
health = math.floor((health / maxHealth) * 100),
armor = armor,
hunger = math.floor(hunger),
thirst = math.floor(thirst),
stress = math.floor(stress)
})
Wait(300)
end
end)
لعداد السرعة، تحتاج إلى خيط منفصل يعمل بمعدل تكرار أسرع لأن السرعة تتغير بسرعة ويتوقع اللاعبون ردود فعل في الوقت الحقيقي أثناء القيادة. يعمل فاصل زمني من 50-100 مللي ثانية بشكل جيد لبيانات المركبة. شغل خيط عداد السرعة فقط عندما يكون اللاعب فعليًا في مركبة لتوفير الموارد، وعطله عند الخروج:
CreateThread(function()
while true do
local ped = PlayerPedId()
if IsPedInAnyVehicle(ped, false) then
local veh = GetVehiclePedIsIn(ped, false)
local speed = GetEntitySpeed(veh) * 3.6 -- Convert to km/h
local rpm = GetVehicleCurrentRpm(veh)
local gear = GetVehicleCurrentGear(veh)
local fuel = GetVehicleFuelLevel(veh)
SendNUIMessage({
action = 'updateVehicle',
speed = math.floor(speed),
rpm = rpm,
gear = gear,
fuel = math.floor(fuel)
})
Wait(50)
else
SendNUIMessage({ action = 'hideVehicle' })
Wait(500)
end
end
end)
بناء واجهة HTML و CSS
تصميم HUD الخاص بك بصريًا يحدد كيف يشعر به داخل اللعبة. تستخدم HUDs الحديثة في FiveM تصاميم نظيفة وبسيطة مع خلفيات شبه شفافة، زوايا مستديرة، ورسوم متحركة خفيفة. ضع أشرطة الحالة في الزاوية السفلية اليسرى حيث لا تعيق اللعب، وضع عداد السرعة في الزاوية السفلية اليمنى عندما يقود اللاعب. استخدم خصائص CSS المخصصة للألوان حتى تتمكن من تغيير ثيم HUD بالكامل بتغيير بعض المتغيرات. أشرطة التقدم المتحركة مع انتقالات سلسة تعطي HUD إحساسًا مصقولًا:
<!-- html/index.html -->
<div id="hud-container">
<div class="status-bars">
<div class="bar-wrapper">
<i class="icon health-icon"></i>
<div class="bar">
<div class="bar-fill health-fill" id="health-bar"></div>
</div>
</div>
<div class="bar-wrapper">
<i class="icon armor-icon"></i>
<div class="bar">
<div class="bar-fill armor-fill" id="armor-bar"></div>
</div>
</div>
<div class="bar-wrapper">
<i class="icon hunger-icon"></i>
<div class="bar">
<div class="bar-fill hunger-fill" id="hunger-bar"></div>
</div>
</div>
<div class="bar-wrapper">
<i class="icon thirst-icon"></i>
<div class="bar">
<div class="bar-fill thirst-fill" id="thirst-bar"></div>
</div>
</div>
</div>
<div class="speedometer" id="speedometer" style="display:none">
<div class="speed-value" id="speed-value">0</div>
<div class="speed-unit">KM/H</div>
<div class="fuel-bar">
<div class="fuel-fill" id="fuel-bar"></div>
</div>
</div>
</div>
لـ CSS، استخدم transition على عرض الشريط لإنشاء حركات تعبئة سلسة، وطبق pointer-events: none إلى حاوية HUD بأكملها حتى لا تتداخل مع إدخال اللعبة. تساعد الألوان المختلفة لكل شريط حالة اللاعبين على التعرف بسرعة على المورد المنخفض دون قراءة التسميات. الأحمر للصحة، الأزرق للدروع، البرتقالي للجوع، والفيروزي للعطش هو اتفاقية معتمدة يفهمها اللاعبون بشكل بديهي.
معالجة رسائل JavaScript
طبقة JavaScript تستقبل الرسائل من عميل Lua وتحدث DOM وفقًا لذلك. سجل مستمع حدث الرسائل الذي يوزع بناءً على حقل الإجراء في الحمولة. اجعل منطق التحديث خفيفًا لأنه يعمل بتردد إرسال بيانات خيوط Lua، وأي تأخير في طبقة JavaScript يترجم مباشرة إلى تقطع بصري. تجنب استعلامات DOM داخل معالج التحديث عن طريق تخزين مراجع العناصر عند التهيئة:
// html/script.js
const elements = {
healthBar: document.getElementById('health-bar'),
armorBar: document.getElementById('armor-bar'),
hungerBar: document.getElementById('hunger-bar'),
thirstBar: document.getElementById('thirst-bar'),
speedometer: document.getElementById('speedometer'),
speedValue: document.getElementById('speed-value'),
fuelBar: document.getElementById('fuel-bar')
};
window.addEventListener('message', (event) => {
const data = event.data;
switch (data.action) {
case 'updateStatus':
elements.healthBar.style.width = data.health + '%';
elements.armorBar.style.width = data.armor + '%';
elements.hungerBar.style.width = data.hunger + '%';
elements.thirstBar.style.width = data.thirst + '%';
// Color shift when low
if (data.health < 25) {
elements.healthBar.classList.add('critical');
} else {
elements.healthBar.classList.remove('critical');
}
break;
case 'updateVehicle':
elements.speedometer.style.display = 'flex';
elements.speedValue.textContent = data.speed;
elements.fuelBar.style.width = data.fuel + '%';
break;
case 'hideVehicle':
elements.speedometer.style.display = 'none';
break;
}
});
إضافة فئة CSS للحالات الحرجة التي تُشغّل حركة نبضية على الشريط، لجذب انتباه اللاعب عندما تنخفض صحته أو جوعه إلى مستوى خطير. هذا النوع من التغذية البصرية أكثر فعالية بكثير من الاعتماد على اللاعبين لمراقبة أرقام حالتهم باستمرار، ويضيف طبقة من التلميع التي تميز HUDs الهواة عن المحترفين.
تخصيص الخريطة المصغرة
الخريطة المصغرة الافتراضية في GTA عملية لكنها تتعارض بصريًا مع معظم تصميمات HUD المخصصة. يمنحك FiveM تحكمًا في موقع الخريطة المصغرة، حجمها، شكلها، ومستوى التكبير من خلال وظائف أصلية. يمكنك إنشاء خريطة مصغرة دائرية، نقلها لتتناسب مع تخطيط HUD الخاص بك، أو حتى إخفاؤها تمامًا واستبدالها بحل مخصص. النهج الأكثر شيوعًا هو إعادة تشكيل الخريطة المصغرة لتكمل جمالية HUD مع الحفاظ على وظيفة خريطة اللعبة الأساسية:
CreateThread(function()
-- Wait for map to load
Wait(500)
-- Set minimap shape and position
local minimapHandle = RequestScaleformMovie('MINIMAP')
SetMinimapClipType(1) -- 0 = rectangle, 1 = circle
-- Adjust minimap position and size
local defaultAspect = 1920 / 1080
local resX, resY = GetActiveScreenResolution()
local aspect = resX / resY
local ratio = defaultAspect / aspect
SetMinimapComponentPosition('minimap', 'L', 'B',
0.0, -0.032, 0.145 * ratio, 0.210)
SetMinimapComponentPosition('minimap_mask', 'L', 'B',
0.0, 0.032, 0.128 * ratio, 0.300)
SetMinimapComponentPosition('minimap_blur', 'L', 'B',
-0.01, -0.032, 0.272 * ratio, 0.420)
-- Hide default health and armor bars
local minimap = RequestScaleformMovie('MINIMAP')
while not HasScaleformMovieLoaded(minimap) do Wait(0) end
while true do
-- Disable default HUD components
HideHudComponentThisFrame(6) -- Vehicle name
HideHudComponentThisFrame(7) -- Area name
HideHudComponentThisFrame(8) -- Vehicle class
HideHudComponentThisFrame(9) -- Street name
Wait(0)
end
end)
عند تخصيص الخريطة المصغرة، احرص دائماً على مراعاة نسب أبعاد الشاشة المختلفة. الخريطة المصغرة التي تبدو مثالية على شاشة 16:9 ستتمدد أو تُوضع بشكل خاطئ على شاشات ultrawide. احسب النسبة بين النسبة الافتراضية والنسبة الفعلية وطبقها على مكونات العرض. اختبر خريطتك المصغرة على ثلاث دقات شائعة على الأقل (1920x1080، 2560x1440، و3440x1440) لضمان تموضع متسق عبر إعدادات اللاعبين المختلفة.
إخفاء عناصر HUD الافتراضية في GTA
عندما تبني HUD مخصص، يجب عليك إخفاء عناصر GTA الافتراضية التي تستبدلها واجهة المستخدم المخصصة، وإلا سيرى اللاعبون معلومات مكررة. يوفر FiveM HideHudComponentThisFrame() native لهذا الغرض، لكن يجب استدعاؤه في كل إطار لأن GTA يعيد تمكين مكونات HUD في كل تكرار. تغطي معرفات المكونات كل شيء من نجوم المطلوبين إلى عرض النقود إلى عجلة الأسلحة. لاستبدال HUD كامل، عادةً ما تريد إخفاء شريط الصحة، شريط الدرع، عرض النقود، ومؤشرات المركبة مع الحفاظ على العناصر الأساسية مثل الترجمة المنبثقة والإشعارات مرئية. أنشئ جدولًا قابلًا للتكوين لمعرفات المكونات بحيث يمكن لمالكي الخوادم تبديل العناصر الافتراضية التي يرغبون في إخفائها دون تعديل الكود الخاص بك. بالإضافة إلى ذلك، استخدم DisplayRadar(false) إذا كان HUD الخاص بك يتضمن بديلًا لخريطة صغيرة خاصة به، لكن كن على علم بأن إخفاء الرادار يعطل أيضًا خريطة قائمة الإيقاف المؤقت ما لم تقم بإعادة تمكينها عند اكتشاف قائمة الإيقاف المؤقت.
أفضل ممارسات الأداء
أداء HUD أمر حاسم لأن HUD الخاص بك يعمل باستمرار أثناء وجود اللاعب في اللعبة، مما يجعل حتى الكفاءات الصغيرة تتراكم إلى انخفاضات ملحوظة في الإطارات خلال جلسات اللعب الطويلة. أكثر تحسين تأثيرًا هو التحكم في تردد التحديث. يمكن لأشرطة الحالة التي تتغير ببطء مثل الجوع والعطش أن تحدث كل 500 مللي ثانية أو حتى كل ثانية، بينما القيم التي تتغير بسرعة مثل السرعة تحتاج إلى تحديثات أكثر تواترًا. استخدم العرض الشرطي لإرسال رسائل NUI فقط عندما تتغير القيم فعليًا، بدلاً من دفع نفس البيانات مرارًا وتكرارًا. على جانب JavaScript، تجنب innerHTML للتحديثات لأنه يجبر المتصفح على إعادة تحليل HTML، واستخدم textContent أو تغييرات مباشرة في خصائص النمط بدلاً من ذلك. قلل من تحريكات CSS على العناصر التي تتحدث بشكل متكرر لأن محرك تحريك المتصفح وتحديثات JavaScript الخاصة بك قد تتعارض، مما يسبب تشوهات بصرية. إذا كان HUD الخاص بك يستخدم خطوط مخصصة، قم بتحميلها مسبقًا في رأس HTML لمنع تحولات التخطيط عند انتهاء تحميل ملف الخط. وأخيرًا، قم بتحليل أدائك باستخدام أدوات FiveM المدمجة resmon الأمر وهدفك هو أن يستهلك HUD أقل من 0.1 مللي ثانية لكل إطار في المتوسط، مما يترك مجالاً لعشرات الموارد الأخرى التي تعمل على العميل.