Problem keeping object in scope
by Jason Swearingen · in Torque Game Builder · 07/14/2005 (3:05 pm) · 11 replies
EDIT: The real bug is how : $player = new fxStaticSprite2D();
is different from new fxStaticSprite2D(mySprite); $player = mySprite;
and how that affects equality operators "==". Skip to my post from <> for the explanation.
-Jason
=============================================
I'm having a problem which looks to be the object leaving scope, and/or not being properly registered with the engine.
this demo of the problem i'm facing uses the Intro-Basic-Tutorial.
#1 First off, let me show what works.
With the above code, the player object gets created fine, and lives throught the scripts functions.
#2 If I change the code slightly, things break:
If I do the above code, the player object is properly allocated *for that function only*. meaning that it seems once I leave the current function (CreatePlayer()) the $player variable isnt properly defined or pointing to the right object.
The reason this is a problem, is that i'm trying to implement this object creation via C++.
#3 If I run the following code, the behavior is the same as #2 above.
The stack-pushing code that #3 is missing is:
Any of you supre-torquers got an idea what I'm doing wrong, and how I can resolve the problem in C++??
Much thanks,
-Jason
is different from new fxStaticSprite2D(mySprite); $player = mySprite;
and how that affects equality operators "==". Skip to my post from <
-Jason
=============================================
I'm having a problem which looks to be the object leaving scope, and/or not being properly registered with the engine.
this demo of the problem i'm facing uses the Intro-Basic-Tutorial.
#1 First off, let me show what works.
TorqueScript: $player = new fxStaticSprite2D;
With the above code, the player object gets created fine, and lives throught the scripts functions.
#2 If I change the code slightly, things break:
TorqueScript: new fxStaticSprite2D(mySprite); $player = mySprite;
If I do the above code, the player object is properly allocated *for that function only*. meaning that it seems once I leave the current function (CreatePlayer()) the $player variable isnt properly defined or pointing to the right object.
The reason this is a problem, is that i'm trying to implement this object creation via C++.
#3 If I run the following code, the behavior is the same as #2 above.
C++:
//create new fxStaticSprite2D object
ConsoleObject *object = ConsoleObject::create("fxStaticSprite2D");
//cast to SimObject
SimObject * currentNewObject = dynamic_cast<SimObject *>(object);
// ??? something the C++ engine always does
currentNewObject->setModStaticFields(true);
currentNewObject->setModDynamicFields(true);
// registers the newly created object with the T2D engine
currentNewObject->registerObject();
//this code adds theobject to a SimGroup ...
//??? not sure what this is for, but the c++ always does it
SimGroup *grp = NULL;
Sim::findObject(RootGroupId, grp);
grp->addObject(currentNewObject);
//create a new global variable
gEvalState.setCurVarNameCreate("$player");
//set this globalvariable to point to the newly created fxStaticSprite2D object
gEvalState.setIntVariable(currentNewObject->getId());This is a copy/paste of the C++ functions that get executed when T2D parase example #1, but the above code does the same behavior as #2, but it is EXACTLY what the C++ engine does when parsing example #1, with the exception that I am not loading the object onto a stack.The stack-pushing code that #3 is missing is:
C++: intStack[UINT] = currentNewObject->getId();The reason why I'm not doing this, is I dont know how to implement this properly, as the stack pushing/poping is all done via the lex parser in compiledEval.cc CodeBlock::exec(...)
Any of you supre-torquers got an idea what I'm doing wrong, and how I can resolve the problem in C++??
Much thanks,
-Jason
#2
I will revert back to a stock T2D setup and see if I can get this to repro.. I hope I"m just being an idiot somewhere.
-----------
edit: I think there is a real problem with the engine here, but I dont have time today to look into exactly where. (I gotta work-work)
Tonight I'll try to determine where exactly the $player object is going out of scope and post my results.
--------
-Jason
07/15/2005 (12:20 pm)
Hmmm, yeah I tried the "simple" route but the player object kept going away.I will revert back to a stock T2D setup and see if I can get this to repro.. I hope I"m just being an idiot somewhere.
-----------
edit: I think there is a real problem with the engine here, but I dont have time today to look into exactly where. (I gotta work-work)
Tonight I'll try to determine where exactly the $player object is going out of scope and post my results.
--------
-Jason
#3
Hopefully though, you'll find out what's going on but please keep me posted in-case I have to eat my words, hat, shoes etc.
- Melv.
07/15/2005 (1:45 pm)
I don't think there is a problem with the engine (at least not in the way I think you're indicating). If you look at what you're suggesting, you're saying that global variables are not working (or have some odd scope). If this was the case, none of the T2D demos apps, TGE apps, TSE apps, Tribes 2 etc etc would work as they use this idea extensively. ;)Hopefully though, you'll find out what's going on but please keep me posted in-case I have to eat my words, hat, shoes etc.
- Melv.
#4
I guess it doesnt repro because in the SpaceScroller when the player dies the game is "reset" but that is pure speculation on my part. (I havent looked at the SpaceScroller code)
I will write up a step-by-step repro along with exact symptoms now.. will post it when I'm done.
-Jason
07/15/2005 (6:02 pm)
I have repro'd my issue using a non-modified T2D, using the IntroTutorial. Curriously, it doesnt repro changing the same call in the SpaceScroller Demo (line 82 of player.cs)I guess it doesnt repro because in the SpaceScroller when the player dies the game is "reset" but that is pure speculation on my part. (I havent looked at the SpaceScroller code)
I will write up a step-by-step repro along with exact symptoms now.. will post it when I'm done.
-Jason
#5
The repro is just a step-by-step net result of following the tutorial, so if you have a tutorial (complete with known tutorial bugs such as the "2/3 scrollmap" and "Invalid fxCollisionMaterial"
If you have the tutorial setup already, just skip to the bottom of this post.
setup 'working' tutorial
Copy the following dirs from example/SpaceScroller/client to example/t2d/client
effects
images
maps
open example/t2d/client/client.cs and replace it's contents with the following:
07/15/2005 (6:27 pm)
First, here's a repro. The repro is just a step-by-step net result of following the tutorial, so if you have a tutorial (complete with known tutorial bugs such as the "2/3 scrollmap" and "Invalid fxCollisionMaterial"
If you have the tutorial setup already, just skip to the bottom of this post.
setup 'working' tutorial
Copy the following dirs from example/SpaceScroller/client to example/t2d/client
effects
images
maps
open example/t2d/client/client.cs and replace it's contents with the following:
//-----------------------------------------------------------------------------
// Torque 2D.
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
// --------------------------------------------------------------------
// Initialise Client.
// --------------------------------------------------------------------
function initialiseClient()
{
GlobalActionMap.bind(keyboard, tilde, ToggleConsole);
GlobalActionMap.bindCmd(keyboard, "alt enter", "", "toggleFullScreen();");
// Initialise Canvas.
InitCanvas("T2D");
// ************************************************************************
// Load-up Demo Datablocks.
// NOTE:- Remove this is you're not interested in running the demos
// or any or the default datablocks.
// ************************************************************************
exec("./demoDatablocks.cs");
// Load-up Datablocks.
exec("./datablocks.cs");
// Load-up GUIs.
exec("./mainScreenGui.gui");
// Set GUI.
Canvas.setContent(mainScreenGui);
// Set Cursor.
Canvas.setCursor(DefaultCursor);
// Setup Scene.
//execScript("SetupT2D","setupT2DScene();");
setupT2DScene();
}
// --------------------------------------------------------------------
// Destroy Client.
//
// Here we destroy the SceneGraph.
// --------------------------------------------------------------------
function destroyClient()
{
// Destroy fxSceneGraph2D.
if ( isObject(t2dSceneGraph) )
t2dSceneGraph.delete();
}
// --------------------------------------------------------------------
// Setup T2D Scene.
// --------------------------------------------------------------------
function setupT2DScene()
{
// Create fxSceneGraph2D.
new fxSceneGraph2D(t2dSceneGraph);
// Associate Scenegraph with Window.
sceneWindow2D.setSceneGraph( t2dSceneGraph );
// Set Camera Position to be centered on (0,0) with
// view width/height of (100/80).
sceneWindow2D.setCurrentCameraPosition( "0 0 100 75" );
// ************************************************************************
//
// Add your custom code here...
//
// ************************************************************************
// Set up the images for the game
SetupImages();
// Set up the player's stuff
CreatePlayer();
// Set up the enemy
CreateEnemy();
//setup background
CreateTileMap();
}
#6
07/15/2005 (6:28 pm)
function SetupImages()
{
// Create an image for the player ship
datablock fxImageMapDatablock2D(playershipImageMap)
{
mode = full;
textureName = "~/client/images/playerShip";
};
// Create an image for the player's missiles
datablock fxImageMapDatablock2D(playermissileImageMap)
{
mode = full;
textureName = "~/client/images/playerMissile";
};
// Create an image for enemy ships
datablock fxImageMapDatablock2D(enemyship1ImageMap)
{
mode = full;
textureName = "~/client/images/enemyship1";
};
// Create an image for the enemy's missiles
datablock fxImageMapDatablock2D(enemymissileImageMap)
{
mode = full;
textureName = "~/client/images/enemyMissile";
};
// Create images for the tilemap
datablock fxImageMapDatablock2D(bgBlankSkyImageMap)
{
mode = full;
textureName = "~/client/images/bg_blank_sky";
};
datablock fxImageMapDatablock2D(bgCloud1ImageMap)
{
mode = full;
textureName = "~/client/images/bg_cloud_1";
};
datablock fxImageMapDatablock2D(bgCloud2ImageMap)
{
mode = full;
textureName = "~/client/images/bg_cloud_2";
};
datablock fxImageMapDatablock2D(bgCloud3aImageMap)
{
mode = full;
textureName = "~/client/images/bg_cloud_3a";
};
datablock fxImageMapDatablock2D(bgCloud3bImageMap)
{
mode = full;
textureName = "~/client/images/bg_cloud_3b";
};
}
function CreatePlayer()
{
// Create the player's ship sprite
$player = new fxStaticSprite2D() { scenegraph = t2dSceneGraph; };
$player.setPosition("-35 0");
$player.setSize( "14 7" );
$player.setImageMap( playershipImageMap );
$player.setWorldLimit( clamp, "-49 -37 40 37" );
//setup link point
$player.fireLinkPoint = $player.addLinkPoint( "0.45 0.2" );
attachThruster( $player, "-0.12 -0.33", 0 ); //TorqueScript defined function
// Create a new action map.
new ActionMap(playerMap);
// Bind keys to actions.
playerMap.bindCmd(keyboard, "w", "playerUp();", "playerUpStop();");
playerMap.bindCmd(keyboard, "s", "playerDown();", "playerDownStop();");
playerMap.bindCmd(keyboard, "a", "playerLeft();", "playerLeftStop();");
playerMap.bindCmd(keyboard, "d", "playerRight();", "playerRightStop();");
playerMap.bindCmd(keyboard, "space", "playerFire();", "");
// Activate the action map.
playerMap.push();
// Set player's collision info:
$player.setGroup( 1 );
$player.setLayer( 1 );
$player.setCollisionActive( true, true );
$player.setCollisionMaterial( standardMaterial );
$player.setCollisionPolyCustom( 4, "-1 0 -0.1 -0.6 0.98 0.15 -0.1 0.7" );
$player.setCollisionMasks( BIT(2), BIT(2) );
$player.setCollisionCallback( true );
}
#7
07/15/2005 (6:30 pm)
function CreateEnemy()
{
// Create an enemy ship
%enemy = new fxStaticSprite2D() { scenegraph = t2dSceneGraph; };
%enemy.setImageMap( enemyship1ImageMap );
%enemy.setSize( "14 7" );
%enemy.setPosition("40" SPC (-30 + (getRandom() * 60))); //WAS: %enemy.setPosition("40 0");
// Move the enemy towards us.
%enemy.setLinearVelocityX(-20);
%enemy.setWorldLimit( kill, "-60 -40 60 40" );
attachThruster( %enemy, "0.8 -0.12", 180 );
attachThruster( %enemy, "0.8 0.18", 180 );
// Set enemy collision info
%enemy.setGroup( 2 );
%enemy.setLayer( 2 );
%enemy.setCollisionActive( true, true );
%enemy.setCollisionMaterial( standardMaterial );
%enemy.setCollisionPolyCustom( 5, "-0.9 0 0 -0.6 1 -0.3 1 0.3 0 0.5" );
%enemy.setCollisionMasks( BIT(1), BIT(1) );
%enemy.setCollisionCallback( true );
// Create an enemy missile and fire it
%enemyFire = new fxStaticSprite2D() { scenegraph = t2dSceneGraph; };
%enemyFire.setPosition( %enemy.getPosition() );
%enemyFire.setSize( "3 1.5" );
%enemyFire.setImageMap( enemymissileImageMap );
%enemyFire.setLinearVelocityX( -35 );
%enemyFire.setWorldLimit( kill, "-60 -40 60 40" );
// Set up collision info
%enemyFire.setGroup( 2 );
%enemyFire.setLayer( 2 );
%enemyFire.setCollisionActive( true, true );
%enemyFire.setCollisionMaterial( standardMaterial );
%enemyFire.setCollisionScale("0.9 0.5");
%enemyFire.setCollisionMasks( BIT(1), BIT(1) );
%enemyFire.setCollisionCallback( true );
schedule(2000, 0, "CreateEnemy"); //creates an enemy (since this is same function, will loop)
}
function playerFire()
{
// Create player projectile.
%projectile = new fxStaticSprite2D() { scenegraph = t2dSceneGraph; };
%projectile.setPosition( $player.getLinkPoint($player.fireLinkPoint) ); //WAS: %projectile.setPosition( $player.getPosition() );
%projectile.setSize( "3 1.5" );
%projectile.setImageMap( playermissileImageMap );
%projectile.setWorldLimit( kill, "-52 -40 52 40" );
%projectile.setLinearVelocityX( 35 );
// Setup collision info
%projectile.setGroup( 1 );
%projectile.setLayer( 1 );
%projectile.setCollisionActive(true, true);
%projectile.setCollisionMaterial(projectileMaterial);
%projectile.setCollisionScale("0.9 0.5");
%projectile.setCollisionMasks( BIT(2), BIT(2));
%projectile.setCollisionCallback( true );
}
function playerUp()
{
// Set the player moving up.
$player.setLinearVelocityY( -10 );
}
function playerUpStop()
{
// If we're moving up then nullify any upward movement.
if ( $player.getLinearVelocityY() < 0 )
$player.setLinearVelocityY( 0 );
}
function playerDown()
{
// Set the player moving down.
$player.setLinearVelocityY( 10 );
}
function playerDownStop()
{
// If we're moving down then nullify any downward movement.
if ( $player.getLinearVelocityY() > 0 )
$player.setLinearVelocityY( 0 );
}
function playerLeft()
{
// Set the player moving left.
$player.setLinearVelocityX( -10 );
}
function playerLeftStop()
{
// If we're moving left then nullify any leftward movement.
if ( $player.getLinearVelocityX() < 0 )
$player.setLinearVelocityX( 0 );
}
function playerRight()
{
// Set the player moving right.
$player.setLinearVelocityX( 10 );
}
function playerRightStop()
{
// If we're moving right then nullify any rightward movement.
if ( $player.getLinearVelocityX() > 0 )
$player.setLinearVelocityX( 0 );
}
function KillPlayer()
{
$player.setVisible( false );
playerMap.pop();
schedule(2000, 0, "ResetPlayer");
}
function ResetPlayer()
{
$player.setPosition("-35 0");
$player.setVisible(true);
playerMap.push();
}
function fxSceneObject2D::onCollision( %srcObj, %dstObj, %srcRef, %dstRef, %time, %normal, %contactCount, %contacts )
{
// Create an explosion for the collision that just occurred
createExplosion( %dstObj );
if (%srcObj == $player)
{
KillPlayer();
%dstObj.safeDelete();
}
else if (%dstObj == $player)
{
KillPlayer();
%srcObj.safeDelete();
}
else
{
%srcObj.safeDelete();
%dstObj.safeDelete();
}
}
#8
Steps to repro the problem
replace line 158 from:
I number of error messages also come up, I will look more into that and post in a bit.
07/15/2005 (6:30 pm)
function CreateTileMap()
{
// Create tile-map.
%scrollerMap = new fxTileMap2D() { scenegraph = t2dSceneGraph; };
// Load saved tile-map file.
%scrollerMap.loadTileMap("~/client/maps/scroller.map");
// Load tile layer from tile-map
%skyLayer = %scrollerMap.getTileLayer( 0 );
// Generate Scrolling Sky, re-size to fill the whole screen
%skyLayer.setPosition( "0 -10" );
%skyLayer.setTileSize( "25 25" );
%skyLayer.setWrap( true, true );
%skyLayer.setAutoPan( "10 0" );
}
function attachThruster(%mountObj, %mountPosition, %angle)
{
// Create Player Thruster.
%thruster = new fxParticleEffect2D() { scenegraph = t2dSceneGraph; };
%thruster.loadEffect("~/client/effects/smallThruster.eff");
%thruster.mount( %mountObj, %mountPosition, 0, false );
%thruster.setRotation( %angle );
%thruster.playEffect();
}
function createExplosion( %object )
{
// Ignore if object not around anymore.
if ( !isObject(%object) )
return;
// Shockwave Explosion.
%explosion = new fxParticleEffect2D() { scenegraph = t2dSceneGraph; };
%explosion.loadEffect("t2d/client/effects/shockwave_burst.eff");
%explosion.setPosition( %object.getPosition() );
%explosion.setEffectLifeMode( kill, 0.1 );
%explosion.playEffect();
}save the file, then run example/t2d.exe and make sure the player sprite respawns after being blown up.Steps to repro the problem
replace line 158 from:
$player = new fxStaticSprite2D() { scenegraph = t2dSceneGraph; };to:new fxStaticSprite2D(mySprite) { scenegraph = t2dSceneGraph; };
$player = mySprite;Now when the player sprite blows up, it will not respawn.I number of error messages also come up, I will look more into that and post in a bit.
#9
The real bug isnt what I initially stated, but rather an error in the implementation of the == mechanism.
This is manifested in the fxSceneObject2D()::onCollision script (found in the intro tutorial)
in here, there are a number of comparisons to delete the non-player objects that collide:
the problem is in the comparisons. for some reason, if you assign $player = mySprite; the if (%srcObj == $player) comparisons always evaluate to false. Meaning that the last else statement will always be executed, deleting both objects.
A workaround to this problem is to instead evaluate based on the object's .getId().
Example:
So knowing this, I feel a bit better about using the C++ code :) obviously I'm hitting the same issue.
Of course, I dont know exactly *why* assigning late is different, and why my C++ code (example #3 in my first post in this thread) doesnt work.. As for Example #3 I traced how the torquescript line $player = new fxStaticSprite2D(); actually gets executed by the C++ engine, and think I have it emulated perfectly except for that dang Stack push.
07/15/2005 (7:48 pm)
OK, i found out what the bug is, either tutorial bug, or engine bug. Take your pick :)The real bug isnt what I initially stated, but rather an error in the implementation of the == mechanism.
This is manifested in the fxSceneObject2D()::onCollision script (found in the intro tutorial)
in here, there are a number of comparisons to delete the non-player objects that collide:
if (%srcObj == $player)
{
KillPlayer();
%dstObj.safeDelete();
}
else if (%dstObj == $player)
{
KillPlayer();
%srcObj.safeDelete();
}
else
{
%srcObj.safeDelete();
%dstObj.safeDelete();
}the problem is in the comparisons. for some reason, if you assign $player = mySprite; the if (%srcObj == $player) comparisons always evaluate to false. Meaning that the last else statement will always be executed, deleting both objects.
A workaround to this problem is to instead evaluate based on the object's .getId().
Example:
if (%srcObj.getId() == $player.getId())
{
KillPlayer();
%dstObj.safeDelete();
}So knowing this, I feel a bit better about using the C++ code :) obviously I'm hitting the same issue.
Of course, I dont know exactly *why* assigning late is different, and why my C++ code (example #3 in my first post in this thread) doesnt work.. As for Example #3 I traced how the torquescript line $player = new fxStaticSprite2D(); actually gets executed by the C++ engine, and think I have it emulated perfectly except for that dang Stack push.
#10
I'll post back here when I have something.
- Melv.
07/16/2005 (1:22 am)
Hmm, I'll need to allocate some time to look into this in more detail as I'm just bogged-down at the moment but thanks for bringing up this potential problem.I'll post back here when I have something.
- Melv.
#11
07/16/2005 (1:52 am)
No problem. I'll just make the mental note of this in the meantime :) The workaround probably is good enough for my needs anyway.
Employee Melv May
Something's not quite right here. You two script examples both work and I've just gone and double-checked this. I added...
...into stock v1.0.2 T2D, function "setupT2DScene()" and then added...
... into "initialiseClient()" directly after the "setupT2DScene()" call and it outputs the same object IDs.
Something you probably already know is that if you use the second script then you don't need to reference the object in a global variable as you've already got a named one called "mySprite". You'd be better using...
So you just want to create T2D objects in C++, cool...
...becomes...
... and ...
...becomes...
When you've finished with the object you do this...
... or the nice helper which will do both (as well as perform some sanity checks for you)...
Hope this helps,
- Melv.