Game Development Community

PickLine to detect tiles as well as objects

by Andy Hawkins · in Torque Game Builder · 12/04/2008 (6:27 am) · 7 replies

I get the feeling that tiles aren't being detected when I use pickLine. How can I ensure my tiles are included so I can determine if a tile is inbetween one object and it's target?

This code is meant to see if the npc can see a bread crumb left by the player. If there is tile which collisions on in between it should have the tile first (or last) in the list of object the ray collided with I suspect - but it doesn't.

I've tagged my breadCrumbs with %this.SetGraphGroup(3)

function lookForClosestVisibleBreadCrumb(%who)
{
   %x1 = %who.getPositionX();
   %y1 = %who.getPositionY();
   %pos1 = %x1 SPC %y1;
   %list_of_visible_breadCrumbs = "";
   %graph = sceneWindow2D.getSceneGraph();
   %count = %graph.getSceneObjectCount();
   
   for (%i=0; %i<%count; %i++)
   {
      %obj = %graph.getSceneObject(%i);
      if (%obj.class $= "breadCrumb")
      {
         %x2 = %obj.getPositionX();
         %y2 = %obj.getPositionY();
         %pos2 = %x2 SPC %y2;
         // ray cast from npc to this breadCrumb
         // look at only walls (group1) and crumbs (group3) - exclude background
         %list_of_objects = %graph.pickLine( %pos1, %pos2, bit(1)|bit(3),bit(0), true, $player );
         //echo (%list_of_objects);
         
         // if first object is not a breadcrumb the something is in the way
         %object = GetWord( %list_of_objects, 0 );
         
         if (%object.class $= "breadCrumb")
         {
            if (GetWordCount(%list_of_visible_breadCrumbs) != 0)
            {
               %list_of_visible_breadCrumbs = %list_of_visible_breadCrumbs @ " ";
            }
            %list_of_visible_breadCrumbs = %list_of_visible_breadCrumbs @ %object;
         }
         
         //%c = GetWordCount( %list_of_objects );
         //for ( %i = 0; %i < %c; %i++ )
         //{
             //%object = GetWord( %list_of_objects, %i );
             //%string = "Object class:" SPC %object.class;
             //echo(%string);
         //}
      }
   }
   echo("Visible breadcrumbs:" @ %list_of_visible_breadCrumbs);
}

#1
12/05/2008 (4:41 pm)
Hmmm, maybe my question was too confusing. I just wanted to know how I can use pickLine to detect tiles as well as other objects please?
#2
12/06/2008 (8:02 am)
Andy,

The internal collision detection system offers-up rich information even for objects such as tile-layers which are composed of non-visible objects e.g. the tiles.

The thing to remember about a tile-layer is that a collision returned is the tile-layer object id and not an id of a tile because tiles don't have them. Making each tile a sim-object would be far too expensive. To get around this, when a parent object has decided that something collides with it (or one of its children), it has the chance to append some meta-data which it can use to provide more information on the collision.

For instance, this information is provided when you use the "OnCollision" callback.

Because picking is just an extension of the collision detection system, this information is available. Unfortunately, because of the way TorqueScript works, the information passed back by the pick routines are a string. This means returning rich structures very difficult, especially when you want to pass back a collection of rich structures. It's possible but very messy and very confusing.

In the end, when writing TGB I decided that the pick routines should simple return a list of object id's and not all the detailed information that's available such as the meta-data I mentioned above as well as the collision point (for line) etc.

In the code, this information is available right up to the point where the string is formed ready to be returned to the scripts. If you had the source, it'd be a 10 minute job to add this information to the pick call or just create a new pick-call to expose it.

Again though, the limitation here is that TS doesn't really provide decent parameter passing support.

Melv.
#3
12/06/2008 (8:13 am)
If you have a specific world point, you can perform a "%myTileLayer.pickTile(...)" method. This returns the logical tile coordinate from a world position.

I guess it wouldn't be that hard to perform a direct "pickLine(...)" method that returns a list of tile coordinates being as all the collision code is there already.

Melv.
#4
12/06/2008 (8:17 am)
Also, with the source, it's possible to add extra elements available when using "castCollision(...)" and "castCollisionList(...)". That'd be a simple job. In the case of using these, you'd need to cast a dummy object which was very small over a distance.

Melv.
#5
12/06/2008 (2:51 pm)
As mentioned in this thread...
www.garagegames.com/mg/forums/result.thread.php?qt=81396
... I will use my rayCastForTiles() method first to determine if any tiles were collidable from my specific tileLayer.

If there was a collision then I will perform the pickLine as above and iterate through the returned list to find out if the tileLayer was detected before the object I was ray casting for.

As per the docs
Quote:
pickLine... The order list is sorted by collision-time (unlike layer order from front->backwards that the other pick functions use).

However this might be overkill if the pickLine (when it returns the id to a tileLayer) only collides with a tileLayer if it actually hit a tile with a collision polygon on already??? Not sure about that one - would kinda make sense.

After all that I will attempt to put all this into source (to speed it up) and release a patch if it's of any use to people.
#6
12/07/2008 (8:06 am)
Andy,

I actually replied to the thread referenced not that long ago. Yes, tile-layers only collide when one of their collidable tiles collide with an object. The tile-layer itself doesn't have any collision detection.

This is a generalised low-level feature of the engine where an object container (tile-layer) reports the collision on its child objects (tiles).

The source for a non-stepped collision but using sweeping is already in the tile-layer source. The problem is that there's not a console-method to expose that. The existing code is used to return this information to the collision system which reports it during the "OnCollision(...)" callback. As I've mention though, the pick routines only report the parent object IDs (not the other rich info) because of the poor support for parameter passing in TorqueScript.

Melv.
#7
12/07/2008 (2:51 pm)
Thanks Melv. I've taken this on board and realised for what I want I don't need to implement my rayCastForTiles() method above as I just want to know if "some" wall was hit before the object I was casting for. I'll have a look at the source too, because I thinking it would be beneficial to know exactly which tile was hit from a ray cast to allow for blowing up walls etc.

I think that's what you are saying right? Have a look at the source and see how the "sweeping" is done. Then expose the results of the that to the console so it can be used in TorqueScript?