نظام التاكسي في FiveM: برمجة سائقي التاكسي NPC واللاعبين
إضافة نظام تاكسي يعمل إلى FiveM. سيارات الأجرة NPC، سائقو اللاعبين، منطق الأجرة، العدادات وأفضل سكربتات التاكسي لمدن لعب الأدوار النابضة بالحياة.
Agency Scripts
المؤسس والمطور الرئيسي في Agency Scripts
هيكل نظام وظيفة التاكسي
نظام وظيفة التاكسي هو ميزة أساسية لأي سيرفر RP يريد توفير وظيفة دخول سهلة مع تفاعل حقيقي بين اللاعبين. على عكس العديد من الوظائف الأخرى التي قد تبدو مملة ومتكررة، يخلق نظام التاكسي المصمم جيدًا لقاءات RP عضوية حيث يلتقط السائقون الركاب، يتفاوضون على الأجرة، ويتنقلون في المدينة تحت ضغط الوقت. تنقسم البنية إلى وضعين مميزين: نقل لاعب إلى لاعب حيث يطلب الركاب الحقيقيون الرحلات، ووضع مهمة NPC حيث يولد النظام مواقع الالتقاط والتوصيل للعب الفردي خلال ساعات الذروة المنخفضة. يشترك كلا الوضعين في نفس محرك حساب الأجرة، واجهة عداد التاكسي، ونظام إدارة المركبات. القرار التصميمي الرئيسي هو ما إذا كان سيتم استخدام نظام إرسال مركزي حيث تذهب طلبات الرحلات إلى قائمة انتظار مشتركة مرئية لجميع السائقين المناوبين، أو نظام قائم على القرب حيث يحصل السائق الأقرب على الأولوية. تستخدم معظم التطبيقات الناجحة نهجًا هجينًا مع لوحة إرسال تعرض كل الطلبات المعلقة لكنها تبرز الأقرب، مما يمنح السائقين حرية اختيار وظائفهم مع ضمان التقاط الركاب بسرعة.
تنفيذ عداد التاكسي
عداد الأجرة هو قلب نظام الأجرة ويحتاج إلى أن يشعر بالأصالة مع بقائه شفافًا لكل من السائق والراكب. يتتبع العداد مكونين: أجرة أساسية تُفرض في بداية كل رحلة، ومعدل لكل مسافة يزداد مع تحرك المركبة. تضيف بعض الخوادم أيضًا معدل انتظار يفرض رسومًا أقل لكل ثانية عندما تكون سيارة الأجرة ثابتة، محاكاة للممارسة الواقعية في فرض رسوم على الوقت المستغرق في الازدحام. يجب أن يكون العداد مرئيًا لكل من السائق وأي ركاب في المركبة من خلال عنصر NUI مستمر موضوع في زاوية الشاشة. فيما يلي تنفيذ عداد على جانب العميل يحسب الأجرة بناءً على المسافة المقطوعة:
local meterActive = false
local currentFare = 0.0
local lastPosition = nil
local baseFare = 50
local ratePerMile = 15
local waitRatePerSecond = 0.5
local totalDistance = 0.0
function StartMeter()
meterActive = true
currentFare = baseFare
totalDistance = 0.0
lastPosition = GetEntityCoords(PlayerPedId())
SendNUIMessage({action = 'showMeter', fare = currentFare, distance = 0.0})
CreateThread(function()
while meterActive do
Wait(500)
local currentPos = GetEntityCoords(PlayerPedId())
local speed = GetEntitySpeed(PlayerPedId())
if speed > 1.0 then
local dist = #(currentPos - lastPosition)
totalDistance = totalDistance + dist
local miles = totalDistance / 1609.34
currentFare = baseFare + (miles * ratePerMile)
else
currentFare = currentFare + (waitRatePerSecond * 0.5)
end
lastPosition = currentPos
SendNUIMessage({
action = 'updateMeter',
fare = math.floor(currentFare),
distance = math.floor(totalDistance),
speed = math.floor(speed * 2.236936)
})
end
end)
end
function StopMeter()
meterActive = false
local finalFare = math.floor(currentFare)
SendNUIMessage({action = 'stopMeter', fare = finalFare})
return finalFare
end
مكون NUI للعداد يجب أن يكون مضغوطًا لكن قابلًا للقراءة، يعرض الأجرة الحالية بوضوح مع المسافة المقطوعة والمعدل الحالي المطبق. استخدم خطًا أحادي المسافة لعرض الأجرة لمحاكاة مظهر عداد تاكسي حقيقي، وأضف حركة تكتكية خفيفة في كل مرة تزداد فيها الأجرة لتعطي رد فعل بصري بأن العداد يعمل. فكر في إضافة ميزة تقدير الأجرة التي تحسب التكلفة التقريبية بناءً على المسافة الخطية إلى الوجهة قبل بدء الرحلة، حتى يتمكن الركاب من اتخاذ قرار المتابعة.
نظام مهام التقاط NPC
تحافظ مهام NPC على انشغال سائقي سيارات الأجرة عندما لا يكون هناك عدد كافٍ من الركاب الحقيقيين على السيرفر. يولد النظام مواقع التقاط وتسليم عشوائية من قائمة مختارة من نقاط الاهتمام حول الخريطة، ينشئ NPC في موقع الالتقاط، ويوجه السائق خلال دورة الأجرة الكاملة. تعتمد جودة تجربة مهمة NPC بشكل كبير على بيانات الموقع: استخدام إحداثيات عشوائية فقط ينتج التقطات غير طبيعية في أماكن نائية، لذا فإن الحفاظ على قائمة مختارة يدويًا من المواقع الواقعية مثل المستشفيات، المطاعم، الفنادق، ومراكز التسوق يجعل المهام تبدو حقيقية. هذه هي منطق الخادم لإنشاء وإرسال مهام NPC:
local MissionLocations = {
{coords = vector3(-240.49, -987.78, 29.29), label = 'Pillbox Medical Center'},
{coords = vector3(228.28, -790.70, 30.58), label = 'Legion Square'},
{coords = vector3(-1044.57, -2739.76, 13.85), label = 'Los Santos Airport'},
{coords = vector3(126.19, -1282.72, 29.27), label = 'Strawberry Avenue'},
{coords = vector3(-556.18, -196.17, 38.22), label = 'Rockford Hills'},
{coords = vector3(1159.56, -314.45, 69.21), label = 'Vinewood Hills'},
{coords = vector3(-1222.08, -906.82, 12.32), label = 'Del Perro Pier'},
{coords = vector3(373.58, 325.71, 103.57), label = 'Downtown Vinewood'},
}
RegisterNetEvent('taxi:server:requestNPCMission', function()
local src = source
local Player = QBCore.Functions.GetPlayer(src)
if not Player or Player.PlayerData.job.name ~= 'taxi' then return end
local pickup = MissionLocations[math.random(#MissionLocations)]
local dropoff = MissionLocations[math.random(#MissionLocations)]
while pickup.label == dropoff.label do
dropoff = MissionLocations[math.random(#MissionLocations)]
end
local estimatedDistance = #(pickup.coords - dropoff.coords)
local basePay = 50
local distancePay = math.floor(estimatedDistance / 1609.34 * 15)
local totalPay = basePay + distancePay
TriggerClientEvent('taxi:client:startNPCMission', src, {
pickup = pickup,
dropoff = dropoff,
estimatedPay = totalPay,
npcModel = Config.NPCModels[math.random(#Config.NPCModels)],
missionId = 'TAXI-' .. os.time() .. '-' .. math.random(1000, 9999)
})
end)
على جانب العميل، استدعِ NPC في موقع الاستلام مع حركة انتظار، أضف علامة لتوجيه السائق، وشغّل حركة دخول المركبة عند وصول السائق. أثناء الرحلة، يجب أن يستخدم NPC سلوكيات طبيعية مثل النظر حوله والتعليق أحيانًا على القيادة عبر فقاعات الدردشة. عند وصول المركبة إلى الوجهة، يخرج NPC ويتم دفع الأجرة تلقائيًا عبر حدث خادم. أضف تنوعًا من خلال توليد مهام خاصة أحيانًا مع مدفوعات أعلى، مثل النقل من المطار أو العملاء VIP الذين يطلبون قيادة حذرة بدون أي تصادمات.
حساب الأجرة وتسعير الذروة
بعيداً عن حساب الأجرة الأساسي المعتمد على المسافة، يأخذ نظام الأجرة المتطور في الاعتبار وقت اليوم، ظروف المرور، ونوع المركبة. نفذ تسعير الزيادة خلال ساعات الذروة على الخادم عندما يكون العديد من اللاعبين متصلين ويتجاوز الطلب على سيارات الأجرة العرض. يجب أن يتم إبلاغ الركاب بمعامل الزيادة بشفافية قبل تأكيد الرحلة حتى لا تكون هناك مفاجآت في النهاية. يمكنك حساب الطلب ديناميكياً بتتبع نسبة طلبات الرحلات المعلقة إلى السائقين المتاحين. إليك محرك حساب الأجرة الذي يدمج هذه المتغيرات:
function CalculateFare(pickupCoords, dropoffCoords, vehicleClass)
local distance = #(pickupCoords - dropoffCoords)
local miles = distance / 1609.34
local rates = Config.FareRates
local baseFare = rates.base
local perMile = rates.perMile
-- Vehicle class multiplier
local classMultiplier = {
[0] = 0.8, -- Compacts (budget)
[1] = 1.0, -- Sedans (standard)
[2] = 1.0, -- SUVs
[3] = 1.2, -- Coupes (comfort)
[18] = 1.5, -- Super (luxury)
}
local vehMultiplier = classMultiplier[vehicleClass] or 1.0
-- Time-of-day multiplier (night premium)
local hour = GetClockHours()
local timeMultiplier = 1.0
if hour >= 22 or hour <= 5 then
timeMultiplier = 1.3 -- 30% night surcharge
end
-- Surge pricing based on demand
local surgeMultiplier = GetCurrentSurgeMultiplier()
local totalFare = (baseFare + (miles * perMile)) * vehMultiplier * timeMultiplier * surgeMultiplier
return {
total = math.floor(totalFare),
breakdown = {
base = baseFare,
distance = math.floor(miles * perMile),
vehicleClass = vehMultiplier,
nightSurcharge = timeMultiplier > 1.0,
surgeActive = surgeMultiplier > 1.0,
surgeRate = surgeMultiplier
}
}
end
اعرض تفصيل الأجرة للراكب عند طلبه للركوب حتى يفهم ما يدفع مقابله. إذا كان التسعير المتصاعد نشطًا، أظهر المضاعف بوضوح مع مؤشر لوني مختلف في واجهة المستخدم. تبني هذه الشفافية الثقة بين السائقين والركاب وتقلل النزاعات حول مبالغ الأجرة. اسمح للركاب باختيار فئة المركبة المفضلة لديهم عند الحجز، مع خيارات اقتصادية باستخدام سيارات مدمجة وخيارات فاخرة باستخدام سيارات سيدان أو SUV عالية الجودة بأسعار مميزة.
عرض المسار والملاحة بنظام GPS
توفير إرشادات طريق بصرية يجعل تجربة التاكسي أكثر سلاسة للسائقين الجدد وذوي الخبرة. يوفر FiveM SetNewWaypoint native للتوجيه الأساسي عبر GPS، لكن النهج الأكثر صقلًا يرسم المسار مباشرة على الخريطة المصغرة ويرسم مسارًا ثلاثي الأبعاد في العالم اختياريًا. استخدم SetBlipRoute function على علامات الوجهة لتمكين مسار GPS المدمج، وتعزيزه بعلامات مخصصة عند نقاط الطريق الرئيسية على طول المسار. لفائدة الراكب، اعرض الوقت المقدر للوصول والمسافة المتبقية في واجهة العداد، مع التحديث في الوقت الحقيقي مع تقدم المركبة. إليك كيفية إعداد نظام عرض المسار مع تتبع نقاط الطريق:
local routeBlip = nil
local checkpointBlips = {}
function SetTaxiRoute(destination, checkpoints)
ClearTaxiRoute()
routeBlip = AddBlipForCoord(destination.x, destination.y, destination.z)
SetBlipSprite(routeBlip, 198)
SetBlipColour(routeBlip, 5)
SetBlipScale(routeBlip, 1.0)
SetBlipRoute(routeBlip, true)
SetBlipRouteColour(routeBlip, 5)
BeginTextCommandSetBlipName('STRING')
AddTextComponentSubstringPlayerName('Destination')
EndTextCommandSetBlipName(routeBlip)
if checkpoints then
for i, cp in ipairs(checkpoints) do
local cpBlip = AddBlipForCoord(cp.x, cp.y, cp.z)
SetBlipSprite(cpBlip, 1)
SetBlipColour(cpBlip, 3)
SetBlipScale(cpBlip, 0.6)
table.insert(checkpointBlips, cpBlip)
end
end
end
function ClearTaxiRoute()
if routeBlip then
SetBlipRoute(routeBlip, false)
RemoveBlip(routeBlip)
routeBlip = nil
end
for _, blip in ipairs(checkpointBlips) do
RemoveBlip(blip)
end
checkpointBlips = {}
end
function UpdateETADisplay(destination)
CreateThread(function()
while routeBlip do
Wait(2000)
local pos = GetEntityCoords(PlayerPedId())
local remaining = #(pos - destination)
local speed = GetEntitySpeed(PlayerPedId())
local etaSeconds = speed > 2.0 and (remaining / speed) or 0
local etaMinutes = math.floor(etaSeconds / 60)
SendNUIMessage({
action = 'updateETA',
distance = math.floor(remaining),
eta = etaMinutes > 0 and (etaMinutes .. ' min') or 'Arriving'
})
end
end)
end
لإضافة طبقة إضافية من الانغماس، نفذ نظام تقييم حيث يقوم الركاب بتقييم رحلتهم بناءً على عوامل مثل وقت السفر مقارنة بالتقدير، عدد التصادمات خلال الرحلة، وما إذا كان السائق يتبع قوانين المرور. عرض متوسط تقييم السائق على ملفه في التاكسي حتى يتمكن الركاب من رؤيته قبل قبول الرحلة، مما يخلق حافزًا للسائقين لتقديم خدمة جيدة.
نظام الإكراميات وتقييمات السائق
نظام الإكراميات يضيف آلية اجتماعية مجزية تشجع السائقين على تقديم خدمة ممتازة. بعد دفع الأجرة وخروج الراكب من المركبة، عرض مطالبة بالإكرامية للراكب مع خيارات مسبقة مثل 10%، 15%، 20%، أو مبلغ مخصص. تذهب الإكرامية مباشرة إلى السائق فوق الأجرة الأساسية وأي عمولة من شركة التاكسي. تتبع الإكراميات التراكمية لكل سائق في قاعدة البيانات لإنشاء لوحات المتصدرين وفتح مكافآت للسائقين الأعلى تقييمًا. على جانب السيرفر، عالج الإكراميات من خلال نفس نظام المعاملات كالأجرة لضمان الاتساق ومنع التكرار. السائقون الذين يحافظون على تقييم عالي ومتوسط إكراميات مع الوقت قد يفتحون مزايا مثل الوصول إلى مركبات مميزة، تقليل معدلات عمولة الشركة، أو أولوية في قائمة الإرسال. اجمع نظام الإكراميات مع نظام المراجعات حيث يترك الركاب مراجعة نصية قصيرة مرئية للسائق، مما يخلق حلقة تغذية راجعة تحسن جودة خدمة التاكسي على السيرفر.
لوحة الإرسال وطلبات الركوب
لوحة الإرسال هي المحور المركزي حيث يجد سائقو سيارات الأجرة وظيفتهم التالية. قم ببنائها كلوحة NUI يمكن الوصول إليها من مقر شركة التاكسي أو من خلال مفتاح اختصار أثناء الخدمة. يجب أن تعرض اللوحة جميع طلبات الركوب المعلقة مرتبة حسب القرب، مع عرض اسم الراكب، موقع الالتقاط، الوجهة، الأجرة المقدرة، والمسافة المقدرة لكل إدخال. عند قبول السائق لوظيفة، قم بإزالتها من اللوحة لجميع السائقين الآخرين وابدأ مؤقت العد التنازلي، إذا لم يصل السائق إلى نقطة الالتقاط ضمن الوقت المحدد، تعود الوظيفة إلى اللوحة ويتلقى السائق عقوبة موثوقية. بالنسبة للجانب الخاص بالراكب، أنشئ تطبيق هاتف بسيط أو أمر يسمح لهم بطلب رحلة عن طريق تحديد موقعهم الحالي والوجهة. يدخل الطلب في قائمة الانتظار للإرسال ويتلقى الراكب تحديثات عند قبول سائق واقترابه. نفذ نظام إلغاء مع رسوم صغيرة للإلغاءات المتأخرة لمنع الركاب من طلب وإلغاء الرحلات بشكل متكرر، مما يضيع وقت السائق ويخلق تجربة محبطة.
نظام إدارة المركبات والأسطول
نظام تاكسي كامل يحتاج إلى إدارة مركبات مناسبة حتى يستخدم السائقون مركبات ملائمة وتحافظ الشركة على أسطولها. أنشئ نظام تسجيل مركبات في مستودع التاكسي حيث يختار السائقون من المركبات المتاحة للشركة. يجب أن يحتوي كل مركبة على عداد أميال متتبع، مستوى وقود، وحالة، ويكون السائقون مسؤولين عن إعادة المركبات بحالة مقبولة أو مواجهة خصومات إصلاح من أرباحهم. يجب أن يحتوي المستودع على مركبات من فئات مختلفة: سيارات سيدان اقتصادية للأجرة العادية، سيارات SUV مريحة للخدمة المميزة، ومركبات فاخرة للحجوزات VIP. تتبع إحصائيات استخدام كل مركبة بما في ذلك إجمالي الأجرة المكتملة، الإيرادات المتولدة، وتكاليف الصيانة. نفذ نظام استهلاك وقود يتطلب من السائقين التزود بالوقود في محطات الوقود خلال نوبتهم، مضيفًا تكلفة تشغيل واقعية يتعلم السائقون المتمرسون إدارتها بكفاءة. في نهاية النوبة، يعيد السائق المركبة إلى المستودع، ويتم حساب أرباحه الإجمالية مطروحًا منها عمولة الشركة وأي تكاليف أضرار المركبة، ويتم إيداع الراتب الصافي في حسابه المصرفي. تخلق هذه الدورة الكاملة تجربة عمل واقعية تحاكي عمليات شركات التاكسي الحقيقية.