279 lines
8.5 KiB
Lua
279 lines
8.5 KiB
Lua
local ent = ent
|
|
local scene = entities.currentScene()
|
|
local metadataJson = ent:getComponent("Metadata")
|
|
local transform = ent:getComponent("Transform")
|
|
local physicsBody = ent:getComponent("PhysicsBody")
|
|
local camera = ent:getComponent("Camera")
|
|
local cameraTransform = camera:getTransform()
|
|
|
|
local fixedCamera = metadataJson["camera"]["settings"]["fixed"]
|
|
|
|
-- setup all timers
|
|
local timers = {
|
|
use = Timer.new(),
|
|
holp = Timer.new(),
|
|
flashlight = Timer.new(),
|
|
physcannon = Timer.new()
|
|
}
|
|
if not timers.use:running() then timers.use:start(); end
|
|
if not timers.holp:running() then timers.holp:start(); end
|
|
if not timers.flashlight:running() then timers.flashlight:start(); end
|
|
if not timers.physcannon:running() then timers.physcannon:start(); end
|
|
|
|
-- setup held object locals
|
|
local heldObject = {
|
|
uid = 0,
|
|
distance = 0,
|
|
smoothSpeed = 4,
|
|
scrollSpeed = 32,
|
|
momentum = Vector3f(0,0,0),
|
|
rotate = false,
|
|
}
|
|
-- setup light locals
|
|
local light = {
|
|
entity = nil,
|
|
}
|
|
for k, v in pairs(ent:getChildren()) do
|
|
if type(v) == "number" then
|
|
goto continue
|
|
end
|
|
if v:name() == "Light" then
|
|
light.entity = v
|
|
end
|
|
::continue::
|
|
end
|
|
|
|
if light.entity == nil then
|
|
light.entity = ent:loadChild("./playerLight.json",true)
|
|
end
|
|
light.metadata = light.entity:getComponent("LightBehavior::Metadata")
|
|
light.transform = light.entity:getComponent("Transform")
|
|
light.power = light.metadata.power
|
|
light.origin = Vector3f(light.transform.position)
|
|
light.metadata.power = 0
|
|
--light.entity:setComponent("Metadata", { light = { power = 0 } })
|
|
|
|
-- sound emitter
|
|
local playSound = function( key, loop )
|
|
if not loop then loop = false end
|
|
local url = "/ui/" .. key .. ".ogg"
|
|
ent:callHook("sound:Emit.%UID%", {
|
|
filename = string.resolveURI(url, metadataJson["system"]["root"]),
|
|
spatial = true,
|
|
streamed = true,
|
|
volume = "sfx",
|
|
loop = loop
|
|
}, 0)
|
|
end
|
|
local stopSound = function( key )
|
|
local url = "/ui/" .. key .. ".ogg"
|
|
ent:callHook("sound:Stop.%UID%", {
|
|
filename = string.resolveURI(url, metadataJson["system"]["root"])
|
|
}, 0)
|
|
end
|
|
|
|
local useDistance = 6
|
|
local pullDistance = useDistance * 4
|
|
|
|
local function tickFlashlight( transform, axes, inputs )
|
|
-- update light position
|
|
if light.enabled then
|
|
local center = transform.position
|
|
local direction = axes.forward * 8
|
|
local offset = 0.25
|
|
local _, depth = physicsBody:rayCast(center, direction)
|
|
depth = math.clamp(depth, 0, 0.5)
|
|
light.transform.position = center + direction * (depth - offset)
|
|
end
|
|
|
|
-- toggle
|
|
if timers.flashlight:elapsed() > 0.5 and inputs["F"] then
|
|
timers.flashlight:reset()
|
|
light.enabled = (light.metadata.power ~= light.power)
|
|
light.metadata.power = light.enabled and light.power or 0
|
|
playSound("flashlight")
|
|
end
|
|
end
|
|
|
|
local function onUse( payload )
|
|
local validUse = false
|
|
-- not currently holding anything, and hit something
|
|
if heldObject.uid == 0 and payload.depth > 0 then
|
|
local prop = entities.get( payload.uid )
|
|
local propMetadata = prop:getComponent("Metadata")
|
|
-- entity is holdable, pick it up
|
|
if propMetadata["holdable"] then
|
|
validUse = true
|
|
local heldObjectTransform = prop:getComponent("Transform")
|
|
local heldObjectFlattened = heldObjectTransform:flatten()
|
|
local offset = transform.position - heldObjectFlattened.position
|
|
|
|
heldObject.uid = payload.uid
|
|
heldObject.distance = offset:norm()
|
|
|
|
local heldObjectPhysicsBody = prop:getComponent("PhysicsBody")
|
|
heldObjectPhysicsBody:enableGravity(false)
|
|
else
|
|
validUse = not string.matched( prop:name(), "/^worldspawn/" )
|
|
end
|
|
-- currently holding something, drop it
|
|
elseif heldObject.uid ~= 0 then
|
|
validUse = true
|
|
local prop = entities.get( heldObject.uid )
|
|
local heldObjectPhysicsBody = prop:getComponent("PhysicsBody")
|
|
heldObjectPhysicsBody:enableGravity(true)
|
|
heldObjectPhysicsBody:applyImpulse( heldObject.momentum )
|
|
|
|
heldObject.uid = 0
|
|
heldObject.distance = 0
|
|
heldObject.momentum = Vector3f(0,0,0)
|
|
end
|
|
|
|
playSound(validUse and "select" or "deny")
|
|
end
|
|
|
|
local function tickUse( transform, axes, inputs )
|
|
-- trigger use
|
|
if timers.use:elapsed() > 0.5 and inputs["E"] then
|
|
timers.use:reset()
|
|
local center = transform.position
|
|
local direction = axes.forward * useDistance
|
|
local prop, depth = physicsBody:rayCast(center, direction)
|
|
|
|
local payload = {
|
|
user = ent:uid(),
|
|
uid = prop and prop:uid() or 0,
|
|
depth = depth,
|
|
}
|
|
if prop then prop:lazyCallHook("entity:Use.%UID%", payload) end
|
|
ent:lazyCallHook("entity:Use.%UID%", payload)
|
|
end
|
|
end
|
|
|
|
local function tickGravGun( transform, axes, inputs )
|
|
-- not holding anything
|
|
if heldObject.uid == 0 then
|
|
-- try and launch object in sights
|
|
if inputs["mouse2"] then
|
|
local center = transform.position
|
|
local direction = axes.forward * pullDistance
|
|
local prop, depth = physicsBody:rayCast( center, direction )
|
|
if depth >= 0 and prop and not string.matched( prop:name(), "/^worldspawn/" ) then
|
|
local heldObjectTransform = prop:getComponent("Transform")
|
|
local heldObjectPhysicsBody = prop:getComponent("PhysicsBody")
|
|
|
|
local strength = 500
|
|
local distanceSquared = (heldObjectTransform.position - transform.position):magnitude()
|
|
|
|
heldObjectPhysicsBody:applyImpulse( axes.forward * -heldObjectPhysicsBody:getMass() * strength / distanceSquared )
|
|
if timers.physcannon:elapsed() > 1.0 then
|
|
timers.physcannon:reset()
|
|
|
|
playSound("phys_tooHeavy")
|
|
end
|
|
end
|
|
end
|
|
-- holding something
|
|
else
|
|
-- adjust hold distance
|
|
if inputs["wheel"] ~= 0 then
|
|
heldObject.distance = heldObject.distance + (inputs["wheel"] / 120 * heldObject.scrollSpeed) * time.delta()
|
|
end
|
|
-- update rotation mode
|
|
if inputs["mouse3"] then
|
|
heldObject.rotate = not heldObject.rotate
|
|
end
|
|
|
|
local prop = entities.get( heldObject.uid )
|
|
local heldObjectTransform = prop:getComponent("Transform")
|
|
local heldObjectPhysicsBody = prop:getComponent("PhysicsBody")
|
|
|
|
-- launch held object
|
|
if inputs["mouse1"] and timers.physcannon:elapsed() > 0.5 then
|
|
timers.physcannon:reset()
|
|
|
|
heldObject.uid = 0
|
|
heldObjectPhysicsBody:enableGravity(true)
|
|
heldObjectPhysicsBody:applyImpulse( axes.forward * heldObjectPhysicsBody:getMass() * 50 )
|
|
|
|
playSound("phys_launch"..math.random(1,4))
|
|
else
|
|
-- update rotation
|
|
if heldObject.rotate then
|
|
--heldObjectTransform.orientation = Quaternion.lookAt( (heldObjectTransform.position - transform.position):normalize(), axes.up )
|
|
heldObjectTransform.orientation = cameraTransform:flatten().orientation
|
|
end
|
|
|
|
-- move held object
|
|
local forward = axes.forward * heldObject.distance
|
|
if heldObject.smoothSpeed ~= 0 then
|
|
local heldObjectFlattened = heldObjectTransform:flatten()
|
|
|
|
local target = transform.position + forward
|
|
local offset = target - heldObjectFlattened.position
|
|
|
|
local stiffness = 15.0
|
|
local damping = 2.0
|
|
local currentVelocity = heldObjectPhysicsBody:getVelocity()
|
|
local mass = heldObjectPhysicsBody:getMass()
|
|
|
|
local springForce = offset * stiffness
|
|
local dampingForce = currentVelocity * -damping
|
|
|
|
heldObjectPhysicsBody:applyImpulse((springForce + dampingForce) * mass * time.delta())
|
|
else
|
|
heldObjectTransform.position = transform.position + forward
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
-- on tick
|
|
ent:bind( "tick", function(self)
|
|
local inControl = scene:globalFindByName("Gui: Menu"):uid() == 0
|
|
|
|
local inputs = {
|
|
E = inputs.key("E") or inputs.key("R_Y"),
|
|
F = inputs.key("F"),
|
|
mouse1 = inputs.key("Mouse1") or inputs.key("L_TRIGGER"),
|
|
mouse2 = inputs.key("Mouse2") or inputs.key("R_TRIGGER"),
|
|
mouse3 = inputs.key("Mouse3"),
|
|
wheel = inputs.analog("MouseWheel"),
|
|
}
|
|
|
|
if not inControl then
|
|
inputs["E"] = false
|
|
inputs["F"] = false
|
|
inputs["mouse1"] = false
|
|
inputs["mouse2"] = false
|
|
inputs["mouse3"] = false
|
|
inputs["wheel"] = 0
|
|
end
|
|
|
|
-- eye transform
|
|
local flattenedTransform = fixedCamera and transform:flatten() or cameraTransform:flatten()
|
|
local axes = flattenedTransform:axes()
|
|
|
|
-- update flashlight
|
|
tickFlashlight( flattenedTransform, axes, inputs )
|
|
|
|
-- update use
|
|
tickUse( flattenedTransform, axes, inputs )
|
|
|
|
-- update HOLP
|
|
tickGravGun( flattenedTransform, axes, inputs )
|
|
|
|
-- get collision events
|
|
--[[
|
|
local collisionEvents = physicsBody:getCollisionEvents()
|
|
for i, event in ipairs(collisionEvents) do
|
|
print( event.state, event.a, event.b, event.point, event.normal, event.impulse )
|
|
end
|
|
]]
|
|
end )
|
|
|
|
-- on use
|
|
ent:addHook( "entity:Use.%UID%", function( payload )
|
|
if payload.user ~= ent:uid() then return end
|
|
onUse( payload )
|
|
end ) |