重力枪
如何制作一个简单的重力枪来四处移动道具。
最终结果
提示
你现在可以在沙盒游戏模式中找到功能完备的重力枪!
代码片段
Server/Index.lua
-- 生成一些道具和静态网格体
-- (注:静态网格体没有物理属性,因此释放后会自动冻结在原处)
local p_sphere = Prop(Vector(200, 0, 200), Rotator(), "nanos-world::SM_Sphere")
local p_cone = Prop(Vector(200, 0, 200), Rotator(), "nanos-world::SM_Cone")
local sm_cube = StaticMesh(Vector(100, 0, 200), Rotator(), "nanos-world::SM_Cube")
local sm_cylinder = StaticMesh(Vector(300, 0, 200), Rotator(), "nanos-world::SM_Cylinder")
-- 订阅客户端自定义事件,用于物体被抓取/丢弃时
Events.SubscribeRemote("GravityGun:Grab", function(player, object, is_grabbing)
object:SetGravityEnabled(not is_grabbing)
object:TranslateTo(object:GetLocation(), 0)
end)
-- 订阅客户端自定义事件,以更新其抓取物体的位置
Events.SubscribeRemote("GravityGun:Move", function(player, object, location)
object:TranslateTo(location, 0.1)
end)
提示
在永远不要信任客户端指南中了解有关校验远程事件的更多信息。
Client/Index.lua
-- 全局变量
picking_object = nil
distance_trace_object = nil
distance = 200
-- 设置索引 1 的高亮颜色
Client.SetHighlightColor(Color(0, 20, 20, 1.5), 1, HighlightMode.OnlyVisible)
-- 当玩家点击时
Input.Subscribe("MouseUp", function(key_name)
-- 如果鼠标是左键
if (key_name == "LeftMouseButton") then
-- 如果正在抓取某物,则放下它
if (picking_object) then
-- 调用服务器重新启用重力(如果可能)并更新其最后位置
Events.CallRemote("GravityGun:Grab", Reliability.Reliable, picking_object, false)
-- 禁用高亮
picking_object:SetHighlightEnabled(false)
picking_object = nil
return
end
-- 获取相机位置和玩家瞄准的方向
local local_player = Client.GetLocalPlayer()
local start_location = local_player:GetCameraLocation()
local direction = local_player:GetCameraRotation():GetForwardVector()
-- 获取追踪的终点位置(前方 5000 个单位)
local trace_max_distance = 5000
local end_location = start_location + direction * trace_max_distance
-- 确定要追踪的对象类型(WorldStatic - 静态网格体 - 以及 PhysicsBody - Prop)
local collision_trace = CollisionChannel.WorldStatic | CollisionChannel.PhysicsBody
-- 设置追踪模式(我们希望返回 Entity 并绘制调试线)
local trace_mode = TraceMode.ReturnEntity | TraceMode.DrawDebug
-- 执行追踪
local trace_result = Trace.LineSingle(start_location, end_location, collision_trace, trace_mode)
-- 如果击中某物且击中了一个 Entity
if (trace_result.Success and trace_result.Entity) then
-- 设置新抓取的对象
picking_object = trace_result.Entity
-- 计算击中点与物体中心之间的偏移
distance_trace_object = picking_object:GetLocation() - trace_result.Location
-- 计算物体与相机之间的距离
distance = trace_result.Location:Distance(start_location)
-- 调用远程以禁用此物体的重力(如果有)
Events.CallRemote("GravityGun:Grab", Reliability.Reliable, picking_object, true)
-- 在索引 1 上启用高亮
picking_object:SetHighlightEnabled(true, 1)
end
end
end)
-- 当鼠标滚轮滚动时,更新物体与相机之间的距离
Input.Subscribe("MouseScroll", function(mouse_x, mouse_y, delta)
if (picking_object == nil) then return end
-- 向上滚动时 delta 为正,向下滚动时为负
distance = math.max(distance + delta * 25, 100)
end)
Client.Subscribe("Tick", function(delta_time)
-- 在 Tick 时,根据距离和相机旋转更新物体的位置
if (picking_object == nil) then return end
-- 获取相机位置和玩家瞄准的方向
local local_player = Client.GetLocalPlayer()
local camera_location = local_player:GetCameraLocation()
local direction = local_player:GetCameraRotation():GetForwardVector()
-- 获取新的物体位置
-- (相机方向 * 'distance' 个单位前方 + 物体相对于首次击中的偏移以保持相对位置)
local end_location = (camera_location + direction * distance) + distance_trace_object
-- 调用远程以更新其位置。我们使用 Unreliable,因为这是每帧发送的,如果丢包,下一帧会自动纠正
Events.CallRemote("GravityGun:Move", Reliability.Unreliable, picking_object, end_location)
end)