Working on a an entity that is going to attach to door to open them, however an issue I have run into positioning the entity correctly.
Not really sure how to determine the correct angle and position for the entity relative to the parent (the door).
For reference, this is what it is supposed to look like on all doors (with exageratted jamming and reduced drill time):
https://www.youtube.com/watch?v=iRv0qlXnBMo
However on a lot of doors, the drill attaches to the wrong side and/or is facing the wrong direction like so:
https://i.imgur.com/Li3zdOY.jpg
This is currently how I am handling attaching:
if self.Attached then return end
if not table.HasValue(doors, ent:GetClass()) then return end
local pos = ent:GetPos()
local b1, b2 = ent:LookupBone("handle"), ent:LookupBone("handle02")
if b1 or b2 then
if b1 and b2 then
local p1, p2 = ent:GetBonePosition(b1), ent:GetBonePosition(b2)
local bone = p1:DistToSqr(self:GetPos()) < p2:DistToSqr(self:GetPos()) and b1 or b2
pos = b1 == bone and p1 or p2
else
pos = b1 and ent:GetBonePosition(b1) or ent:GetBonePosition(b2)
end
end
self.Attached = true
self:SetMoveType(MOVETYPE_NONE)
self:SetCollisionGroup(COLLISION_GROUP_WEAPON)
self:SetParent(ent)
self:SetPos(pos)
self:SetLocalPos(self:GetLocalPos() + Vector(10, 0, -11)) -- This is my problem area
self:SetLocalAngles(self:AlignAngles(self:GetAngles(), ent:GetAngles() + Angle(0, 0, 0))) -- So is this
damn, you beat me to it, i was gonna do this exact thing eventually
You could try taking the distance of where you currently have the position, and the position of the drill on the other side of the door (if that makes sense) and find which one is closer, and attach it at that position.
I feel like I didn't word that well...
Alright well guess I'll start debugging some more!
*Convoluted debugging hooks intensify*:
local doors = { ["prop_door_rotating"] = true, ["func_door"] = true, ["func_door_rotating"] = true }
hook.Add("PostDrawTranslucentRenderables", "DoorPos", function()
local drill = NULL
for _, e in ipairs(ents.FindInSphere(LocalPlayer():GetPos(), 500)) do
if e:GetClass() == "pd2_drill" then
drill = e
break
end
end
if IsValid(drill) then
local door = NULL
for _, e in ipairs(ents.FindInSphere(drill:GetPos(), 200)) do
if doors[e:GetClass()] then
door = e
break
end
end
if IsValid(door) then
local trace = util.TraceLine({
start = drill:GetPos(),
endpos = door:GetBonePosition(door:LookupBone("handle")) or door:GetPos(),
filter = function(e)
return e:EntIndex() == door:EntIndex()
end
})
local angle = trace.HitNormal:Angle()
render.DrawLine( trace.HitPos, trace.HitPos + 8 * angle:Forward(), Color( 255, 0, 0 ), false )
render.DrawLine( trace.HitPos, trace.HitPos + 8 * -angle:Right(), Color( 0, 255, 0 ), false )
render.DrawLine( trace.HitPos, trace.HitPos + 8 * angle:Up(), Color( 0, 0, 255 ), false )
render.DrawLine(drill:GetPos(), trace.HitPos, Color(255, 255, 255), false)
local pos = nil -- Where will we attach?
local b1, b2 = door:LookupBone("handle"), door:LookupBone("handle02")
if b1 or b2 then -- We have something to work with...
if b1 and b2 then -- Pick the closer one!
local p1, p2 = door:GetBonePosition(b1), door:GetBonePosition(b2)
local bone = p1:DistToSqr(drill:GetPos()) < p2:DistToSqr(drill:GetPos()) and b1 or b2
pos = b1 == bone and p1 or p2
else -- Pick whichever we have!
pos = b1 and door:GetBonePosition(b1) or door:GetBonePosition(b2)
end
else -- We're gonna guess!
pos = door:GetPos()
end
render.SetColorMaterial()
render.DrawSphere(pos, 1, 30, 30, Color(255, 255, 0))
local mass = 0
if not IsValid(door:GetPhysicsObject()) then
local dims = door:OBBMaxs() - door:OBBMins()
mass = dims.x * dims.y * dims.z
else
mass = door:GetPhysicsObject():GetMass()
end
cam.Start2D()
draw.SimpleText("MASS: " .. mass, "DermaDefault", ScrW() / 2, ScrH() / 2 - ScrH() / 4, Color(255, 255, 255), TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
cam.End2D()
end
end
end)
Didn't say it before but I also really wanted to make something like this and only had the idea a couple days ago. Excited to see how it turns out at least and I wish you the best of luck <3
On a serious note though isn't the position of an entity at (0,0) always in the top left(like with dermas)? If that's the case then you would just need to get the height and width of an entity to position the drill over the lock.
After that... Get the position of the drill? and set the angle relative to the drill's position?
Also is it necessary to get the handle position why not just use the door surface instead of the handle bone?
I'm just thinking of setting the drills position similarly to how you'd set the position/angle of cam3d2d so sorry if everything I said is redundant
I mostly have everything figured out now.
If you're curious how it looks so far, this is how the entity is attached when it touches a door, commented for your viewing pleasure:
local doors = { ["prop_door_rotating"] = true, ["func_door"] = true, ["func_door_rotating"] = true }
local states = { ["m_eDoorState"] = 0, ["m_toggle_state"] = 1, ["m_eDoorState"] = 1 }
function ENT:Touch(ent)
if self.Attached or not doors[ent:GetClass()] then return end -- Only doors please!
-- Only closed doors!
local data, closed = ent:GetSaveTable(), false
for state, value in pairs(states) do
if data[state] and data[state] == value then
closed = true
break
end
end
if not closed then return end
-- Time to figure out where to drill!
local pos, b1, b2 = ent:GetPos(), ent:LookupBone("handle"), ent:LookupBone("handle02") -- Where to attach?
if b1 or b2 then -- We have something to work with...
if b1 and b2 then -- Pick the closer one!
local p1, p2 = ent:GetBonePosition(b1), ent:GetBonePosition(b2)
local bone = p1:DistToSqr(self:GetPos()) < p2:DistToSqr(self:GetPos()) and b1 or b2
pos = b1 == bone and p1 or p2
else -- Pick whichever we have!
pos = b1 and ent:GetBonePosition(b1) or ent:GetBonePosition(b2)
end
end
-- Parenting to the door!
self:SetMoveType(MOVETYPE_NONE)
self:SetCollisionGroup(COLLISION_GROUP_WEAPON)
self:SetParent(ent)
-- Perform a trace to calcuate drill angles based on hit normal
local trace = util.TraceLine({
start = self:GetPos(),
endpos = pos,
filter = function(e)
return e:EntIndex() == ent:EntIndex() -- Not ideal but 100% accurate
end
})
-- Let's test positions to see where to put the drill, pick the closer
local angle, p1, p2 = trace.HitNormal:Angle(), pos + Vector(10, 0, -11), pos + Vector(-10, 0, -11)
pos = self:GetPos():DistToSqr(p1) < self:GetPos():DistToSqr(p2) and p1 or p2
-- Now actually move the drill
self:SetPos(pos)
self:SetAngles(angle:Forward():Angle() + Angle(0, 180, 0)) -- Always face the opposite the normal!
-- Let's get the mass of the door
local mass = 0
if not IsValid(ent:GetPhysicsObject()) then
local dims = ent:OBBMaxs() - ent:OBBMins()
mass = dims.x * dims.y * dims.z
else
mass = ent:GetPhysicsObject():GetMass()
end
-- Hacky way to calculate drill time based on mass! (Maybe I could do it based on thickness instead?)
self:SetTime(math.ceil(-1 / 1237500000 * math.pow(mass, 2) + 199 / 495000 * mass - 305 / 99))
-- We're done!
self.Attached = true
end
The only issue I have now is finding a robust solution to positioning the drill in ALL doors. It works perfectly now with regular doors, but giant doors like garage doors and custom doors (like bank vaults), the drill can end up inside the door too far. So I'll have to play around with that.
Update the debugging post for my full debugging function for anyone interested. You can see that ENT:Touch() uses much of the same code but is slight different due to it being on the server instead of the client.
It was quite an interesting exercise on using rendering to help debug positions, he is what it looks like with debug mode on (I'm pretty proud of figuring this out as I've never done stuff like this before):
https://www.youtube.com/watch?v=FF8VpmwiPLk
Still trying to fix positioning issues on certain doors though.
You can consider that not every door where correctly setup in hammer and that might cause problems with positioning, the best i would think of is to create a tool to fix a door manually (Human proof fix)
Sorry, you need to Log In to post a reply to this thread.