Gravity Gun
Older/Work In Progress Page
- This page was initially written for an older version of Helix, has not been updated, and may be out of date!
- Contributions are more than welcome (see buttons at the top right of the page).
How to create a simple Gravity Gun to move Props around.
Final result#
Code Snippet#
Add the following code to Server/Index.lua
file inside the package.
Server/Index.lua
-- Spawns some Props and Static Meshes
-- (note: Static Meshes don't have physics so they will freeze where released automatically)
local p_sphere = Prop(Vector(200, 0, 200), Rotator(), "helix::SM_Sphere")
local p_cone = Prop(Vector(200, 0, 200), Rotator(), "helix::SM_Cone")
local sm_cube = StaticMesh(Vector(100, 0, 200), Rotator(), "helix::SM_Cube")
local sm_cylinder = StaticMesh(Vector(300, 0, 200), Rotator(), "helix::SM_Cylinder")
-- Subscribe for Client's custom event, for when the object is grabbed/dropped
Events.SubscribeRemote("PickUp", function(player, object, is_grabbing)
object:SetGravityEnabled(not is_grabbing)
object:TranslateTo(object:GetLocation(), 0)
end)
-- Subscribe for Client's custom event, to update the position of the object he is grabbing
Events.SubscribeRemote("UpdateObjectPosition", function(player, object, location)
object:TranslateTo(location, 0.1)
end)
Client/Index.lua
-- Global Variables
picking_object = nil
distance_trace_object = nil
distance = 200
-- Sets the color of Highlighing at index 1
Client.SetHighlightColor(Color(0, 20, 20, 1.5), 1, HighlightMode.OnlyVisible)
-- When Player clicks
Input.Subscribe("MouseUp", function(key_name)
-- If mouse was left button
if (key_name == "LeftMouseButton") then
-- If is grabbing something, drop it
if (picking_object) then
-- Calls server to re-enable gravity (if possible) and update it's last position
Events.CallRemote("PickUp", picking_object, false)
-- Disables the highlight
picking_object:SetHighlightEnabled(false)
picking_object = nil
return
end
-- Get the camera location in 3D World Space
local viewport_2D_center = Viewport.GetViewportSize() / 2
local viewport_3D = Viewport.DeprojectScreenToWorld(viewport_2D_center)
local start_location = viewport_3D.Position
-- Gets the end location of the trace (5000 units ahead)
local trace_max_distance = 5000
local end_location = viewport_3D.Position + viewport_3D.Direction * trace_max_distance
-- Determine at which object we will be tracing for (WorldStatic - StaticMeshes - and PhysicsBody - Props)
local collision_trace = CollisionChannel.WorldStatic | CollisionChannel.PhysicsBody
-- Sets the trace modes (we want it to return Entity and Draws a Debug line)
local trace_mode = TraceMode.ReturnEntity | TraceMode.DrawDebug
-- Do the Trace
local trace_result = Trace.LineSingle(start_location, end_location, collision_trace, trace_mode)
-- If hit something and hit an Entity
if (trace_result.Success and trace_result.Entity) then
-- Sets the new picked up object
picking_object = trace_result.Entity
-- Calculates the offset of the hit and the center of the object
distance_trace_object = picking_object:GetLocation() - trace_result.Location
-- Calculates the distance of the object and the camera
distance = trace_result.Location:Distance(viewport_3D.Position)
-- Calls remote to disable gravity of this object (if has)
Events.CallRemote("PickUp", picking_object, true)
-- Enable Highlighting on index 1
picking_object:SetHighlightEnabled(true, 1)
end
end
end)
Input.Subscribe("MouseScroll", function(mouse_x, mouse_y, delta)
-- If mouse scroll, updates the Distance of the object from the camera
localdistance = distance + delta * 55
if (distance < 100) then distance = 100 end
end)
Client.Subscribe("Tick", function(delta_time)
-- On Tick, updates the Position of the object, based on it's distance and camera rotation
if (picking_object == nil) then return end
local player = Client.GetLocalPlayer()
if (player == nil) then return end
-- Get the camera location in 3D World Space
local viewport_2D_center = Viewport.GetViewportSize() / 2
local viewport_3D = Viewport.DeprojectScreenToWorld(viewport_2D_center)
local start_location = viewport_3D.Position
-- Gets the new object location
-- (camera direction * 'distance' units ahead + object offset from first Hit to keep it relative)
local end_location = (viewport_3D.Position + viewport_3D.Direction * distance) + distance_trace_object
-- Calls remote to update it's location
Events.CallRemote("UpdateObjectPosition", picking_object, end_location)
end)