Game Development Community

onEnterTrigger affecting a function

by Infinitum3D · in Torque Game Engine · 04/09/2009 (7:03 am) · 17 replies

I have a door that opens and closes by keyBind. The problem is, there is no collision "in transition" so the door swings right through the Player. I'm setting a trigger area behind the door, so that IF(Player in trigger) THEN(Door is blocked, Do Not Play animation) ELSE(Play animation)

Here's my script:


// -----------------------------------------------------------------------------
// Datablocks - shapes
// -----------------------------------------------------------------------------

datablock StaticShapeData(woodDoor){
category = "doors";
className = door;
shapeFile = "~/data/shapes/doors/door_rotate.dts";
position = "0 0 0";
Scale="1 1 1";
emap = true;
receiveSunLight = "1";
};

datablock TriggerData(DoorTrigger)
{
tickPeriodMS = 500;
PlayerInZone = 0; //--declaration default no Player in zone
};

//-----------------------------------------------------------------------------
// This is the trigger for a door blocked by a Player
//-----------------------------------------------------------------------------

function DoorTrigger::onEnterTrigger(%this,%trigger,%obj)
{

if (%obj.client) //--player entered zone
{
echo( "PLAYER ENTERED ZONE");
%trigger.PlayerInZone = %trigger.PlayerInZone++;
echo("There are " @ %trigger.PlayerInZone @ "players in Zone");
}
}

function DoorTrigger::onLeaveTrigger(%this,%trigger,%obj)
{
if (%obj.client) // player left zone
{
%trigger.PlayerInZone = %trigger.PlayerInZone--; //reduce PlayerInZone
if ( %trigger.PlayerInZone <= 0) // dont ever go below zero
{
%trigger.PlayerInZone = 0;
}
echo("There are " @ %trigger.PlayerInZone @ "players in Zone");
echo("PLAYER LEFT THE ZONE");
}
}

// ----------------------------------------------------------------------------------
// Functions - door open events
// ----------------------------------------------------------------------------------

// This function is called whenever the client presses the 'use interaction' key ("u" key)
// within the set distance.
// calls from interaction.cs change distance there.

function door::interact(%this, %obj, %client)
{
if (%this.doorBlocked???); //--something blocks the door, WHAT GOES HERE?
{
messageClient(%client, '', 'Something is blocking the door!');
}
else
{
%this.MoveDoor(%obj);
}
}

function door::MoveDoor(%this, %door)
{
if (!%door.open)
{
%door.open = true;
%door.setthreaddir(0,"true");
%door.playthread(0,"open");
}
else
{
%door.setthreaddir(0,"false");
%door.open = false;
}
}
function door::doorBlocked(%client)
{
messageClient(%client, '', 'Something is blocking the door!');
}


function DoorTrigger::onTickTrigger(%this,%trigger)
{
//--If Player is in the trigger area.
if (%trigger.PlayerInZone >=1)
{
echo("DOOR IS BLOCKED");
%this.doorBlocked(); //--something blocks the door
}
}


I don't know how to do the If Door Is Blocked part. I tried
%trigger.PlayerInZone >= 1
%this.PlayerInZone >=1
%obj.PlayerInZone >=1

Obviously, I'm an idiot :) Everything works EXCEPT the door blocking part. (and the messageClient doesn't work either, but I'll fix that later.)

What is the correct syntax for this part of the function?

Thanks!

Tony

#1
04/09/2009 (7:27 am)
How about:

%this.doorBlocked(%obj);

as in

function door::interact(%this, %obj, %client)
{
if (%this.doorBlocked(%obj)); //--something blocks the door, WHAT GOES HERE?
{
messageClient(%client, '', 'Something is blocking the door!');
}
else
{
%this.MoveDoor(%obj);
}
}



Or Maybe:

function door::interact(%this, %obj, %client)
{
if
{
%this.doorBlocked(%obj); //--something blocks the door, WHAT GOES HERE?
messageClient(%client, '', 'Something is blocking the door!');
}
else
{
%this.MoveDoor(%obj);
}
}

#2
04/09/2009 (7:46 am)
OK, This at least compiles:

function door::interact(%this, %obj, %client)
{
if (%PlayerInZone >= 1)//--something blocks the door
{
%this.doorBlocked(%obj);
//messageClient(%client, '', 'Something is blocking the door!');
}
else
{
%this.MoveDoor(%obj);
}
}






But when Player is in the trigger, my onTickTrigger generates this console error every tick (500MS):

FUNCTION DOOR TRIGGER
starter.fps/server/scripts/door.cs (98): Unknown command doorBlocked.
Object DoorTrigger(99) DoorTrigger -> TriggerData -> GameBaseData -> SimDataBlock -> SimObject

The first part is my echo("FUNCTION DOOR TRIGGER");
The second part tells me that command doorBlocked is an invalid function...

Gotta go back and rewrite it.

Tony
#3
04/09/2009 (9:11 am)
Whoops - need to read more carefully :P. Using code tags wouldn't hurt ;)

Is 'door' your datablock? In that case, your 'door::doorBlocked()' function eneds to include more than 1 argument. If it's a method on a datablock, then you need to include at least a %this to catch the datablock. It's also useful to put a %obj in, so you know which object you're calling the method on, not just which datablock. So you'd be looking at:
function Door::doorBlocked(%this,%obj,%client)
{
   ...
}

%doorDataBlock.doorBlocked(%trigger,%client);
#4
04/09/2009 (3:44 pm)
@Daniel,

"more than one argument" meaning an If...Else... statement? Sorry, I'm not a programmer so I apologize for lack of terminology knowledge.

Oh, wait, arguments...you mean %this, %obj... I get it.

I like your example script there.

I can work with that.

Thanks!
Tony
#5
04/10/2009 (12:24 am)
Note that when you call the method like I showed above, you only put 2 parameters in (%trigger and %client), even though there are 3 in the function declaration. When you call the method on %doorDataBlock, this value is passed in as the first parameter. So inside the function, you use %this to refer to %doorDataBlock, %obj to refer to %trigger, and %client for %client.
#6
04/10/2009 (4:49 am)
Thanks alot! I really have a hard time understanding which argument goes with which reference. I need to start naming them better. %this and %obj just confuse me. I just need more experience I guess. I'm reading a few different Beginner C++ books, and that helps some.

%this refers to the datablock, right? and %obj refers to object, which is the actual object in the game world, right? I understand %client is the Player, and %trigger is obviously the trigger...

I'll let you know when I've got it working.

Thanks again! You've been a big help.

Tony

ps, sorry about leaving out the code tags, but I was using my cellphone at the time. Lousy way to post, but the only 'net connection I had at the time.
#7
04/10/2009 (5:09 am)
Yes, %this is usually the datablock (at least, that's the way stock scripts are written). And %obj is the object. In your case, %client shouldn't be the actual Player object, but the client who owns the player. Good luck, and happy to be able to help :)
#8
04/10/2009 (7:09 am)
Ok, I still need help. (I must be driving you crazy!)

How do I retrieve the value/information in PlayerInZone for my function door::interact?

CAN I retreive it, if PlayerInZone is declared in the trigger datablock? Is there any way to "get" it into a door function?

Here's my theory - there is a player in the trigger zone, so my %trigger.PlayerInZone = 1. But I can't just do this

function door::interact(%this, %obj)
{
if (%trigger.PlayerInZone >= 1)

because %trigger isn't a door argument. Even if I try this

function door::interact(%this, %obj, %trigger)

it still doesn't work. So how do I use %trigger.PlayerInZone in my door function? Is there a "get" precursor, as in %get.trigger.PlayerInZone

I tried it, but it gets ignored. I'm sure there's a way to pull a value from one datablock and use it in another object's function... But how? I really need to learn proper syntax.

Its gotta be something simple. I'm just using the wrong word/name.

Thanks!
Tony
#9
04/10/2009 (7:28 am)
Ok, made progress.

if(%DoorTrigger.PlayerInZone(%obj)>=1)

That at least gets recognized, but then I get: Unable to find object:'' attempting to call function 'PlayerInZone'

Making progress! Not really. Its kinda like shouting out random noises and hoping someone that speaks another language will recognize it.

Tony
#10
04/10/2009 (9:41 am)
OK, This code gets the Transform, not the Value...

function door::interact(%this, %obj)
{
	%PlayerInZone = %DoorTrigger.getPlayerInZone();//THIS LINE IS WRONG
	echo("INTERACT - PLAYER IN ZONE = " @ %PlayerInZone);
	 if (%PlayerInZone >= 1)//--something blocks the door
	{
	echo("INTERACT" @ %PlayerInZone @ " PLAYER BLOCKING");                 	%this.doorBlocked(%obj);
	}
	else
	{
	%this.MoveDoor(%obj);
	}
}



Here's the console log:


starter.fps/server/scripts/door.cs (60): Unable to find object: '' attempting to call function 'getPlayerInZone'
INTERACT - PLAYER IN ZONE = 1763 199.028 -619.429 109.765 0 -1 0
INTERACT1763 199.028 -619.429 109.765 0 -1 0 PLAYER BLOCKING
FUNCTION DOOR IS BLOCKED


So the problem lies in this line:
%PlayerInZone = %DoorTrigger.getPlayerInZone();

How do I get the value of PlayerInZone from the DoorTrigger datablock into the door::Interact Function?

...

Tony
#11
04/10/2009 (11:06 am)
I'm not exactly a pro, actually I'm a newbie, but.. my initial reaction is that I'd go about it a different way.

(I'm just thinking loudly here, bash me to bits if you want!)

How about making it so that instead of trying to read that value directly.. making a trigger on that door that sets another value to true/false depending on if the player is blocking it, and in the if function reading that value instead?

Shouldn't that be easy to implement the way you had it earlier when you had problems with the collision?

</dumbassramblings>
#12
04/10/2009 (12:50 pm)
Okay, take a look at that function you have above. It's declared as a 'door' datablock method, and has parameters %this and %obj. These parameters refer to the door datablock and the door object respectively. Nowhere is there a reference to a trigger object, which is where you're storing the number of players in the trigger.

Going back to the first post #8, your first code block is on the right track. However, you don't declare the variable %trigger anywhere - you can't expect the engine to know what you mean by %trigger if you haven't told it!

What I would do is store a reference to the trigger object insde the door object. So you create an object with datablock 'door'. You create a trigger with datablock 'DoorTrigger'. Then set %doorObjectID.trigger = %triggerObjectID; Now your door is 'aware' of the trigger that belongs to it, so to speak. So you could do a function like this:
function door::interact(%this,%obj)
{
   if(%obj.trigger.PlayerInZone > 1)
   {
      ...

Another word on the scripts in your latest posts. You've tried %trigger.PlayerInZone(%obj) and %trigger.getPlayerInZone(). Neither of these, as far as I can tell from the script you've showed us, are actual functions. PlayerInZone is a numerical member - you can't call it like a function, that doesn't mean anything. You could write a getPlayerInZone() method for your trigger datablock/object, but you may as well just reach in and grab the value of PlayerInZone directly.

Marcus - if I'm reading you right, your idea's similar to what Tony wants to do. In your case, you might give the trigger a reference to a door object. When a player enters the trigger, you set a parameter on the door to true. When someone wants to open the door, the door checks that parameter, and if it's true, it won't open.
This way is the opposite: the trigger stores a value itself, and the door checks with the trigger's value.
#13
04/10/2009 (2:57 pm)
@Marcus, I thought about that also, but since I started this way, I was trying to keep going till I got it right.

@Daniel, I understand the logic/concepts, I just can't put it into play. I tried adding %this to function door::interact, but function door interact still doesn't acknowledge the DoorTrigger datablock because I'm in a 'door' function, not a 'doorTrigger' function.

function door::interact(%this, %obj, %trigger)//doesn't help


1.
Quote:
What I would do is store a reference to the trigger object insde the door object.

I don't understand "inside the door object". I thought the door 'object' was the door in the game...

2.
Quote:
So you create an object with datablock 'door'. You create a trigger with datablock 'DoorTrigger'.

OK, I have those, right?

3.
Quote:Then set %doorObjectID.trigger = %triggerObjectID;

Where do I set this? In my DoorTrigger::onEnterTrigger function, or in my function door::interact function?

I can't tell you how much this is helping me. Thank you! I really really really appreciate it! I do think I'm learning, just not as quickly as I'd like.

Tony

#14
04/11/2009 (2:02 am)
Quote:Where do I set this?
Well, that's the trick, because it needs to be at some point in the script where you actually have both object IDs available. You've written a script to create doors and triggers based on their datablocks, correct? I think you'd want to do something like create a trigger automatically when your door is created, then you have a place where you can give the door a reference to its trigger object.

You mentioned that adding %trigger to the definition of the door::interact function doesn't help. How are you calling the function when you want to interact with the door? If you've defined 3 parameters for the function, but don't put any values into those when you call the function, then it definitely won't work as expected.

Quote:I don't understand "inside the door object". I thought the door 'object' was the door in the game...
Well, metaphorically speaking ;P. I meant storing the ID of the trigger object as a property of the door object.
#15
04/11/2009 (12:40 pm)
Quote:I think you'd want to do something like create a trigger automatically when your door is created, then you have a place where you can give the door a reference to its trigger object.

Yeah, I don't know how to do that. I'll see what I can figure out, though. So there's no way to access multiple datablocks in a single function?

I'll keep at it.

Thanks for your help!

Tony
#16
04/11/2009 (1:36 pm)
The trick is adding members to an object so that they're stored someplace you can access them. So, if your function is called with a reference to a door object, it's helpful if that door 'knows' about the trigger it's linked to. But by default, yes, functions usually only reference one datablock.

You should have a function like door::create so that you can place doors with the editor. In that function, as well as doing the usual of creating the door object, you'd also create a trigger object and store the trigger's ID as a member of the door object.
#17
04/11/2009 (5:39 pm)
Quote:
You should have a function like door::create so that you can place doors with the editor.

I can create doors with the editor using my datablock

datablock StaticShapeData(woodDoor){
category = "doors";
className = door;
shapeFile = "~/data/shapes/doors/door_rotate.dts";
position = "0 0 0";
Scale="1 1 1";
emap = true;
receiveSunLight = "1";
};



But I now see where I need the ::create function to include the trigger.

Thanks!!!

Tony