| 1 |
DTS Support?
back |
With regards to your other question; it depends on what you mean by 3D interaction. If you're talking about rendering then no because the GUI controls are rendered discreetly by T3D. T2D can only be over/underlaid any other GUI controls, not intermix rendering, at least not stock. You can of course freely communicate any other information you want, even at the C++ level if you want. The majority of T2D is about the management and manipulation of the scenegraph, its objects and their state. It is possibly to develop a 3D object, using something like my fxRenderObject, that renders the fxSceneGraph2D. The core T2D object is a fxSceneObject2D and that contains all the goodies but the great thing is, it doesn't do any rendering so you can create new objects that do, and work in 3-space with the 2D layer being some Z in 3-space. Some of the stuff though just wouldn't fit or be appropriate and I'm not sure exactly the benefit of doing all this work.
It'd be much easier to develop 2D 3-space objects than try to convert T2D. - Melv. "The only way you'll get 3D objects in T2D is to integrate T2D with TGE or TSE. This is exceptionally simple (you copy the T2D directory into your TGE or TSE project and re-compile). The code to display a DTS shape inside a T2D world is very easy if you are working inside TGE / TSE. Since so many people are interested in doing this, we'll provide a resource that at least gets a DTS shape rendering in a T2D world (not sure if we'll do the whole bounding box collision thing yet) and explains how to do it in general. This won't come online for a while though, as there are many more important things to take care of for now. -Josh Williams |
| 2 |
"SetDebugOn();"?
back |
You can use "setDebugOn" on either the fxSceneGraph2D (in which case it applies to all objects in the scene) or to individual fxSceneObject2D objects (essentially everything).
As a sanity check, use option #0 which turns the debug-stats on. Try this on your scenegraph object, something like... t2dSceneGraph.setDebugOn( BIT(0) ); You see debug-stats at the top of your screen? - Melv. T2dSceneGraph.setDebugOn( 0xFFFFFF ); will show all the debug info... the debug info in T2D is beyond outstanding ! the advantage Melv implemented when making this an object member function is you can do this $player.setDebugOn( BIT(5) ); and now you see just the players bounding box ! |
| 3 |
Docs T2D only users?
back |
you see the official scripting documentation there, the same exact stuff (and all of it) that TGE owners get. That is over 40 pages of TorqueScript documentation in chapter 5 of the online doc alone! :) Yes, there is a big "preview" graphic watermark, but TGE owners see that too. It is there to represent that we are working on more docs. However, we might want to get rid of that watermark finally. Also there are more TorqueScript docs available here on the site. Check out the main TGE Tutorials page, which anyone can see. Check out Joel Baxterīs quick TorqueScript reference and Ron Yackettaīs TorqueScript command reference in particular. Note that the next release of T2D has an HTML page in the docs dir pointing you directly to these links, so that itīs more clear to everyone. As for particle editor docs, a quickie write-up is the next doc on that "to do" list. As Melv says, it may take a little while to get to it, but it is on its way. On the tile editor, you see the temporary doc we have in place already, and Melv has posted some more temporary info here |
| 4 |
I am following through the Tutorial and I am at the part where we start learning player movement. I did everything the tutorial said but the player will not move.
back |
The most common error for player not moving in tutorial is this function playerUp() { // Set the player moving up. $player.setLinearVelocityY( -$10 ); } the -$10 should be -10 Another common error (not just with movement) for those new to programming/scripting is the following when you create a "function" you do this function (put function name here)() { } the "{" signify the beginning of defining that function and the "}" defines the end of the definition... This tells the language what to use when you reference that function an important thing to remember is a function should never be in another function so function setupT2DScene() function playerUp() { // Set the player moving up.$player.setLinearVelocityY( -$10 ); } so this automatically will not work reason why is "function setupT2DScene()" get started... then you have put "function playerUp()" in it... you need to make sure you start setupT2DScene and end it first before you declare another function... so the format would rather be this function setupT2DScene() { } function playerUp() { } that way they are defined as seperate functions if you need any more help don't hesitate to ask |
| 5 |
How do I make Collision Polys?
back |
"Hi - I built a little visual plotter online at: http://www.ramspeed.com -It's rough but works OK until we have a built-in app. I'll upload an exe that will allow you to load local images soon. thanks" - Pete111 Comments on collision polys in T2D from Melv You canīt. Thatīs concave. Go through all your points and check its neighbour points. If the interior angle is more than 180-deg, itīs concave. Another way of thinking about it is to draw all the lines that define your polygon so that they extend out to infinity. If they intersect any of the other lines in the polygon, itīs concave. So many different ways to define this. This may sound brutal but is extremely common in engines as it allows certain assumptions/constraints to be made. Supporting concave polygons requires the engine to decompose them into discreet convex polygons which takes time and extra effort for very little reward in certain cases. Most 2D games get away with this because it actually doesnīt matter in most instances, particular for high-paced games. You definately donīt want your polygon to exactly match the contours of an object. Lots of people get hung-up on being precise when most of the time, games are quite the opposite. The shooter demo has really crude collision polygons, especially for the ship. The pool demo has collision detection for the pockets (which are concave) but the nieve implementation would try to have a polygon that completely defined the pocket. All you really need is something that the ball collides with in the pocket, in this case we did a box. Another way to deal with this is with your art. If youīve got a ship with a big gun sticking out and you also want this to be part of the collision-detection solution then simply draw it seperately, mount it as an object and give it a collision poly. The same would go for a large player with arms or legs. Hope I don't sound "preachy" here. :) - Melv. |
| 6 |
Working example of fxAnimatedSprite2D ??back |
datablock fxImageMapDatablock2D(circleGuy)
{
mode = cell;
cellWidth = 64;
cellHeight = 64;
textureName = "~/client/images/circleGuy";
};
datablock fxAnimationDatablock2D(circleGuyStandLeft)
{
imageMap = circleGuy;
animationFrames = "0";
animationTime = 1;
animationCycle = 0;
randomStart = 0;
};
datablock fxAnimationDatablock2D(circleGuyWalkLeft)
{
imageMap = circleGuy;
animationFrames = "1 2 3";
animationTime = 0.75;
animationCycle = 1;
randomStart = 0;
};
datablock fxAnimationDatablock2D(circleGuyStandRight)
{
imageMap = circleGuy;
animationFrames = "7";
animationTime = 1;
animationCycle = 0;
randomStart = 0;
};
datablock fxAnimationDatablock2D(circleGuyWalkRight)
{
imageMap = circleGuy;
animationFrames = "6 5 4";
animationTime = 0.75;
animationCycle = 1;
randomStart = 0;
};
datablock fxAnimationDatablock2D(circleGuyCastSpellLeft)
{
imageMap = circleGuy;
animationFrames = "8 9 10";
animationTime = 0.75;
animationCycle = 0;
randomStart = 0;
};
datablock fxAnimationDatablock2D(circleGuyCastSpellLeftEnd)
{
imageMap = circleGuy;
animationFrames = "10";
animationTime = 0.75;
animationCycle = 0;
randomStart = 0;
};
datablock fxAnimationDatablock2D(circleGuySpellCastedLeft)
{
imageMap = circleGuy;
animationFrames = "11";
animationTime = 0.75;
animationCycle = 0;
randomStart = 0;
};
datablock fxAnimationDatablock2D(circleGuyCastSpellRight)
{
imageMap = circleGuy;
animationFrames = "15 14 13";
animationTime = 0.75;
animationCycle = 0;
randomStart = 0;
};
datablock fxAnimationDatablock2D(circleGuyCastSpellRightEnd)
{
imageMap = circleGuy;
animationFrames = "13";
animationTime = 0.75;
animationCycle = 0;
randomStart = 0;
};
datablock fxAnimationDatablock2D(circleGuySpellCastedRight)
{
imageMap = circleGuy;
animationFrames = "12";
animationTime = 0.75;
animationCycle = 0;
randomStart = 0;
};
$circleGuy = new fxAnimatedSprite2D() { scenegraph = t2dSceneGraph; };
$circleGuy.setPosition("-35 0");
$circleGuy.setSize( "10 7" );
$circleGuy.playAnimation(circleGuyStandLeft)
heres the image I use
Here are the keys and corresponding functions I use with them
new ActionMap(playerMap);
// Bind keys to actions.
playerMap.bindCmd(keyboard, "w", "castSpellLeft();", "spellCastedLeft();");
playerMap.bindCmd(keyboard, "s", "castSpellRight();", "spellCastedRight();");
playerMap.bindCmd(keyboard, "a", "circleGuyLeft();", "circleGuyLeftStop();");
playerMap.bindCmd(keyboard, "d", "circleGuyRight();", "circleGuyRightStop();"
);
playerMap.bindCmd(keyboard, "space", "playerFire();", ");
playerMap.push();
function castSpellLeft()
{
$circleGuy.playAnimation(circleGuyCastSpellLeft, 0);
$animation = "circleGuyCastSpellLeft";
%fire = new fxParticleEffect2D() { scenegraph = t2dSceneGraph; };
%fire.loadEffect("~/client/effects/fire_fury.eff");
%fire.mount( $circleGuy, "0.8 -0.12", 0, false );
%fire.setRotation( 180 );
%fire.setScale( "0.1 0.1" );
%fire.playEffect();
}
function spellCastedLeft()
{
$circleGuy.playAnimation(circleGuySpellCastedLeft, 0);
%fireBall = new fxStaticSprite2D() { scenegraph = t2dSceneGraph; };
%fireBall.setPosition( $circleGuy.getPosition() );
%fireBall.setSize( "3 1.5" );
%fireBall.setImageMap( enemymissileImageMap );
%fireBall.setLinearVelocityX( -35 );
%fireBall.setWorldLimit( kill, "-60 -40 60 40" );
%fire = new fxParticleEffect2D() { scenegraph = t2dSceneGraph; };
%fire.loadEffect("~/client/effects/smallThruster.eff");
%fire.mount( %fireBall, "0.8 -0.12", 0, false );
%fire.setRotation( 180 );
%fire.playEffect();
}
function castSpellRight()
{
$circleGuy.playAnimation(circleGuyCastSpellRight, 0);
$animation = "circleGuyCastSpellRight";
}
function spellCastedRight()
{
$circleGuy.playAnimation(circleGuySpellCastedRight, 0);
%fireBall = new fxStaticSprite2D() { scenegraph = t2dSceneGraph; };
%fireBall.setPosition( $circleGuy.getPosition() );
%fireBall.setRotation( 180 );
%fireBall.setSize( "3 1.5" );
%fireBall.setImageMap( enemymissileImageMap );
%fireBall.setLinearVelocityX( 35 );
%fireBall.setWorldLimit( kill, "-60 -40 60 40" );
%fire = new fxParticleEffect2D() { scenegraph = t2dSceneGraph; };
%fire.loadEffect("~/client/effects/smallThruster.eff");
%fire.mount( %fireBall, "0.8 -0.12", 0, false );
%fire.setRotation( 0 );
%fire.playEffect();
}
function circleGuyLeft()
{
$circleGuy.playAnimation(circleGuyWalkLeft);
$circleGuy.setLinearVelocityX( -10 );
}
function circleGuyLeftStop()
{
if ( $circleGuy.getLinearVelocityX() < 0 )
{
$circleGuy.setLinearVelocityX( 0 );
$circleGuy.playAnimation(circleGuyStandLeft);
}
}
function circleGuyRight()
{
$circleGuy.playAnimation(circleGuyWalkRight);
$circleGuy.setLinearVelocityX( 10 );
}
function circleGuyRightStop()
{
if ( $circleGuy.getLinearVelocityX() > 0 )
{
$circleGuy.setLinearVelocityX( 0 );
$circleGuy.playAnimation(circleGuyStandRight);
}
}
|
| 7 |
Question about Global Variables?Do you have to use global variables to define players and objects in T2D?back |
As has been said above, globals, particularly when starting/prototyping, as just convienient. More production-quality games would want to ensure that objects are stored in containers and that when the game/mission finishes, these containers and their contents are destroyed. You can lookup SimSets/SimGroups in the TGE engine doco for an idea on how to maintain abstract lists of objects. The good thing about T2D is that when you add any of its objects to the scene (fxSceneGraph2D), they are automatically destroyed when the scene is destroyed and so the scene can be used as a container. WIth singular objects like a $player, it's much easier to simply use a global although when networking comes along, this practice won't scale very well. Also, I personally don't like wide-scale use of naming objects e.g. "new fxCoolObject2D(MyNamedObject)" because of the potential of naming conflicts. This is particularly true for the naming of GUI elements which don't have the concept of instantiation when placed onto the Canvas. - Melv. |
| 8 |
Mouse woes
back |
function sceneWindow2D::onMouseMove( %This, %Modifier, %WorldPosition, %MouseClicks )
{
//get mouse positions
$mxpos = getWord(%WorldPosition,0);
$mypos = getWord(%WorldPosition,1);
UpdatePlayer();
}
Thats my mouse handling code - someone on these forums told me how it was done, however, when I click, it pauses movement for some reason? Am I doing the right thing, as this is an entirely mouse-driven game?
TIA, Rob Melv's response Nothing wrong with that code. When you click the mouse and move, it produces "onMouseDragged()" or "onRightMouseDragged()" events, not "onMouseMove()" at that point. You can put the same code in the dragged call as well if you wish (example below). Also, Iīd definately recommend not splitting-up the X/Y components until you have to. No need doing more work and having more variables than you have to. Also, you donīt need to store the players position or use globals to transfer stuff like this. Most of the time these variables will be out of date so they are just overhead and confusing. Just use something like:- // Mouse Move. function sceneWindow2D::onMouseMove( %This, %Modifier, %WorldPosition, %MouseClicks ) { UpdatePlayer( %WorldPosition ); } // Click and Drag. function sceneWindow2D::onMouseDragged( %This, %Modifier, %WorldPosition, %MouseClick s ) { UpdatePlayer( %WorldPosition ); } // Update Player. function UpdatePlayer( %WorldPosition ) { myPlayer.setPosition( %WorldPosition ); } // Where is my player? echo( myPlayer.getPosition() ); - Melv. |
| 9 |
Determining where collision happened?back |
original question What is the best way to determine which side of a rectangle one object collides with another? Could I use the %normal parameter from onCollision() to determine this? Or would a simpler way be better? Any takers? :) The "onCollision" returns you the exact collision point (or points). See "contact points" in the "onCollision" callback. If you need to know about the objects then you've got the "%srcObj" and "%dstObj" and you can get their positions and details as well. The normal parameter gives you the direction of the collision surfaces in question. - Melv. |
| 10 |
Vert cols and sprite brightness
back |
- SetBlendColour() - SetBlending() The reference documents are your friend. :) - Melv. |
| 11 |
Image questions
back |
T2D doesnīt fix anything. T2D gives you complete choice. Okay, imagine another 2D engine if you will.... The coordinates you use are (0,0) at the top-left and the resolution in the bottom-right, say (800,600). You design your game to work in pixels and everything is good. The user changes the resolution to 1600x1200 and your game still renders to (800,600). So you say, well I have some variables that look at the resolution and I change the limits of all my objects, where my center is, where my enemy appear. Boy, what alot of fuss over something not under your control. Then comes T2D that says, choose your own logical coordinate system. Have any coordinates you want. Now you can use a standard coordinate system that automatically scales your graphics for the resolution with absolutely no changes to your code whatsoever. Then someone says, but I donīt want that, I want my old method where I have coordinates mean pixels. T2D says fine then, do this:- // When the T2D window has changed... function sceneWindow2D::onExtentChange( %this, %newExtent ) { // Set my view to be the Screen-Resolution sceneWindow2D.setCurrentCameraPosition( "0 0" SPC %newExtent ); } Wow! Okay, can I have it really old-school and have the (0,0) view at the top-left? Yes, just use... // When the T2D window has changed... function sceneWindow2D::onExtentChange( %this, %newExtent ) { // Set my view to be the Screen-Resolution sceneWindow2D.setCurrentCameraArea( "0 0" SPC %newExtent ); } .. instead. T2D allows you to work how you want. Weīve tried to make as few assumptions as possible thatīll impact the way you make your games. - Melv. |
| 12 |
Rotating and moving spritesback |
original question I'm slowly getting to grips with T2D, but not being a coder, I'm struggling. Still, I'm making progress day by day :) I'm trying to figure out how to get my players sprite zooming about on the screen as I want it to. For the effect, think an Asteroids ship with the thruster stuck on, but the player can rotate the ship to change direction. So far, my Action Map fires these procedures:
function playerCW()
{
$player.setAngularVelocity( -90 );
$player.setLinearVelocityPolar(($player.getRotation()+90),10);
}
function playerCWStop()
{
if ( $player.getAngularVelocity() < 0 )
$player.setAngularVelocity( 0 );
}
This rotates the player clockwise. There are corresponding functions for anti-clockwise. I hope I have used the various set functions correctly, but here's how I'm using them and what's happening at the moment:setAngularVelocity(-90) - This is the speed at which the player rotates, and as long as the key is held down, the player rotates. Releasing the key stops the rotation. setLinearVelocityPolar(($player.getRotation()+90),10) - This gets the players current rotation value and adds 90 to it so it's pointing the same way as the sprite (to the right). The second value is the speed the sprite should move. This all works, except that setLinearVelocityPolar is only called once per keypress. So if you hold the rotation key down, you can effectively fly backwards. The next quick tap of the rotation key sorts it out and you fly in the right direction again. I want the ship to constantly be moving in the direction it's facing. I get the feeling that I'm *almost* there, but there's a bit of the puzzle that's fallen down the back of the sofa and I can't reach it. Any advice would be appreciated :) reponses You'll need to use a schedule to handle applying the setLinearVelocityPolar
function playerCW()
{
$player.setAngularVelocity( -90 );
$turnCW=true;
playerCWSched();
}
function playerCWSChed()
{
if($turnCW)
{
$player.setLinearVelocityPolar(($player.getRotation()+90),10);
//Every 1/4 second (250 milliseconds) apply thrust
schedule(250, 0, "playerCWSched");
}
}
function playerCWStop()
{
if ( $player.getAngularVelocity() < 0 )
$player.setAngularVelocity( 0 );
$turnCW=false;
}
|
| 13 |
Z order of sprites?
back |
Sprite.SetLayer() AND Scenegraph.setLayerDrawOrder(sceneobj, command); AND Scenegraph.setSceneDrawOrder(sceneobj, command); command = 'FRONT' 'BACK' 'FORWARD' 'BACKWARD' |
| 14 |
Isometric games?back |
We do have plans for ISO tile sets for the future. Hard to quantify how much work is involved. We do know the issues involved though. Some critical design decisions to be made there.
I don't really want to open-up a debate on implementation details of ISO tiling at this point as we're still in the middle of a stealthy EA1 release and are just fixing the first-round of bugs making sure that T2D stays extremely useful but.... The main problem with ISO tiles would be how to integrate the idea of z-ordering into T2Ds layer system. Getting the tiles rendered in order is easy as pie but without doubt, people would then want to move standard sprites, particles, whatever through the tile-space and not have to worry about z-order. What we don't want is to change all of T2D to suit the ISO tilesets, I'd rather not support it in that case. We can generate something like a fxTileISOLayer2D, identical to the fxTileLayer2D that renders a z-correct set of ISO tiles into a T2D render-layer. Trouble is, in this ISO layer, we've got a virtual 3D world. We're NOT going to change every T2D object (and the functional complexity that goes with it) so that it can be position within this virtual world. Also, people would expect physics, mounting and all that but it's easy to forget that this is a virtual 3D world and we're not about to write a 3D engine again!!!! I haven't thought about this for a couple of weeks but I'm happy to tell you where I got to. If we were to implement it, we'd probably have a set of seperate rendering objects that could be positioned in the world, something like fxISOSprite2D. As I've said above though, it starts getting complex as you've got to do 3D (box) swept-collisions which is right back to 3D. I personally think that T3D would be best suited for this but we do intend to look at this in T2D but I won't stick my neck out on dates. :) - Melv. |
| 15 |
Help with "look at" ( using vector ops? )
back |
Hereīs the code we used in the new "Grav" demo featuring "Flegg". His head is mounted onto neck segments which stretch as he moves and eventually, his head catches up! Anyway, when you move the mouse cursor, Flegg watches it. The script code we used to achieve this is...
// Yes, so get Fleggs Head Position.
%flegHeadPos = flegHead.getPosition();
// Seperate the X/Y components of the head position.
%flegX = getWord( %flegHeadPos, 0 );
%flegY = getWord( %flegHeadPos, 1 );
// Seperate the X/Y components of the mouse position.
%mouseX = getWord( %worldPosition, 0 );
%mouseY = getWord( %worldPosition, 1 );
// Calculate head-angle.
%headAngle = mRadToDeg(mAtan(%mouseX - %flegX, %flegY - %mouseY));
... or...
function Angle(%x1, %y1, %x2, %y2)
{
return mRadToDeg(mAtan(%x2- %x1, %y1 - %y2));
}
The bizarre inversion (%flegY - %mouseY) is because the coordinate system has the origin at the top-left of the screen.Look out for those neat helper functions like "mRadToDeg()" and "mDegToRad()"; soooo helpful. :) I'm thinking at "rotate-to" utility function should be added so I'll put that on my list. - Melv. |
| 16 |
Bouncing ball physicsback |
original question Just curious, but is there a way to have the physics system do the vector reflection for a bounce collision response so I don't have to create all this sub-system stuff to get the unrealistic response I need? :) It bounces objects off the WorldLimits, so can we also use that to override other collision responses? Would it handle the arbitrary angles of collision polys? response The physics system is extremely powerful but with that power comes responsibility. :) Understanding how the physics works is key to configuring it into a "dumb" mode. Try the following:- - Ensure that you've got no friction so set that to 0. - You want almost perfect bounces to set the restitution to 1. - You don't want energy to bleed-off so set the damping to 0. - Keep the forces within reasonable bounds by adjusting the density of your object. Density is very sensitive so tweak with small fractional increases although the default is good. - You want all the energy to be dissipated into the bouncing object so set the other object to be immovable (density 0) - helper func setImmovable(). - You don't want your objects to rotate so set you max-angular velocity to 0 although you get more accurate results from an object that spins. Follow these rules, most of which can be defined in a collision-material datablock and you will be okay. If you continue to struggle, I'll post a simple example soon. - Melv. |
| 17 |
Query current Animation?back |
original question Is there a way to find out the current animation an AnimatedSprite2D is playing? response I haven't added those calls but the info is there and would only be a couple of lines of code. It's probably a good idea so I'll add it to the list. - Melv. more responses Here is a workaround function fxAnimatedSprite2D::playAnim(%this, %anim) { %this.currentAnim = %anim; %this.playAnimation(%anim); } so instead of using $player.playAnimation(thisAnimation); use $player.playAnim(thisAnimation); then to get the current animation reference $player.currentAnim; to see it echo($player.currentAnim); more repsonses Ok, well threw together a couple bigger functions if you use this playAnim it will keep a record of the last 5 animations (as you can see you can change %this.animLimit to whatever you want though) you then use .getLastAnim() to get the last anim... and if you want previous animations you just throw an offset number in there.... for example echo($player.getLastAnim(1)); this will display which animation was one animation back a bit of looping in here that keeps the limit at whatever you set it as and when it goes over it kicks each value back once so everything is stored correctly function fxAnimatedSprite2D::playAnim(%this, %anim)
{
%this.animLimit = 5;
if(%this.playAnimation(%anim))
{
if(%this.animCount > %this.animLimit)
{
%this.animCount--;
for(%i=0;%i<(%this.animLimit - 1);%i++)
%this.lastAnim[%i] = %this.lastAnim[%i+1];
}
if(!%this.animCount)
%this.animCount = 1;
%this.currentAnim = %anim;
%this.lastAnim[(%this.animCount - 1)] = %anim;
%this.animCount++;
}
}
function fxAnimatedSprite2D::getLastAnim(%this, %offset)
{
if(%offset >= %this.animCount)
{
echo("Do not have anim that far back");
} else
{
return %this.lastAnim[(%this.animCount - 1) - %offset];
}
}
|
| 18 |
Compiling under MacOS X?back |
Reported this over in the Bugs, but to compile under MacOS X you need to do a couple things first: Doubleclick on Torque2D-MacCarb-Debug for the properties Select 'Search Paths' Delete the entry for '/Josh/Programming/engines/Torque2D/EA1/Release_1_0_Base/torque2d/branches/t2dea1/lib/vorbis/macosx' Repeat for Torque2D-MacCarb-Release Open Terminal, go to your T2D directory: cd lib/vorbis/macosx ranlib libogg.a libvorbis.a Easily fixed, but just in case |
| 19 |
Tilemap edge problemback |
original question When I create my imagemap to use in the tilemap editor is there anything special I should be aware of? I have an image that has 8x3 of 32x32 pixel tiles. When I start the editor in it's default settings and draw my tile I see a blurry line on the top or left edge of some tiles. It's like the filtering is wrapping round or something. Any ideas? responses I'll be looking at different ways to do this. I want it as transparent to the user as possible. Got a few ideas. -Melv |
| 20 |
Adding Functions - Game not updating?back |
Also, if there is an error in your code, T2D will use the last successfully compiled version of it (the .dso) file. If your game doesn't work quite right, look in the console for errors, or scan the console.log file for problems. To force a recompile of your .cs file, just rename the appropriate .dso file and see what happens. If it goes completely bananas, put the old one back, and start scanning your code for problems. |
| 21 |
Collision "hitch" at tile seam?
back |
Original Questions
I noticed that when sliding along a row of collision tiles, and the player is angled into the wall slightly (so there is part of the force pushing into the wall), that the player collision "catches" where two tiles butt up against each other, causing a collision hitch. In other words the player doesn't just slide along the wall nicely, it catches and spins away when it hits that seam. THe player collision in this instance is a wedge. It's the front point that catches. I tried blunting the point a bit, but it still catches. I'm using setConstantForcePolar to apply the force to the player. and I am having a issue with my character bobbing up and down when he walks. I am making a platformer style game, where the physics are similar to a game like Super Mario Brothers. I apply a constant force to the scene so that all objects are pulled towards the ground. Then I apply a constant force to the character to make him walk back and forth. The problem is, when the character touches one of the "seams" in a tilemap collision polygon, he kind of gets caught on it. This makes the character bump up a little when he hits it. If you are going really slow, in some cases it will actually stop him from moving. Responses Iīm aware of this issue. youīre just too good and finding problems. ;) I wonīt bore you with all the details but it is partly a precision issue and partly related to the fact that each tile has a discreet and discontinuous collision-polygon. Applying a continuous force that causes the object to collide with the layers on angles, produces this issue. v You can start to get around this issue by balancing the mass/forces involved as well as reducing the dynamic friction coef of the surfaces. You can also clamp angular momentum at zero. Thankfully, there are different (transparent) ways to resolve this problem though in the engine. This is one of the "bigger" issues that Iīll be focusing my efforts on soon. Sorry for any inconvienience this may cause. - Melv. |
| 22 |
Physics Timing Issuesback |
Original Question I am having a few issues with the the physics. I have a character that needs some basic platformer style physics (think Super Mario). Basically the little knight dude i have has the ability to jump and walk around. The problem is, that he can jump, but he jumps different heights on all machines. So I have gravity setup by doing the following after creating the scenegraph: Responses Hmmm, you should have consistency, independant of OS or timings as long as the relative FPS differences are not too extreme although even then, the differences shouldnīt be that noticable. Iīll play with this as soon as I can (so many things to resolve at the moment) so Iīve just added it to my growing list. v Sorry for any inconvienience this may be causing. -Melv |
| 23 |
Moving the cameraback |
Original Question Effect I'm wanting to achieve: player can move around window, but camera scrolls to prevent movement off window. Planned method: set world limit for player with NULL and a callback to a function setting camera velocity appropriately. Problem: I can't find a way to set camera velocity. I could extrapolate a position, set a target, start the camera move and have the movement interpolated but that seems like a lot of work to get back to the same place. What am I missing? Responses Don't forget that you can mount the camera to any T2D object, even use forces. You can also restrict the view so a larger region and the camera will never view outside of it which is important if you want your player to be able to move there and the camera is mounted to it. - Melv. Result @Melv: Thanks! I'd missed being able to mount with a force and that does *exactly* what I want. Now its just a matter of playing with the force number. |
| 24 |
Does T2D currently support DirectX as a graphics renderer instead of OpenGL?back |
Guys... if you compile the T2D project, the opengl2d3d glu2d3d dlls will be compiled for you, as a dependent step. I know lots of you may not be super familiar with C++ projects, so not includings this in these in the example directory itself was an oversight on my part. Sorry. :) We'll make sure they're in the next release. |
| 25 |
Oh no flickery flickery!back |
Original Question Ouch! strobe like flickering when I run full screen! Responses Yes, it's all easy when you have a specific case on a specific OS but we've got a cross-platform system here and things can get a little complex. I cannot just jump into the code and do a little hack on anything that touches platform-level stuff. Stuff like this takes longer than you would expect because there are many other considerations. Again, no big deal, I'll do some investigation, chat with Ben Garney and Josh Williams and see what's the best approach. That's the best I can do at the moment guys. - Melv. |
| 26 |
Object IDs and Picking -- How do I know what I clickedback |
Original Question I presume that picking in Torque works someting like it does in OpenGL. Looking at the manual, if I use the function: fxSceneGraph2D::pickPoint()It should return a list of object IDs beneath a given point. My question is: How do I convert an object ID back into an object, or alternatively can I set the object ID of something myself so that I know what I got back? Responses The good thing is that you donīt need to do any conversion at all. Hereīs how it works... If you create an object like this... %obj = new fxStaticSprite2D(); ...you can do this...This is will return the objects internal ID thatīs used by T2D. Assuming this number is "1234", you can still do stuff like this... 1234.setPosition( "10 20" );1234.setSize( 40 );... which is cool. What this means that the object-IDs that the pick-routines return (as do other functions), can be used directly so I can do this...
// Pick a point.%pickList = myScene.pickPoint("5 10");
// Get Pick
Count.%pickCount = getWordCount(%pickList)
// Finish if we didnīt pick anything.
if ( %pickCount == 0 ) return;for ( %n = 0; %n < %pickCount; %n++ )
{
// Fetch Object.
%obj = getWord( %pickList, %n );
// Dump where object is actually positioned.
echo( "We picked object whose position is" SPC %obj.getPosition() );
}
... and we can do this because "%obj" contains the ID and it can be used as the object itself!One thing to add is that the picking routines use the collision-polygon which defaults to the same size as the bounding-box. It does this because it uses the same swept-polygon system to pick a point, area or line. - Melv. |
| 27 |
Executable icon and name...back |
the application name and its icon are things you set in the C++ project file. In Visual Studio, you look under the project properties, in XCode you look at the "target properties", I'm not sure for Eclipse but it's gotta be something similar, and if you use make files, you change the build product name, etc. :) This is probably one not to worry about much until everything else is done. But, if someone has time to write-up a quick tutorial on how you change app names and icons in various IDEs explicitly, I'm sure many people would find it useful. |
| 28 |
Default BG color?back |
There isn't a T2D setting as T2D doesn't have any concept of background, there's just a standard bitmap background control setup. You don't have to use this though. In the "mainScreenGui.gui" file, you'll see a "GuiChunkedBitmapCtrl" called "mainScreenGui". This displays the T2D logo thats located in "./images/background". You can edit this setting in the console editor (F10) or manually editing the file. Just changing the bitmap will do this. We'll be changing the default background to something darker, probably in the next release. - Melv. |
| 29 |
SetCollisionMasks() help...back |
Original Question I need some help understanding setCollisionMasks( groupMask/[layerMask] ) Reference docs donīt give me (artist trying to be programmer too) enough info on whatīs going on, or perhaps Iīm looking at it wrong. Iīm attempting to get my player to collide(and die) with objects in group 3, layer 8, but setCollisionMasks( 3, 8 ) doesnīt work and Iīd like to be able to specify multiple groups and layers. I also noticed that in the spaceshooter tutorial Melv uses BIT(2). Why? I didnīt find any reference to it in the reference docs. Can I delay the collisionmask by a few millisecs so I can get the object out and away from the firing object first? I want the projectile to be able to kill even the player firing it. Responses Just use BIT(3) and BIT(8), as Robert says. In the future, weīll probably make it so that if you donīt specificy "BIT(X)", T2D will just interpret the parameters for you as bits. But for now, this is the way. Re: srcObj and dstObj in collisions, other people have said they find it helpful to re-name these sendingObj and receivingObj, respectively. The srcObj is the object which is causing the collision, and the destination object is the object against which a collision is occurring. If you have two moving objects that are configured to both send and receive collisions, thereīs really no good way to tell which is which, except by using some sort of tag to identify the objects. I probably do this too much, but I canīt help but describe how these systems are planned to change... in the future, the collision callback will probably change so that you can specify a collision callback function name per-object (though we'll still keep the general / default callback around, since that is convenient for many, many situations) |
| 30 |
delay the collision?
back |
Original Question I'm sure I saw a post where someone showed how they delayed the collision by 250 millisecs so it could clear the area first... Response - person A Also, for disabling collision, you can use the setcollisionsupress (true) to turn off all collisions for that object. Just set it to true, then use a script schedule to turn it back off after a few milliseconds. Response - person B Ah ha! I missed that in the tech docs. Thanks for the help. I was just going to move the linkpoint out further and leave it at that, but this is much better. EDIT: I find myself unable to make it work. My code: %cannon_ballProjectile.setCollisionSuppress( true ); // so as not to collide with barrel schedule( 250, 0, %cannon_ballProjectile.setCollisionSuppress( false ) ); // activate collision returns error: %cannon_ballProjectile.setCollisionSuppress( false ): Unknown command My code: %cannon_ballProjectile.setCollisionSuppress( true ); // so as not to collide with barrel schedule( 250, 0, %cannon_ballProjectile.setCollisionSuppress( false ) ); // activate collision <-- note: without quotes around commandreturns error: Call to setCollisionSuppress in player1Fire uses result of void function call I know this more of a basic TorqueScript question, but I couldn't find sufficient documentation and copying examples I've found from TGE hasn't worked as you can see above. Response - person A Matt, you're almost there. Just change the schedule line to be: %cannon_ballProjectile.schedule (250, setCollisionSuppress, false) ;Using your method invokes a global schedule handler. You'd have to write that supress line inside a function, and then point the global scheduler to that. (At least, that's how it seems to work, those who are more TS savvy might say differently!) Where if you invoke the local schedule method on the %cannon_Ballprojectile, you're just calling setcollisionsuppress as a part of that object. (There's no reason to have the '%cannon_ballProjectile' in front of it.) Also, you can't pass parameters in the same manner, they need to be given as seperate arguments in schedule. |
| 31 |
Loading and Saving Tile Mapsback |
Original Question You can save tile maps to the T2D/client/maps folder (as well as many others), but you can't load maps from that folder. As far as I can tell you can only load maps from the tileeditor/client/maps directory which makes it a nuisance to edit maps. I'd love to be proven wrong here. Also, the load dialog shows files that begin with a period which are supposed to be invisible. Not a big deal. Another thing about this is that the load dialog doesn't re-list the files every time it's opened. So if you put a map in the maps folder, you have to quit T2D and reopen it to be able to edit that map. Most annoying. Response Thanks again for the report. As I posted elsewhere, we'll be refining the way the tile editor loads in the future. We just had to get a basic system up and running for now. The workflow isn't nearly as smooth as it will be in the future. Right now, it should just be considered a rough first-pass... it's much, much better than nothing (believe us.. we were hand-coding tilemaps for a while ;). Much more work to come in this area, appreciate the reports, but please don't get too frustrated. Under stand that this is a very early pass at this tool. -Josh Williams |
| 32 |
Custom Tile Images?back |
Original Question Where do you place custom PNG files so they show up in the tile editor. I placed the PNG images in "~tileeditor/client/images" and can not load them. Thanks for the help! Response The defaults are in the t2d/client/images in t2d/client/demodatablocks.cs they have set up the ones that show up when u launch the tile editor at the mo. have a look in there are youīll get the gist of what u need to do :) Another Response Just so you guys know, we'll be refining the way the tile editor loads in the future. We just had to get a basic system up and running for now. The workflow isn't nearly as smooth as it will be in the future. :) -Josh Williams |
| 33 |
Acceleration Woesback |
Original Question Okay, I'm having some issues with my acceleration code. I'm currently working on a top-down shooter--I guess the controls are somewhat similar to asteroids. I get the x and y vector and multiply that by an acceleration modifier. Now, I can limit whether or not to add the acceration value if the current x or y value is less than my defined max velocity, but that of course will not work if I'm moving at an angle other than 0, 90, 180, and 270. It occured to me to use vectorlength2d for the player's current velocity to compare to my maxspeed value, but that doesn't seem to work how I want either. Does anyone have any pointers on how to best achieve this sort of thing? I hate to be a bother, but this one really has me stumped. There Own Response Thanks for your example, Philip. My problem was a little different. The player's ship is set to accelerate at a fixed modifier until it reaches max speed. I was correct in thinking that vectorlength2d would work for what I needed, but I was a little off in the execution. Now it seems to work, but it seems like it takes a really long time to alter your course.. it may just need number tweaking, or I may have screwed something up yet again.. Not sure. I can post what I have if it would be useful to anyone, or if anyone wouldn't mind taking a look to see how to improve upon it. Just let me know. |
| 34 |
Collision callbacks?back |
Original Question The collision normal - how does that work? it's two numbers and I'm not sure how I might use it to my gain... Response The collision normal is a vector (x y). Collision point(s) tells you where a collision happened, the normal tells you its direction and magnitude, the collision time tells you the time the collision occurred, and the src and dst objects tell you the objects involved with the collision. With that info you have or can query for everything you need to do realistic collision responses. :) |
| 35 |
What determines if an object is the src or dst for collisions?back |
Original Question If I have two objects that collide, how is it determined which is the source and which is the destination? Without knowing how this works, I can see my code being a bit more complicated (having to account for the sender being A or B). If an object is only set to send (like a bullet) or receive (like a target) then it's a bit easier to account for collisions. Response @Philip: Itīs related to what attempted to move into what. When you activate collisions using "setCollisionActive()", one parameter is for send and one is for receive. If you wanted your bullets to only send collisions (not receive them), then you can. This way, a bullet would only send and therefore be the "%srcObj". - Melv. |
| 36 |
Bringing Focus to an Input?back |
Original Question I wanted to learn about the GUI system, and my kids needed a good math facts drill program, so I made one. I'm still trying to figure out how to make the input box focused programatically. Response This is a case where you will want to name your GUI control. Something like txtAnswerBox should look like this in the file
new guiTextEditCtrl(txtAnswerBox) {
You can then call the following to set focus to that control:
txtAnswerBox.makeFirstResponder(true); |
| 37 |
Map data formatback |
Original Question Hello, Is the format for the storage of map data given anywhere? I'd like to add the ability to make T2D maps in my own map editor. Response hierarchical. The fxTileMap2D saves its own private data (as well as the parent sub-object) as well as all the fxTileLayer2D objects which in turn, save their own private data (and their parent sub-objects) as well as the tile database itself. The tile database is composed of different tile-types that have their own private-data as well as physics-info which is a seperate object that's used by all fxSceneObject2D objects and it saves its own private data as well as collision-definitions etc. There are certain tile-types that are true objects in their own right; these are fxActiveTile2D objects which are self-contained objects that can exist within the tile-layer (think of gun-turrets etc) and these save their own-private data and any custom data that a user might define as these can be customised in C++ to create gun-turrets, tile-particle emitters etc. All in all, it's a pretty complex format but is clearly defined in the code and is encoded by the T2D stream which deals with endian issues to correct for the platform its running on. You can follow it by looking at the console method in "fxTileMap2D.cc" (approx line 829) and following the stream saves. ConsoleMethod(fxTileMap2D, saveTileMap, bool, 3, 3, "(tileMapFile$) - Saves a Tilemap File.") At this point, we'll not be issuing such info as it's likely to change, besides, we've provided the well-documented code. There is a bunch of work to be done on the tilemaps, including work on active-tiles so I'd be careful there. - Melv. Another Response We will definitely be changing the tilemap format soon, and it'll be in an easier to document state at that point. (It's a good format right now, it's just complex). As Melv says, reading the load / save code is probably the best bet for now. We can't spend time documenting this atm, since any doc we write now will be subsumed shortly. |
| 38 |
Keeping track of things...back |
Original Question Hi there! If I use the same global variable to create many enemies, how do I "loop" through the enemies again after I have created them? Does T2D keep an internal list, or would I have to roll my own "linked list" ? how does that kind of thing work in T2D? I would not like to have to use indexed arrays as the list could grow and shrink in size as objects are created and safe deleted :) Response These are what you need to use, SimSets. - Melv. |
| 39 |
what formula T2D uses for random numbers?back |
Fast, very good random numbers Kirkpatrick, S., and E. Stoll, 1981; A Very Fast Shift-Register Sequence Random Number Generator, Journal of Computational Physics, V. 40. Maier, W.L., 1991; A Fast Pseudo Random Number Generator, Dr. Dobbīs Journal, May, pp. 152 - 157 Period = 2^249 R250 All TGE products use this. You have the code so you can look in "mRandom.cc/h". I would say that it would only be a problem if you were relying on a some kind of determinism based upon a seeded value although there may be other scenarios Iīve not thought of. - Melv. |
| 40 |
Basic question: where to store globals?
back |
Original Question I'm not familiar with TGE at all, but I can code a bit. So, my questions with T2D are probably really, really basic stuff for people coming over from TGE. Two that I'm coming up with right away are: 1) Where do I store any kind of global variables or data? Things like playerMaxVelocity, playerHP, playerLives, etc? I'm assuming I instantiate a datablock, but the T2D references only describe T2D specific datablocks. Along these lines, are all variables scoped inside of datablocks? Which are basically like structs? (Sorry I'm kind of a noob coder). Can I declare local variables inside of functions? Is it basically like C/C++ as far as control structures, etc? I guess this is a big huge topic... any help is appreciated though. v 2) Are there any references for other useful commands, such as writing to the console for debugging. Anything like "printf" type parsing so I can check variables? Even better would be text on the screen. (There may be reference for this... haven't looked for that yet). Response $playerHP = 10000; echo($playerHP); Another Response Here's the official GG Documentation to look through. Two other useful references are... Language Reference Console Commands Other than that Phil, just ask, we're always here, time-zones allowing. :) Good Luck. - Melv. Another Response $playerInfo = new ScriptObject(); $playerInfo.hp = 100; $playerInfo.lives = 10; etc..... you can also then do $playerInfo.dump(); in the console and it will dump all the contents of the object... writing to the console for debuging
echo("debug info");
:) Another Response To answer some of your specific questions: --Global variables are automatically placed in a namespace that is visible to other modules. It is as simple as using the $ in the front of the variable--that's what makes it global, and the script console takes care of the rest. --local variables are created dynamically as well (simply use them), and are indicated by the % in the front of the variable. These act pretty much just like local variables in other languages, and are only accessable via the same scope/namespace. Another Question (self answered) This is somewhat related, so instead of a new thread I figured Iīd ask it here. Is there a way to dynamically select a namespace? For instance: $myPref:: Where Edit: While I'm guessing that this isn't possible, if it is I'd love to know. :) But meanwhile, I've chosen to just do this: $myPref::someVariable[ since it does essentially the same thing. |
| 41 |
GG staff mentioned... a profiler?back |
Original Question Yo! On the channel, someone mentioned a profiler - possible to enable this thing with a command etc? :) Self Response Never mind :) Two console commands to help: profilerEnable(1); profilerDump(); :) Response Thanks for posting the answer. :) If you encounter any probs with the profiler, let me know. I only had the opportunity to run real basic tests on it. |
| 42 |
How about a raycast command which works within the world?back |
There are three types of pick function in T2D, "pickPoint()" (point), "pickArea()" (rectangle) and "pickRay()" (line). These functions use the swept collision-detection system and are very accurate/fast. They detect against the objects collision polygons and return a complete list of all objects (if any) that are picked. Note that the "pickRay()" returns the objects, presorted in the order that they collide along the line. As mentioned above, "castCollision()" is a powerful function that allows you to sweep any object through forward-time to see if it collides with anything. The advantage here is that the objects collision-polygon is used for the sweep against other objects collision-polygons. The important factor here (as is stated in the reference doco) is that the collision-test is done using the objectsī current setup. Typically, this would already been setup but if not, you need to setup the collision masks etc. The way this call works is that you specify a time and T2D will check for a collision over that time-period. If the object is at rest (zero linear velocity) then it will not collide with anything (unless itīs currently overlapping something). If you want to check in a certain direction then simply set the linear velocity (using polar for a specific direction), do the "castCollision()" call and then restore/reset the linear velocity and any other settings you changed. Typically though, youīll probably only specify the time for an object moving in a certain direction already. The "castCollision()" returns you rich collision-info in the same manner as the "onCollision()" callback. It returns the following:- - collision time - position x - position y - collision normal x - collision normal y Hereīs "castCollision()" in action in the pool demo...
- Melv. |
| 43 |
Creating sprites with Datablocksback |
So, Iīve been trying to create a sprite based on a datablock. For example:
datablock fxStaticSpriteDatablock2D(Sprite1) { imageMap = sprite1ImageMap;}
Now, normally in Torque you would go about creating something with this datablock like this:
%player = new Player() { dataBlock = SomeGuy;}
I tried this in T2D and it didnīt work:
%player = new fxStaticSprite2D() {
scenegraph = playSceneGraph2D;
dataBlock = Sprite1;
}
After digging around in the source I found out how to do it:
%player = new fxStaticSprite2D() {
scenegraph = playSceneGraph2D;
config = Sprite1;
}
Just a note to anyone else that runs into this problem. |
| 44 |
Mountingback |
Original Question I'm trying to mount a few pieces together. I am putting user inputs on what I'm calling "Piece". Anything else that is mounted should move with it in a very rigid way to include rotation. Both "Pieces" are just static sprites, nothing special. I have set up the link point like this: $piece.LeftLinkPoint = $piece.addLinkPoint("-1 0"); and I have mounted piece2 like this: $piece2.mount($piece, $piece.getLinkPoint($piece.LeftLinkPoint), 0, true, true, false, true); "Piece2" does rotate around "piece" in a very rigid fashion that I am looking for, and moves with it in a desired way, it is just way far away. It is only supposed to be 1 world unit away and it is nearly off the screen. But the world space is nearly 60 units across. I tried changing the number to 0.1 instead of 1 and it is in the same exact spot. I'm thinking maybe it has something to do with the scaling I performed on the images? So for more info on that if you need it: Each "Piece" is currently using the same image, nothing more than a 32X32 box. I set their size to 4X4 when I initially set up the images: $piece.setSize("4 4"); So does scaling do something to mounting? Response Yes, the mounting system uses the same coordinate-system as the collision-polygon one. (0,0) is the center of your object, (-1,-1) is the top-left, (1,1) is the bottom-right and so on. The reason for this is so that the position you mount to on an object is independant of size. If you size the object, you want the mount-point to be the same (just like you would the collision-polygon). If you mount to "-1 0" in your example, you're asking to mount to the far left/middle of the object which you want to be no matter what size it is. Do this make sense? - Melv. |
| 45 |
Sprite setPivotPoint()back |
Original Question
Unless I'm missing something (entirely possible) you can't set the pivot point for (at least) staticsprites. There is a setPivotPoint() function for particle effects and I decided to try it for grins on the sprite (hoping it existed undocumented) but all I got was an error. What am I missing? Or can this be added? Response As Melv has mentioned, you can "fake" arbitrary rotation points without doing the "make the sprite larger" dealie-- By mounting one object to another. For example, letīs assume a hammer sprite, that you want to smash something with. If you just make the sprite normally, then try to rotate it, it will rotate around the exact sprite center -- which in this case would be somwhere around halfway up the handle. Not what we want. So, you make a new fxSceneObject2D, set its size to something moderate, and donīt set an image for it so that it is invisible -- then mount the hammer sprite onto it, at the top. Line up the bottom of the hammer with the center of your newly-made object. Set the mounted hammer to track rotation, and boom, when you rotate the parent object, the hammer will tip as if its rotating along the base. UPDATE: Hmm, maybe this will explain it better:
|
| 46 |
Creating a help file for T2D engine docsback |
Ok, Out of the need for engine docs, I created a .chm file based on the original resource by Daan Broekhof. To do so for T2D you need a couple of files that are not in the sdk. Follow these directions and then you will be all set. I'm sure a lot of you could or have figured out this already but I figured I would post it just in case. Right now, this will only work for the people who have a TGE license. After I get permission from GG, I will include the files needed. First do this: 1) Go to your TGE/SDK/ folder and copy all the folders in the doc folder. 2) Copy those folders into your T2d/SDK/doc folder. 3) Go to your TGE/SDK/Engine folder and copy engine.changelog.txt and engine.overview.txt files 4) Copy those files to your T2D\SDK\engine folder 5) Follow the instructions on this resource Example: How-to generate the documentation in Windows Help file format (chm) And that should be it. Please remember that the files that you are removing from TGE (engine.changelog.txt and engine.overview.txt) have information about TGE in them. Until (or if) they create doxygen stuff for T2D the files will come off a little weird. Namely they will have TGE overviews etc.... But the hierarchy and all that are correct. For now though, its a good way to see whats going on inside T2D |
| 47 |
"blank" != "blank" ???back |
Original Question
Check it, the following two lines of code immediately follow eachother in script:
$piece.tag="blank";
if($piece.tag == "blank")
{
Yet the stuff following the if statment never exectues. Conversely:
echo($piece.tag);
if($piece.tag != "blank")
{
also never executes when the tag actually doesn't = "blank". Looking at the console.log it says: T2D/client/client.cs (195): string always evaluates to 0. Why is that? Response When you are comparing strings, you need to use $=, not ==. To check for not equal, use !($piece.tag $= "blank") (I think, it's been a bit on that particular check). |
| 48 |
Changes In Script Not Showing?back |
Check the console after each unexpected result for grey or red errors :) |