Players and Doors (And Collision)
by Glenn Bermingham · in Torque 3D Professional · 08/27/2014 (7:40 pm) · 25 replies
Been a while since I've been active here, just wanted to get other peoples ideas and opinions on going about players and doors (Collision specifically).
So one of the fundamental flaws you find working with the base(Full) First Person T3D, is when you want to implement a simple swinging door and then have the collision not affect the players position and most likely permanently lodge the player inside. To clarify, this is talking about solutions that don't require major engine changes.
Simple fix would be not to have swinging doors... While Sci-fi and shopping mall games could get away with this, its not really an acceptable answer.
Taking a look from another games point of view is Half Life 2(Source Engine), the Source engines doors system is actually quite cleaver but you probably wouldn't notice it. On a surface level the doors do not have and collision problems as the door and physics engine work in conjunction with the player and the door simply pushes the player away. However the next time you play Half Life 2, take note that every time you open a door, the door will always open away from you and never towards you. This is intentional to stop any unwanted issues like being stuck in the door or pushed away annoyingly.
So the initial problem with a T3D door system is that it'll likely have an open and close function(s) which consist of an Open and Closed state. These states would be done through animation and same with the collision. The Door then only swings open in one direction, so unless you're really nit picky with your level flow and tunnel your players direction, you're going to have some backwards doors. Which they'll open and likely get stuck in it. So what can we do about that...
So my first attempt at fixing the problem was to create a literal PhysicalZone's that would spawn and destroy itself inside of the door location to push the player in the doors swinging direction. Here's my code for it if people are interested: (This was in my door "open" function)
The problem with it is that if a player immediately started to walk into the doorway as the door was swinging away from the player, they'd get sucked through the doorway. While I did add an offset to the position the zone spawned in to be center of the door swing area; the problem is still there just not quite as obvious. Also note I had a function for closing of the door too which had the same effect only sucked plays into a closed door briefly. So while I think this was a good step in the right direction, it still felt cheap and a hack than a real fix.
Another option I consider was teleporting the player away from the door, but I quickly dismissed the idea as it'd be jolting and feel extremely cheap.
Now I'm thinking for a swinging door to work, its going to need several mechanics working in conjunction with each other. My simple physical Zone, while it does the job, its extremely... time consuming to get right for each door, there is not automatic direction of which way the physical zone actually pushes and the zone cannot be setup for one direction and simply rotated. In an ideal situation you'd want to simply be able to spawn the door object and have all of its fields automatically filled in whenever the door is used. That would take some good amount of maths to convert the rotation to the forces (1000 -1000 0 etc).
Despite that, the next viable step for me is to enhance my doors with double directions, have an open and close state for both swinging directions and have the door always open away from the player.
If you've got an idea of a way to go about this or any suggestions go into as much detail as you want.
It might seem like an excessive amount of time on a (What seems to be) a simple system, but we're in an age where people will quickly discredit a game because of things that seem "simple" but in reality take quite a complex bit of thinking to make it function in a way people expect.
So one of the fundamental flaws you find working with the base(Full) First Person T3D, is when you want to implement a simple swinging door and then have the collision not affect the players position and most likely permanently lodge the player inside. To clarify, this is talking about solutions that don't require major engine changes.
Simple fix would be not to have swinging doors... While Sci-fi and shopping mall games could get away with this, its not really an acceptable answer.
Taking a look from another games point of view is Half Life 2(Source Engine), the Source engines doors system is actually quite cleaver but you probably wouldn't notice it. On a surface level the doors do not have and collision problems as the door and physics engine work in conjunction with the player and the door simply pushes the player away. However the next time you play Half Life 2, take note that every time you open a door, the door will always open away from you and never towards you. This is intentional to stop any unwanted issues like being stuck in the door or pushed away annoyingly.
So the initial problem with a T3D door system is that it'll likely have an open and close function(s) which consist of an Open and Closed state. These states would be done through animation and same with the collision. The Door then only swings open in one direction, so unless you're really nit picky with your level flow and tunnel your players direction, you're going to have some backwards doors. Which they'll open and likely get stuck in it. So what can we do about that...
So my first attempt at fixing the problem was to create a literal PhysicalZone's that would spawn and destroy itself inside of the door location to push the player in the doors swinging direction. Here's my code for it if people are interested: (This was in my door "open" function)
if (%this.getFieldValue(pushEnabled))
{
%pos = VectorAdd(%this.getPosition(), %this.getFieldValue(pushOffset));
%openpush = %this.getFieldValue(pushOpen);
%scalepush = %this.getFieldValue(pushScale);
//echo(%pos);
%pushZone = new PhysicalZone(Door_pushZone)
{
position = %pos;
scale = %scalepush;
velocityMod = "1";
gravityMod = "1";
appliedpush = %openpush;
polyhedron = "-0.5 0.5 0.0 1.0 0.0 0.0 0.0 0.0 1.0 0.0 -1.0 0.0";
};
%this.pushZone = %pushZone;
}Then had this code in a OnAnimationEnd function// Delete push Zones
if(isObject(%this.pushZone))
%this.pushZone.delete();The problem with it is that if a player immediately started to walk into the doorway as the door was swinging away from the player, they'd get sucked through the doorway. While I did add an offset to the position the zone spawned in to be center of the door swing area; the problem is still there just not quite as obvious. Also note I had a function for closing of the door too which had the same effect only sucked plays into a closed door briefly. So while I think this was a good step in the right direction, it still felt cheap and a hack than a real fix.
Another option I consider was teleporting the player away from the door, but I quickly dismissed the idea as it'd be jolting and feel extremely cheap.
Now I'm thinking for a swinging door to work, its going to need several mechanics working in conjunction with each other. My simple physical Zone, while it does the job, its extremely... time consuming to get right for each door, there is not automatic direction of which way the physical zone actually pushes and the zone cannot be setup for one direction and simply rotated. In an ideal situation you'd want to simply be able to spawn the door object and have all of its fields automatically filled in whenever the door is used. That would take some good amount of maths to convert the rotation to the forces (1000 -1000 0 etc).
Despite that, the next viable step for me is to enhance my doors with double directions, have an open and close state for both swinging directions and have the door always open away from the player.
If you've got an idea of a way to go about this or any suggestions go into as much detail as you want.
It might seem like an excessive amount of time on a (What seems to be) a simple system, but we're in an age where people will quickly discredit a game because of things that seem "simple" but in reality take quite a complex bit of thinking to make it function in a way people expect.
About the author
I spend most of my time working on games.
#22
09/11/2014 (8:17 am)
Oh, hell yeah - great idea Jesse - that eliminates the collision issues entirely. My idea just opened the door, but if the trigger were too small you might still have encountered the collision weirdness. Good catch.
#23
09/11/2014 (4:18 pm)
Az - is that really true? Player collision uses an extruded poly list along the Player's velocity. Though I guess the early out check does somewhat scupper any correctness that might achieve if your player is moving fast enough. Seems like an odd optimisation for an engine like Torque which was full of players moving very quickly most of the time.
#24
I would choose for a collision that is thick enough and has enough overlap with the wall it's placed in. A thicker collision also prevents the player from sneak peeking behind the door.
Also would a key bind be helpful to avoid issues of script not being fast enough etc. "Tap [E] to open the door" etc.
09/11/2014 (6:47 pm)
I would preferably not use any triggers for this. Especially when there are issues with those, you really can't fully rely on them if the door is playing a significant role in the gameplay.I would choose for a collision that is thick enough and has enough overlap with the wall it's placed in. A thicker collision also prevents the player from sneak peeking behind the door.
Also would a key bind be helpful to avoid issues of script not being fast enough etc. "Tap [E] to open the door" etc.
Torque Owner Jesse Allen
door.cs
function DoorTrigger::onEnterTrigger(%this, %trigger, %obj) { echo ( "Entered pBDoorTrigger" ); %trigger.doorRef.playThread( 1, "Door_open" ); %trigger.doorRef.setMeshHidden( "collision-1", 1 ); } function DoorTrigger::onLeaveTrigger (%this, %trigger, %obj ) { echo ( "Left pBDoorTrigger" ); %trigger.doorRef.playThread( 1, "Door_close" ); %trigger.doorRef.setMeshHidden( "collision-1", 0 ); }Where the trigger just sets the collision mesh's state on or off? Probably some obvious problem I'm missing with this, but it was a trick I used once.