实现 blaster 行为 是编程爆炸机械人在第一人称射击体验中的过程。虽然玩家可以用单击或按钮的单击来爆炸,但创建令人满意和准确的爆炸行为是重要的,因为它会增强玩家的总体游戏体验。
使用示例激光标记体验作为参考,这个教程的第二部分教你了解两种不同类型的激光器的实现方法,包括有关:
- 检测玩家是否按下爆炸按钮。
- 检查玩家是否可以使用他们的冲击枪,如果他们刚刚按下了爆炸按钮。
- 生成告诉服务器谁启动了爆炸、它从哪里来的和每个激光束的最终目的地的爆炸数据。
- 通知服务器,以便它可以在爆炸与另一名玩家碰撞时执行适当的行动。
- 在每次爆炸之间重置激光,让激光有足够的时间来冷却,以便它可以再次爆炸。
完成此部分后,您将了解允许激光与其他玩家碰撞时检测的脚本,然后根据每个激光输入型 deduct 相应的生命值。
检测玩家输入
实现 Blaster 行为的第一个步骤是听到玩家按下爆炸按钮的时候。 输入类型由玩家使用来按下爆炸按钮依赖于他们使用的设备。 例如,复制存储中的示例激光标签体验支持鼠标和键盘控控制、游戏手柄和触摸控控制。 您可以在 ReplicatedStorage > 用户输入处理器 此客户端脚本使用 ContextActionService 来将 MouseButton1 和 ButtonR2 绑定到爆炸操动作。这意味着每次玩家按下左键或游戏手柄的 R2 按钮时,都会触发激光从 blaster 中发射。注意,
用户输入处理器
ContextActionService:BindAction("_", onBlasterActivated, false,Enum.UserInputType.MouseButton1,Enum.KeyCode.ButtonR2)
另一个重要的注意事项是在 Enum.UserInputState.Begin 定义中使用 Enu
要示例,您可以将 Enum.UserInputState.Begin 变更为 Enum.UserInputState.End ,然后玩测试以确定爆炸对体验的游戏玩法有何影响。例如,如果玩家可以按住按钮 without triggering the blast,如何这可能会改变他们的体验标记其他玩家时?
用户输入处理器
local function onBlasterActivated(_actionName: string,
inputState: Enum.UserInputState, _inputObject: InputObject)
if inputState == Enum.UserInputState.End then -- 更新了行,请确保返回
attemptBlastClient()
end
end
检查玩家是否可以爆炸
UserInputHandler 检测到一个按钮或屏服务器触摸后,它会调用 ReplicatedStorage > Blaster</
可以本地玩家爆炸
local function canLocalPlayerBlast(): boolean
return localPlayer:GetAttribute(PlayerAttribute.blasterStateClient) == BlasterState.Ready
end
如果您
此轻度暂停会阻止您尽可能快地单击。例如,如果您将函数更改为 always return true,您可以快速爆炸您的冲击枪,无视激光标签游戏的延迟,这是对于激光标签游戏的不真实。
可以本地玩家爆炸
local function canLocalPlayerBlast(): boolean
return true -- 更新了行,请确保返回
end
生成爆炸数据
在验证玩家的 blaster 在 Ready 状态后,attemptBlastClient 调用 ReplicatedStorage > 1> attemptBlastClient1> > 4> blastClient4> 。 第一步,
下一步是生成爆炸数据。如果您查看 ReplicatedStorage > Blaster > BlastData ,您可以看到每个爆炸包含三个信息块:
- 发生爆炸的玩家。
- 一个 DataType.CFrame 代表爆炸的起始点。
- 一个 RayResult 表,包含每个激光波的最终目的地和命中玩家,如果命中另一个玩家。
要生成此数据,blastClient 调用ReplicatedStorage > attemptBlastClient > 2> blastClient2> > 5> generateBlastData5>,您可以在下面查看。
生成爆炸数据
local function generateBlastData(): BlastData.Type
local blasterConfig = getBlasterConfig()
local rayDirections = getDirectionsForBlast(
currentCamera.CFrame, blasterConfig)
local rayResults = castLaserRay(
localPlayer, currentCamera.CFrame.Position, rayDirections)
local blastData: BlastData.Type = {
player = localPlayer,
originCFrame = currentCamera.CFrame,
rayResults = rayResults,
}
return blastData
end
此函数使用 getBlasterConfig 来检索玩家的激光输入。样例提供两种类型的激光:一个生成多个光束,覆盖横向布局,另一个生成单个光束。您可以在 ReplicatedStorage > Instances > 1> LaserBlastersFolder1> 中找到其配置。
然后,该函数使用 currentCamera.CFrame 作为爆炸的起始点,将其交给 getDirectionsForBlast 。在此时,代码不再是关于 Blaster,它是关于
向服务器发送通知
一旦 blastClient 有完整数据为爆炸,它会触发两个事件:
爆炸客户
local laserBlastedBindableEvent = ReplicatedStorage.Instances.LaserBlastedBindableEventlocal laserBlastedEvent = ReplicatedStorage.Instances.LaserBlastedEventlaserBlastedBindableEvent:Fire(blastData)laserBlastedEvent:FireServer(blastData)
Class.BindableEvent 向其他客户端脚本发布爆炸。例如, ReplicatedStorage > FirstPersonBlasterVisuals 使用此事件来知道显示视觉效果的时间,例如爆炸动画和冷却条。同样,1>Class.
激光冲击处理器
local function onLaserBlastedEvent(playerBlasted: Player, blastData: BlastData.Type)
local validatedBlastData = getValidatedBlastData(playerBlasted, blastData)
if not validatedBlastData then
return
end
if not canPlayerBlast(playerBlasted) then
return
end
blastServer(playerBlasted)
processTaggedPlayers(playerBlasted, blastData)
for _, replicateToPlayer in Players:GetPlayers() do
if playerBlasted == replicateToPlayer then
continue
end
replicateBlastEvent:FireClient(replicateToPlayer, playerBlasted, blastData)
end
end
为了帮助防止作弊,服务器必须验证每个客户端发送的所有数据。这些检查包括:
- 是否为BlastData表?它包含一个Class.CFrame和另一个名为rayResults的表?
- 玩家有没有装备了冲击波?
- 玩家有一个角色和一个地点在世界内吗?
- 发送爆炸数据后,玩家是否已经从发射激光柱的地方移动过度?
最后一步检查涉及判断调用,根据服务器的延迟和玩家移动速度,您可能会决定这些不同的值对于您自己的体验过于。要示例这个判断调用,您可以在 getValidatedBlastData 中添加打印声明,并且测试体验。
获取验证爆炸数据
local distanceFromCharacterToOrigin = blastData.originCFrame.Position - rootPartCFrame.Positionprint(distanceFromCharacterToOrigin.Magnitude) -- 更新了线,请确保移除if distanceFromCharacterToOrigin.Magnitude > ToleranceValues.DISTANCE_SANITY_CHECK_TOLERANCE_STUDS thenwarn(`Player {player.Name} failed an origin sanity check while blasting`)returnend
当你移动和爆炸时,请注意输出。它可能看起来像这样:
1.90196299552917483.15495586395263672.57428836822509774.80445861816406252.6434271335601807
如果您在 ReplicatedStorage > PlayerStateHandler > togglePlayerMovement 测试玩家移动速度,您将可能遇到许多因过度移动而导致的故障。
切换玩家移动
local ENABLED_WALK_SPEED = 60 -- updated line, be sure to change back
服务器然后会做到以关注中/正在关注:
- 验证 rayResults .
- 检查玩家是否可以爆炸。
- 重置激光状态。
- 降低任何受标签玩家的生命值。
- 复制爆炸到所有其他玩家,以便他们可以看到第三人称视觉。
了解有关此服务器操作的更多信息,请参阅检测命中部分的教程。
重置冲击波
在示例激光标记体验中,激光使用热机械。 而不是在一系列激光爆炸后重新加载,它们需要在每次激光爆炸之间“冷却”。 这种冷却延迟在客户端(blastClient)和服务器(blastServer)之间发生,服务器作为真实的源头。
爆炸服务器
local blasterConfig = getBlasterConfig(player)
local secondsBetweenBlasts = blasterConfig:GetAttribute("secondsBetweenBlasts")
task.delay(secondsBetweenBlasts, function()
local currentState = player:GetAttribute(PlayerAttribute.blasterStateServer)
if currentState == BlasterState.Blasting then
player:SetAttribute(PlayerAttribute.blasterStateServer, BlasterState.Ready)
end
end)
secondsBetweenBlasts 属性是 ReplicatedStorage > Instances > 1> LaserBlastersFolder1> 中的一部分。 在 4>secondsBetweenBlasts4> 延迟通过后,玩家可以再次爆炸,整个过程都会重复。 为了帮助玩家了解当他们可
在此时,玩家可以生成和重生,瞄准并爆炸,但体验仍然必须确定每次爆炸的结果。 在教程的下一部分,您将学习如何程序 blaster 检测到另一个玩家时击中时,然后根据 blaster 设置减少适当的玩家健康。