• Determine Entity Position/Angle Relative to Door
    6 replies, posted
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.