FiveM扳手腕脚本 FiveM插件网优质资源的首选

FiveM扳手腕脚本 FiveM插件网优质资源的首选

你是否想在FiveM服务器中添加一个有趣的臂力大赛功能?本文将详细解析如何通过Lua脚本实现这一功能,涵盖客户端和服务器端的完整实现流程。

FiveM臂力大赛脚本安装指南

在FiveM服务器中添加臂力大赛功能是一个非常有趣的玩法,玩家可以通过快速按键来与对手进行臂力比拼。本文将详细解析如何通过Lua脚本来实现这一功能,涵盖客户端和服务器端的完整实现流程。文末附VIP专属资源包,加入VIP即可获取完整资源包+专属客服。

客户端脚本解析(client.lua)

客户端脚本主要负责玩家的动作、动画播放、按键检测以及与服务器的通信。以下是核心代码的详细解析:

local QBCore = exports['qb-core']:GetCoreObject()
local isWrestling = false
local waitingForOpponent = false
local currentOpponent = nil
local wrestlingProps = {}
local mashing = false
local inWrestling = false
local countdownActive = false
local positioningInProgress = false
local playerStrength = 0
local opponentStrength = 0
local centerPosition = 50 -- 中心位置(中立)
local currentPosition = 50 -- 当前臂力大赛的位置
local winThreshold = 100 -- 获胜的位置
local loseThreshold = 0 -- 失败的位置
local vsAI = false -- AI对手标志
local aiDifficulty = 1 -- AI难度(1=简单,2=中等,3=困难)
local QBCore = exports['qb-core']:GetCoreObject()
local isWrestling = false
local waitingForOpponent = false
local currentOpponent = nil
local wrestlingProps = {}
local mashing = false
local inWrestling = false
local countdownActive = false
local positioningInProgress = false
local playerStrength = 0
local opponentStrength = 0
local centerPosition = 50 -- 中心位置(中立)
local currentPosition = 50 -- 当前臂力大赛的位置
local winThreshold = 100 -- 获胜的位置
local loseThreshold = 0 -- 失败的位置
local vsAI = false -- AI对手标志
local aiDifficulty = 1 -- AI难度(1=简单,2=中等,3=困难)
local QBCore = exports['qb-core']:GetCoreObject() local isWrestling = false local waitingForOpponent = false local currentOpponent = nil local wrestlingProps = {} local mashing = false local inWrestling = false local countdownActive = false local positioningInProgress = false local playerStrength = 0 local opponentStrength = 0 local centerPosition = 50 -- 中心位置(中立) local currentPosition = 50 -- 当前臂力大赛的位置 local winThreshold = 100 -- 获胜的位置 local loseThreshold = 0 -- 失败的位置 local vsAI = false -- AI对手标志 local aiDifficulty = 1 -- AI难度(1=简单,2=中等,3=困难)

动画字典与动画名称

local animDicts = {
['enter'] = 'mini@arm_wrestling',
['idle'] = 'mini@arm_wrestling',
['playing'] = 'mini@arm_wrestling',
['win'] = 'mini@arm_wrestling',
['lose'] = 'mini@arm_wrestling'
}
local animNames = {
['enter'] = 'aw_ig_intro_alt1_a', -- 玩家A的介绍动画
['enterWaiting'] = 'aw_ig_intro_alt1_a',
['idle'] = 'nuetral_idle_a',
['idleWaiting'] = 'nuetral_idle_a',
['playing'] = 'sweep_a', -- 玩家A的挣扎动画
['win'] = 'win_a_ped_a', -- 玩家A的获胜动画
['lose'] = 'win_a_ped_b' -- 玩家A的失败动画(玩家B获胜)
}
local animDicts = {
    ['enter'] = 'mini@arm_wrestling',
    ['idle'] = 'mini@arm_wrestling',
    ['playing'] = 'mini@arm_wrestling',
    ['win'] = 'mini@arm_wrestling',
    ['lose'] = 'mini@arm_wrestling'
}

local animNames = {
    ['enter'] = 'aw_ig_intro_alt1_a',  -- 玩家A的介绍动画
    ['enterWaiting'] = 'aw_ig_intro_alt1_a',
    ['idle'] = 'nuetral_idle_a',       
    ['idleWaiting'] = 'nuetral_idle_a',
    ['playing'] = 'sweep_a',           -- 玩家A的挣扎动画
    ['win'] = 'win_a_ped_a',           -- 玩家A的获胜动画
    ['lose'] = 'win_a_ped_b'           -- 玩家A的失败动画(玩家B获胜)
}
local animDicts = { ['enter'] = 'mini@arm_wrestling', ['idle'] = 'mini@arm_wrestling', ['playing'] = 'mini@arm_wrestling', ['win'] = 'mini@arm_wrestling', ['lose'] = 'mini@arm_wrestling' } local animNames = { ['enter'] = 'aw_ig_intro_alt1_a', -- 玩家A的介绍动画 ['enterWaiting'] = 'aw_ig_intro_alt1_a', ['idle'] = 'nuetral_idle_a', ['idleWaiting'] = 'nuetral_idle_a', ['playing'] = 'sweep_a', -- 玩家A的挣扎动画 ['win'] = 'win_a_ped_a', -- 玩家A的获胜动画 ['lose'] = 'win_a_ped_b' -- 玩家A的失败动画(玩家B获胜) }

AI对手模型

local aiPedModel = "a_m_y_musclbeac_01" -- 海滩肌肉男 - 非常适合臂力大赛!
local aiPedHandle = nil
local aiPedModel = "a_m_y_musclbeac_01" -- 海滩肌肉男 - 非常适合臂力大赛!
local aiPedHandle = nil
local aiPedModel = "a_m_y_musclbeac_01" -- 海滩肌肉男 - 非常适合臂力大赛! local aiPedHandle = nil

安全播放动画的辅助函数

function PlaySafeAnim(ped, dict, anim, speedIn, speedOut, duration, flag)
if not DoesEntityExist(ped) then
return false
end
RequestAnimDict(dict)
local timeout = GetGameTimer() + 5000 -- 5秒超时
while not HasAnimDictLoaded(dict) and GetGameTimer() < timeout do
Citizen.Wait(100)
end
if HasAnimDictLoaded(dict) then
ClearPedTasks(ped) -- 清除任何现有动画
Citizen.Wait(10) -- 确保任务已清除
TaskPlayAnim(ped, dict, anim, speedIn, speedOut, duration, flag, 0, false, false, false)
-- 等待动画开始,但有超时
local animStartTimeout = GetGameTimer() + 1000 -- 1秒超时
while not IsEntityPlayingAnim(ped, dict, anim, 3) and GetGameTimer() < animStartTimeout do
Citizen.Wait(50)
end
if IsEntityPlayingAnim(ped, dict, anim, 3) then
return true
else
--print("Failed to start animation: " .. dict .. " - " .. anim)
end
else
--print("Failed to load animation dictionary: " .. dict)
end
return false
end
function PlaySafeAnim(ped, dict, anim, speedIn, speedOut, duration, flag)
    if not DoesEntityExist(ped) then
        return false
    end
    
    RequestAnimDict(dict)
    local timeout = GetGameTimer() + 5000 -- 5秒超时
    while not HasAnimDictLoaded(dict) and GetGameTimer() < timeout do
        Citizen.Wait(100)
    end
    
    if HasAnimDictLoaded(dict) then
        ClearPedTasks(ped) -- 清除任何现有动画
        Citizen.Wait(10) -- 确保任务已清除
        
        TaskPlayAnim(ped, dict, anim, speedIn, speedOut, duration, flag, 0, false, false, false)
        
        -- 等待动画开始,但有超时
        local animStartTimeout = GetGameTimer() + 1000 -- 1秒超时
        while not IsEntityPlayingAnim(ped, dict, anim, 3) and GetGameTimer() < animStartTimeout do
            Citizen.Wait(50)
        end
        
        if IsEntityPlayingAnim(ped, dict, anim, 3) then
            return true
        else
            --print("Failed to start animation: " .. dict .. " - " .. anim)
        end
    else
        --print("Failed to load animation dictionary: " .. dict)
    end
    
    return false
end
function PlaySafeAnim(ped, dict, anim, speedIn, speedOut, duration, flag) if not DoesEntityExist(ped) then return false end RequestAnimDict(dict) local timeout = GetGameTimer() + 5000 -- 5秒超时 while not HasAnimDictLoaded(dict) and GetGameTimer() < timeout do Citizen.Wait(100) end if HasAnimDictLoaded(dict) then ClearPedTasks(ped) -- 清除任何现有动画 Citizen.Wait(10) -- 确保任务已清除 TaskPlayAnim(ped, dict, anim, speedIn, speedOut, duration, flag, 0, false, false, false) -- 等待动画开始,但有超时 local animStartTimeout = GetGameTimer() + 1000 -- 1秒超时 while not IsEntityPlayingAnim(ped, dict, anim, 3) and GetGameTimer() < animStartTimeout do Citizen.Wait(50) end if IsEntityPlayingAnim(ped, dict, anim, 3) then return true else --print("Failed to start animation: " .. dict .. " - " .. anim) end else --print("Failed to load animation dictionary: " .. dict) end return false end

注册臂力大赛道具

Citizen.CreateThread(function()
while true do
Citizen.Wait(1000)
local objects = GetGamePool('CObject')
for _, object in pairs(objects) do
if GetEntityModel(object) == GetHashKey('prop_arm_wrestle_01') then
if not wrestlingProps[object] then
wrestlingProps[object] = {
waiting = nil,
playerA = nil,
playerB = nil,
inProgress = false
}
end
end
end
end
end)
Citizen.CreateThread(function()
    while true do
        Citizen.Wait(1000)
        local objects = GetGamePool('CObject')
        for _, object in pairs(objects) do
            if GetEntityModel(object) == GetHashKey('prop_arm_wrestle_01') then
                if not wrestlingProps[object] then
                    wrestlingProps[object] = {
                        waiting = nil,
                        playerA = nil,
                        playerB = nil,
                        inProgress = false
                    }
                end
            end
        end
    end
end)
Citizen.CreateThread(function() while true do Citizen.Wait(1000) local objects = GetGamePool('CObject') for _, object in pairs(objects) do if GetEntityModel(object) == GetHashKey('prop_arm_wrestle_01') then if not wrestlingProps[object] then wrestlingProps[object] = { waiting = nil, playerA = nil, playerB = nil, inProgress = false } end end end end end)

加载动画

Citizen.CreateThread(function()
for _, dict in pairs(animDicts) do
RequestAnimDict(dict)
while not HasAnimDictLoaded(dict) do
Citizen.Wait(10)
end
end
RequestAnimDict("amb@world_human_push_ups@male@base")
while not HasAnimDictLoaded("amb@world_human_push_ups@male@base") do
Citizen.Wait(10)
end
end)
Citizen.CreateThread(function()
    for _, dict in pairs(animDicts) do
        RequestAnimDict(dict)
        while not HasAnimDictLoaded(dict) do
            Citizen.Wait(10)
        end
    end
    RequestAnimDict("amb@world_human_push_ups@male@base")
    while not HasAnimDictLoaded("amb@world_human_push_ups@male@base") do
        Citizen.Wait(10)
    end
end)
Citizen.CreateThread(function() for _, dict in pairs(animDicts) do RequestAnimDict(dict) while not HasAnimDictLoaded(dict) do Citizen.Wait(10) end end RequestAnimDict("amb@world_human_push_ups@male@base") while not HasAnimDictLoaded("amb@world_human_push_ups@male@base") do Citizen.Wait(10) end end)

服务器端脚本解析(server.lua)

服务器端脚本主要负责管理玩家之间的匹配、比赛状态的同步以及比赛结果的处理。以下是核心代码的详细解析:

if IsDuplicityVersion() then
local wrestlingTables = {}
-- 注册玩家为等待状态
RegisterNetEvent("qb-armwrestling:registerAsWaiting")
AddEventHandler("qb-armwrestling:registerAsWaiting", function(entityId)
local src = source
if not wrestlingTables[entityId] then
wrestlingTables[entityId] = {
waiting = src,
inProgress = false,
playerA = nil,
playerB = nil
}
else
wrestlingTables[entityId].waiting = src
end
end)
if IsDuplicityVersion() then
    local wrestlingTables = {}
    
    -- 注册玩家为等待状态
    RegisterNetEvent("qb-armwrestling:registerAsWaiting")
    AddEventHandler("qb-armwrestling:registerAsWaiting", function(entityId)
        local src = source
        
        if not wrestlingTables[entityId] then
            wrestlingTables[entityId] = {
                waiting = src,
                inProgress = false,
                playerA = nil,
                playerB = nil
            }
        else
            wrestlingTables[entityId].waiting = src
        end
    end)
if IsDuplicityVersion() then local wrestlingTables = {} -- 注册玩家为等待状态 RegisterNetEvent("qb-armwrestling:registerAsWaiting") AddEventHandler("qb-armwrestling:registerAsWaiting", function(entityId) local src = source if not wrestlingTables[entityId] then wrestlingTables[entityId] = { waiting = src, inProgress = false, playerA = nil, playerB = nil } else wrestlingTables[entityId].waiting = src end end)

开始比赛

RegisterNetEvent("qb-armwrestling:startMatch")
AddEventHandler("qb-armwrestling:startMatch", function(entityId, playerA, playerB)
local tableInfo = wrestlingTables[entityId]
if tableInfo and tableInfo.waiting == playerA and not tableInfo.inProgress then
tableInfo.inProgress = true
tableInfo.waiting = nil
tableInfo.playerA = playerA
tableInfo.playerB = playerB
-- 获取实体坐标以同步玩家位置
local ent = NetworkGetEntityFromNetworkId(entityId)
local coords = GetEntityCoords(ent)
local heading = GetEntityHeading(ent)
-- 定位玩家
TriggerClientEvent("qb-armwrestling:positionPlayers", -1, entityId, playerA, playerB, coords, heading)
-- 初始化臂力大赛值
tableInfo.position = 50 -- 中立位置
end
end)
RegisterNetEvent("qb-armwrestling:startMatch")
AddEventHandler("qb-armwrestling:startMatch", function(entityId, playerA, playerB)
    local tableInfo = wrestlingTables[entityId]
    
    if tableInfo and tableInfo.waiting == playerA and not tableInfo.inProgress then
        tableInfo.inProgress = true
        tableInfo.waiting = nil
        tableInfo.playerA = playerA
        tableInfo.playerB = playerB
        
        -- 获取实体坐标以同步玩家位置
        local ent = NetworkGetEntityFromNetworkId(entityId)
        local coords = GetEntityCoords(ent)
        local heading = GetEntityHeading(ent)
        
        -- 定位玩家
        TriggerClientEvent("qb-armwrestling:positionPlayers", -1, entityId, playerA, playerB, coords, heading)
        
        -- 初始化臂力大赛值
        tableInfo.position = 50 -- 中立位置
    end
end)
RegisterNetEvent("qb-armwrestling:startMatch") AddEventHandler("qb-armwrestling:startMatch", function(entityId, playerA, playerB) local tableInfo = wrestlingTables[entityId] if tableInfo and tableInfo.waiting == playerA and not tableInfo.inProgress then tableInfo.inProgress = true tableInfo.waiting = nil tableInfo.playerA = playerA tableInfo.playerB = playerB -- 获取实体坐标以同步玩家位置 local ent = NetworkGetEntityFromNetworkId(entityId) local coords = GetEntityCoords(ent) local heading = GetEntityHeading(ent) -- 定位玩家 TriggerClientEvent("qb-armwrestling:positionPlayers", -1, entityId, playerA, playerB, coords, heading) -- 初始化臂力大赛值 tableInfo.position = 50 -- 中立位置 end end)

更新玩家力量

RegisterNetEvent("qb-armwrestling:updateStrength")
AddEventHandler("qb-armwrestling:updateStrength", function(playerSrc, opponentSrc, strength)
for entityId, tableInfo in pairs(wrestlingTables) do
if tableInfo.inProgress and
((tableInfo.playerA == playerSrc and tableInfo.playerB == opponentSrc) or
(tableInfo.playerA == opponentSrc and tableInfo.playerB == playerSrc)) then
-- 根据玩家推力更新位置
if tableInfo.playerA == playerSrc then
tableInfo.position = tableInfo.position + (strength * 0.5)
else
tableInfo.position = tableInfo.position - (strength * 0.5)
end
-- 确保位置在范围内
tableInfo.position = math.max(0, math.min(100, tableInfo.position))
-- 广播更新后的位置给双方玩家
TriggerClientEvent("qb-armwrestling:updatePosition", tableInfo.playerA, tableInfo.position)
TriggerClientEvent("qb-armwrestling:updatePosition", tableInfo.playerB, 100 - tableInfo.position)
-- 检查获胜条件
if tableInfo.position >= 100 then
-- 玩家A获胜
EndMatch(entityId, tableInfo.playerA, tableInfo.playerB)
elseif tableInfo.position <= 0 then
-- 玩家B获胜
EndMatch(entityId, tableInfo.playerB, tableInfo.playerA)
end
break
end
end
end)
RegisterNetEvent("qb-armwrestling:updateStrength")
AddEventHandler("qb-armwrestling:updateStrength", function(playerSrc, opponentSrc, strength)
    for entityId, tableInfo in pairs(wrestlingTables) do
        if tableInfo.inProgress and 
          ((tableInfo.playerA == playerSrc and tableInfo.playerB == opponentSrc) or
           (tableInfo.playerA == opponentSrc and tableInfo.playerB == playerSrc)) then
            
            -- 根据玩家推力更新位置
            if tableInfo.playerA == playerSrc then
                tableInfo.position = tableInfo.position + (strength * 0.5)
            else
                tableInfo.position = tableInfo.position - (strength * 0.5)
            end
            
            -- 确保位置在范围内
            tableInfo.position = math.max(0, math.min(100, tableInfo.position))
            
            -- 广播更新后的位置给双方玩家
            TriggerClientEvent("qb-armwrestling:updatePosition", tableInfo.playerA, tableInfo.position)
            TriggerClientEvent("qb-armwrestling:updatePosition", tableInfo.playerB, 100 - tableInfo.position)
            
            -- 检查获胜条件
            if tableInfo.position >= 100 then
                -- 玩家A获胜
                EndMatch(entityId, tableInfo.playerA, tableInfo.playerB)
            elseif tableInfo.position <= 0 then
                -- 玩家B获胜
                EndMatch(entityId, tableInfo.playerB, tableInfo.playerA)
            end
            
            break
        end
    end
end)
RegisterNetEvent("qb-armwrestling:updateStrength") AddEventHandler("qb-armwrestling:updateStrength", function(playerSrc, opponentSrc, strength) for entityId, tableInfo in pairs(wrestlingTables) do if tableInfo.inProgress and ((tableInfo.playerA == playerSrc and tableInfo.playerB == opponentSrc) or (tableInfo.playerA == opponentSrc and tableInfo.playerB == playerSrc)) then -- 根据玩家推力更新位置 if tableInfo.playerA == playerSrc then tableInfo.position = tableInfo.position + (strength * 0.5) else tableInfo.position = tableInfo.position - (strength * 0.5) end -- 确保位置在范围内 tableInfo.position = math.max(0, math.min(100, tableInfo.position)) -- 广播更新后的位置给双方玩家 TriggerClientEvent("qb-armwrestling:updatePosition", tableInfo.playerA, tableInfo.position) TriggerClientEvent("qb-armwrestling:updatePosition", tableInfo.playerB, 100 - tableInfo.position) -- 检查获胜条件 if tableInfo.position >= 100 then -- 玩家A获胜 EndMatch(entityId, tableInfo.playerA, tableInfo.playerB) elseif tableInfo.position <= 0 then -- 玩家B获胜 EndMatch(entityId, tableInfo.playerB, tableInfo.playerA) end break end end end)

总结

通过以上代码,我们可以在FiveM服务器中实现一个完整的臂力大赛功能。客户端负责玩家的动作和动画播放,服务器端则负责比赛的管理和同步。如果你对FiveM脚本开发感兴趣,欢迎访问FiveM插件网获取更多资源和教程。

加入VIP即可获取完整资源包+专属客服,享受更多FiveM插件开发的乐趣!

© 版权声明
THE END
喜欢就支持一下吧
点赞13 分享
评论 共2条
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片快捷回复