Game Development Community

How to manually setup trigger

by Ryan Jones · in Torque Game Builder · 01/23/2009 (11:28 am) · 16 replies

I appreciate all the help I've been given to the people on this forum. Thank you so much!

I have an object which is a graphic of a bullet and I have a behavior which is called AreaDamageBehavior to deal damage to the player. The behavior has a section of code to deal damage based upon onCollision or onEnter. My firing method is the ShootsBehavior which uses clonewithBehaviors().

The onCollision method is easy, just apply the behavor to the bullet and turn on receive collisions.

The onEnter method if I put mount a trigger to the bullet and apply the behavior to the trigger then that works.

The problem is clonewithBehaviors() does not clone the trigger! So this will not work with the onEnter method. Although onCollison deals damage once the bullet contacts the player that's it, it's instant resolved and the bullet will either die or stay there. With onEnter method I can have the bullet touch the player, cause damage, then continue on it's path. This is what I would like to achieve.

Is there a way to clone a trigger to be mounted to an object? Once I have this figured out it will really open doors for me in game design.

#1
01/26/2009 (12:13 pm)
Edited my origional question.
#2
01/26/2009 (9:05 pm)
Hey Ryan. I create Triggers programatically by creating one in the TGB editor, then going into the level and copying it out of the level. Then I spawn instanced of my trigger all over the place. One reason I need this is to get around some collision issues I found because I want to collect something when my character gets it without actually bouncing off of it. I accomplish this by spawning a trigger over my item to collect whenever one is in the scene. Here is some example code that might help:

function star::onLevelLoaded(%this, %scenegraph)
{
   $starsGroup.add(%this);
   starsneeded.setValue($starsGroup.getCount());//add stars needed value
   $totalStars=$starsGroup.getCount();
   
   //create and attach starShine effect
   %FX = new t2dParticleEffect() { scenegraph = %scenegraph; };
   %FX.loadEffect("~/data/particles/starShine.eff");
   %FX.mount(%this);//mount Shine on star
   %FX.playEffect();
   
   //mount collision trigger to star so that it will be collected correctly
   //using the star objects existing collision caused the ball to bounce off of it.
     %starTrigger= new t2dTrigger() {
      scenegraph = sceneWindow2D.getScenegraph();
      LeaveCallback = "0";
      canSaveDynamicFields = "1";
      class = "starCollisionTrigger";
      Position = "-742.785 1788.232";
      size = "15 15";
      CollisionPhysicsSend = "0";
      CollisionPhysicsReceive = "0";
      CollisionDetectionMode = "CIRCLE";
      CollisionResponseMode = "KILL";
      ForceScale = "0";
      AutoMassInertia = "0";
      Mass = "0";
      Inertia = "0";
      Density = "0";
      Friction = "0";
      Restitution = "0";
         mountID = "60";
   };
   %starTrigger.mount(%this);//mount trigger on star
   
}

It took me a while to figure out that when adding something programatically you have to add it to the scene with the following line: "scenegraph = sceneWindow2D.getScenegraph();". That's been a poorly documented and often overlooked pain point for me.
#3
01/27/2009 (5:14 am)
Hey thanks! I'm going to check out what you did and post my results.
#4
01/30/2009 (9:23 am)
I basically dropped your code right into a behavior and it didn't work, drat!

function TestTrigger::onLevelLoaded(%this, %scenegraph)
{
   //mount collision trigger to star so that it will be collected correctly
   //using the star objects existing collision caused the ball to bounce off of it.
     %starTrigger= new t2dTrigger() {
      scenegraph = sceneWindow2D.getScenegraph();
      LeaveCallback = "0";
      canSaveDynamicFields = "1";
//      class = "starCollisionTrigger";
      Position = "-35 -25";
      size = "15 15";
      CollisionPhysicsSend = "0";
      CollisionPhysicsReceive = "0";
      CollisionDetectionMode = "CIRCLE";
      CollisionResponseMode = "CLAMP";
      ForceScale = "0";
      AutoMassInertia = "0";
      Mass = "0";
      Inertia = "0";
      Density = "0";
      Friction = "0";
      Restitution = "0";
         mountID = "60";
   };
   %starTrigger.mount(%this);//mount trigger on star
}

/// Adds damage to the actor when entering the trigger
function TestTrigger::onEnter(%this, %theirObject)
{
...code here
}

function TestTrigger::onLeave(%this, %theirObject)
{
...code here
}
I basically have my main character between two bullets. The bullet on the left is using this behavior i'm testing and the bullet on the right has a trigger manually mounted to it with the AreaDamage behavior attached to it. When I walk into the right bullet the character gets damanaged, but the left isn't yet.
#5
01/30/2009 (10:23 am)
Hahah, yeah I didn't expect it to work right away. Did you create an object in the TGB editor, or programmatically with the "class" name of TestTrigger? And if so was the TestTrigger object added to the scenegraph?

#6
01/30/2009 (1:15 pm)
Well, I just added it right away and crossed my fingers for the best of luck. :)

Well, the graphic is placed with the editor in the scene, but the code is placed in a behavior called TestTrigger which has been applied to the bullet. I did not give it a class, but it does a name which is just Bullet1.

I also tried this example below which did not work either (thanks for looking by the way).
function TestTrigger::onLevelLoaded(%this, %scenegraph)
{
   // Spawn a trigger around the platform.
   %trigger = new t2dTrigger() { scenegraph = %scenegraph; class = FireTrigger; };

   // Disable sending of collisions, so platforms don't collide with the trigger.
   %trigger.setCollisionActiveSend(false);

   // Set the position and size to match the platform's position and size.
   // The trigger is offset below the platform to insure that the trigger is entered.
   %trigger.setPositionX(%this.Owner.getPositionX());
   %trigger.setPositionY(%this.Owner.getPositionY());
   %trigger.setWidth(%this.Owner.getWidth()+2);
   %trigger.setHeight(%this.Owner.getHeight()+2);

   // Place in a different graph group than the platforms so player to platform collisions can
   // be disabled while leaving player to trigger collisions enabled.
   %trigger.setGraphGroup(1);
}

/// Adds damage to the actor when entering the trigger
function FireTrigger::onEnter(%this, %theirObject)
{...something....}

function FireTrigger::onLeave(%this, %theirObject)
{...something...}
#8
01/30/2009 (1:47 pm)

Try the original example I gave you.

Go in the editor and make an image, then go to the loadout where it says "class" if you dont' have this it won't work. Name doesn't cut it. What the "onlevelloaded" callback does.. is calls that function the first time that it sees the object loaded onto the scenegraph; So it will only happen once per object. Then the trigger code will do all the other work. Also.. your onEnter, and onExit are incorrectly named. Since it's the trigger, that's calling the shoot methods, and not the class you set up to create it, you need to use that object, not the object that it's mounting to.

They have to be

function starCollisionTrigger::onEnter(%obj, %therObj)
{}
function starCollisionTrigger::onLeave(%obj, %therObj)
{}

notice that when I create the trigger programmatically, I give it a class? You have to use that class name to set up it's callbacks.
#9
02/02/2009 (11:39 am)
Okay, here's what I got now. When my character walks over the bullet damage is still not triggered yet.

The object's name is: Bullet1
The object's calss is: starCollisionTrigger

function star::onLevelLoaded(%this, %scenegraph)
{   
   //mount collision trigger to star so that it will be collected correctly
   //using the star objects existing collision caused the ball to bounce off of it.
     %starTrigger= new t2dTrigger() {
      scenegraph = sceneWindow2D.getScenegraph();
      LeaveCallback = "0";
      canSaveDynamicFields = "1";
      class = "starCollisionTrigger";
      Position = "-17.811 -37.007";
      size = "15 15";
      CollisionPhysicsSend = "0";
      CollisionPhysicsReceive = "0";
      CollisionDetectionMode = "CIRCLE";
      CollisionResponseMode = "KILL";
      ForceScale = "0";
      AutoMassInertia = "0";
      Mass = "0";
      Inertia = "0";
      Density = "0";
      Friction = "0";
      Restitution = "0";
         mountID = "60";
   };
   %starTrigger.mount(%this);//mount trigger on star  
}

function starCollisionTrigger::onEnter(%obj, %%theirObject) 
{} 
function starCollisionTrigger::onLeave(%obj, %%theirObject) 
{}
#10
02/02/2009 (11:45 am)
Can I assume that you have code in the onEnter and onLeave callbacks at the bottom of the code? You need to call your damage method inside those methods for it to do anything.
Your turrets have to have the class name "star" (I think you said your turret has the classname of starCollisionTrigger which will not work). Otherwise it will not call the star::onLevelLoaded(%this, %scenegraph)
method, and your triggers will not be created and mounted to your turret!
#11
02/02/2009 (1:05 pm)
I changed the functions name
function starCollisionTrigger::onLevelLoaded(%this, %scenegraph)
so now the're all the same but still does not work.

My AreaDamageBehavior was taken from the platformer starter kit, so maybe the problem here just lies in how the onEnter and onLeave is being called?
#12
02/02/2009 (1:24 pm)
I know what your problem is. I addressed them in my last post. I apologize if I was not clear.

1) You need to call a method that causes damage inside your "onEnter" function. If you have a behavior that you are using for that.. then call the method that your behaviour uses to cause damage. You will probably need to send the "%theirObject" object to the function. Also there is a typo.. there shouldn't be two %'s in theirObject definition. I wouldn't use a behavior though.. just create your own method that takes an object and reduces it's life by x. Then kills the object once its life reches zero.

2)You have to make sure that any turret you put in the game has the class "star". Otherwise the method " star::onLevelLoaded" will not be used since that callback will only be called when an object with classname: star is loaded into the scene. If you want to email me a working version of your project I can fix it for you.

-nic
#13
02/03/2009 (5:39 am)
Sure, what's your e-mail? I just can't get this thing to work, grr.

Also, looking at your code again is this step correct?
%starTrigger= new t2dTrigger() {
#14
02/03/2009 (7:14 pm)
my personal email is
nicbiondi@gmail.com


and yeah that's correct. It's creating a trigger dynamically and sticking the handle in the %starTrigger variable which it later uses to mount it to the parent.
#15
02/04/2009 (8:47 am)
Okay, I gotcha. It's been e-mailed, hopefully you can figure out what I've been doing wrong.
#16
02/11/2009 (9:43 am)
Thanks Nic for helping me figure it out. As usual I will post up my answer incase somebody else has this same problem. What Nic did was approach it from a different perspective then what I was trying.

First, the trigger has to be added within datablocks.cs, I have mines at the bottom.
function createLazerTrigger()
{
     %lazerTrigger=new t2dTrigger() {
      scenegraph = sceneWindow2D.getScenegraph();  
      StayCallback = "0";
      canSaveDynamicFields = "1";
      Position = "50.682 -27.885";
      size = "38.637 5.770";
      CollisionActiveSend = "1";
      CollisionActiveReceive = "1";
      CollisionPhysicsSend = "0";
      CollisionPhysicsReceive = "0";
      CollisionCallback = "1";
      _Behavior0 = "AreaDamageBehavior	PlayerOnly	1	Amount	10";
};
   return %lazerTrigger;
}

Now where I put in my code for the shooting using the shoots behavior I have this:

if (!isObject(%this.projectile))
      return;

	%lazerTrigger=createLazerTrigger();
	%lazerTrigger.setPositionX(%this.owner.getpositionX() + 7);
	%lazerTrigger.setPositionY(%this.owner.getpositionY());
	%lazerTrigger.setWidth(3);
	%lazerTrigger.setHeight(3);
	%lazerTrigger.setLinearVelocityPolar(90, 100);

   %projectile = "securitybitshot";
   %projectile.setPositionX(%this.owner.getpositionX() + 7);
   %projectile.setPositionY(%this.owner.getpositionY());
   %projectile.setLinearVelocityPolar(90, 100);

So what's happening is the the bullet's object name is "securitybitshot" and the %projectile section will get the image of the bullet to fire (with an x offset of + 7) across the screen.

%lazertrigger has a width of 3x3 and it fires at the same time and same offset. so what's happening is the graphic and the trigger are both firing at the same time across the screen. The trigger calls the areadamage behavior so the player is damaged as the bullet crosses path.

Thanks again Nic!