Game Development Community

Schedule not working!

by FruitBatInShades · in Technical Issues · 02/23/2005 (9:00 am) · 21 replies

NEWB ALERT!

I'm trying to get exploding glass. I have 2 models, one that has the animated explosion (Glass2) and one that is the glass after it has been exploded. I cannot get schedule to work to remove the sound or swap the datablock. If I swap the datablock directly in Glass2::damage, then the object swaps but the animation is never played. So i tried to use the schedule function to do this after the animation has finished but the SwapBlock function is never called.
The audioemitter is never destroyed either :(

Any pointers for a newb :)

datablock StaticShapeData(Glass2)
{
   category = "DamageItems";
   shapeFile = "~/data/shapes/glass2.dts";

   maxDamage = 1;
   destroyedLevel = 1;
};
datablock StaticShapeData(Glass3)
{
   category = "DamageItems";
   shapeFile = "~/data/shapes/glass3.dts";
};
function Glass2::create(%block)
{
   %obj = new StaticShape()
   {
      dataBlock = %block;
   };
   return(%obj);
}

function Glass2::onCollision(%this,%obj,%collider)
{
	echo("Glass2 collision");
}

function Glass2::damage(%this, %obj, %sourceObject, %position, %damage, %damageType)
{
   echo("GlassTube::damage() obj=" @ %obj @ ", source=" @ %sourceObject @ ", damage=" @ %damage);
   %obj.applyDamage("1");
   %obj.playThread(0,"ambient");
   %smashsound = new AudioEmitter() 
         {
            position = %obj.position;
            fileName = "~/data/sound/smash.ogg";
            description = AudioClose3d;  //for loud sound
         };
      //This schedules the audio emitter to delete itself when done playing the sound.
      //If you use a longer sound, change the value of 1000 to a length of time long enough
      //to finish your sound before deleting the emitter.
        %this.schedule(1000,"KillSound",%smashsound);
}

function Glass2::onDamage(%this, %obj, %delta)
{
   echo("GlassTube::onDamage() obj=" @ %obj @ ",delta=" @ %delta);
   %this.schedule(500,"SwapBlock",Glass3);
}

function SwapBlock(%this, %block)
{
	echo("Swapblock called");
	%this.setDataBlock(%block);
}
Page «Previous 1 2
#1
02/23/2005 (9:40 am)
It appears that you are being quite loose with your objects that are being sent back and forth between your variables:

in Glass2::onDamage, you are using %this.schedule, which is calling schedule on the datablock. in functionSwapblock, you are receiving a %this parameter, which I am pretty sure is also the datablock (from the schedule), but then trying to set the datablock of a datablock (%this.setDataBlock, where %this is already a datablock).

Try changing the schedule line in Glass2::onDamage() to:

%obj.schedule(500,"SwapBlock", Glass3);
and see if that helps.

Also, you are doing the same thing (confusing datablock with object) in your Glass2::damage() function. Instead of using %this in that schedule, try %obj instead.
#2
02/23/2005 (10:36 am)
Hi Stephen.

That doesn't woprk either. What object actually contains the schedule function? No errors are reported, but nothing ever happens! Is part of GameBaseData?
#3
02/23/2005 (10:47 am)
You are also using namespace schedules which may not be properly handled. For instance, you would need to alter this schedule...

%this.schedule(1000,"KillSound",%smashsound);

to this...

%obj.schedule(1000,"KillSound",%smashsound);


And then you would need this function to handle it....

function Glass2::killSound(%obj, %smashsound)
{

}
#4
02/23/2005 (3:09 pm)
Bat,

to get your existing schedule call to work, make your SwapBlock function belong to the datablock

function Glass2::SwapBlock(%this, %block)
{
...
}

------------------------------------------------------------------------------------------------------------
or, conversely, leave the function alone and use the general script function call for schedule (in onDamage):

schedule(500,0,"SwapBlock",%obj, Glass3);


Either one of those two approaches should work.
-----------------------------------------------------------------------------------------

Also, I don't see your KillSound method anywhere? it should be defined somewhere as belonging to the datablock since you are accessing it via the datablock:

function Glass2::KillSound(%this, %sound)
{
...
}
#5
02/23/2005 (3:38 pm)
Thanks guys. How do I dispose of an object like the sound, I don;t want to just add it to mission cleanup cos theres a lot going on. How do I dispose of it properly?
#6
02/23/2005 (5:16 pm)
I've tried those changes and now I get a full crash! Where am I going wrong? Its the call to SwapBlock thats crashing!
echo("scheduling killsound");
        schedule(100,0,"KillSound",%smashsound);
        echo("scheduling Swapblock");
        schedule(500,0,"SwapBlock",%obj, Glass3);

function SwapBlock(%this, %block)
{
	echo("Swapblock called");
	%this.setDataBlock(%block);
}

function KillSound(%this, %soundtokill)
{
	echo("KillSound Called");
	%soundtokill.delete();
}

[b]Console.log[/b]
scheduling killsound
scheduling Swapblock
GlassTube::damage() obj=1473, source=1506, damage=3.03052
scheduling killsound
scheduling Swapblock
KillSound Called
starter.fps/server/scripts/Glass.cs (0): Unable to find object: '' attempting to call function 'delete'
KillSound Called
starter.fps/server/scripts/Glass.cs (0): Unable to find object: '' attempting to call function 'delete'

It seems that event is fired recursively! Is there a way to specify it should fire only once?
#7
02/23/2005 (5:30 pm)
Kill Sound will continue to get called until you cancel the schedule.

Do this:
%smashsound.scheduleId = schedule( 100, 0, "KillSound", %smashsound );
...
function KillSound( %soundtokill )
{
   echo( "KillSound Called" );
   cancel( %soundtokill.scheduleId );
   %soundtokill.delete();
}
It wasn't working the first time, because the schedule was putting %smashsound in the place of %this, and you were never canceling the schedule.
#8
02/23/2005 (5:31 pm)
Looks like you are missing a closing brace after your call to schedule(500,0,"SwapBlock",%obj, "Glass3");
#9
02/23/2005 (5:32 pm)
Oh yeah, and what Pat said too
:-)
#10
02/23/2005 (5:39 pm)
That was just a cut and paste extract :)

@Pat: Thanks :)

But if you look at the console dump above, %obj never gets passed or is out of scope when KillSound is called. Also Swapblock still crashes the engine :( When schedule is called %smashsound has an id, when KillSound is actually called 0 is passed as the ID!
#11
02/23/2005 (6:04 pm)
Fruit

Take a closer look, you are passing the variable to "%this" and Pat has altered the function to only use "%soundtoKill". You were trying to delete a variable that didn't exist.
#12
02/23/2005 (8:57 pm)
@Fruit
The sound should play 1 sec what i understand , why dont you use
%obj.playaudio(0,audiodescription) ?

And for the rest why not this

function Glass2::onDamage(%this, %obj, %delta)
{
schedule(500,0,"SwapBlock",%obj);
}

function SwapBlock(%obj)
{
%obj.setDataBlock(glass3);

}
#13
02/23/2005 (9:09 pm)
Because this...

%obj.setDataBlock(glass3);

hardwires ONE possibility only where his method offers virtually unlimited possibilities.
#14
02/23/2005 (9:12 pm)
Got it :)
But still depends on what he are after .
What i understand this swapblock is not somekind of global swap function.
#15
02/23/2005 (9:28 pm)
Hopefully this will clear up some confusion...

function SomeObject::someMethod( %this, %foo )
{
...
}

To call a schedule with parameters
// Schedule someMethod to be executed on an instance of SomeObject
%obj = new SomeObject();
%obj.schedule( 100, "someFunction", "foo argument" );

// Is the same as
schedule( 100, %obj, "someFunction", "foo argument" );

// Is the same as
schedule( 100, 0, "SomeObject::someFunction", %obj, "foo argument" );

In each of these examples, when the schedule fires, the parameters in the call to 'someFunction' will be:
%this = Sim Object Id of the SomeObject created
%foo = "foo argument"

Unfortunatly TorqueScript does not, currently, have a concept of 'this' so that is the reason for the semi-hacked way of passing a reference to the current object in a script method. This will not always be the case, but for now that's the way it works.
#16
02/23/2005 (9:43 pm)
Great Pat !
This cleared out some question marks in my head :)
Im not a coding guy so i really need clear examples like this.

Most of the time the problem is, so many good really skilled coders
give differnt approaches to the same problem.
Instead of giving a clear solution at once.
And the less skilled coders/semihackers like me comes and mess things up :)
#17
02/24/2005 (3:02 am)
ARGGHHHHH. Still no swapblock calls, although no crash either ;)

@Pat: Thanks Pat, I was looking throught the docs but couldn't find any info on schedule other than the doxygen stuff which is useless on that function.

@Billy: I want to use the SwapBlock for a lot of stuff. We are using a lot of models that we WANT to swap at avrious points in their lifecycle. So having SwapBlock as a global function is what we're after. Same with killsound.

@everyone

I cannot get the swapBlock function to be called. It schedules, but never executes and no error message doesn't help me track down the problem :( Does anyone have any more ideas?

Swapblock is never called :(
GlassTube::damage() obj=1473, source=1506, damage=10
GlassTube::onDamage() obj=1473,delta=1.000000
breaking glass
scheduling killsound for item 1512
scheduling Swapblock for item 1473
GlassTube::damage() obj=1473, source=1506, damage=1.90956

//DTS with animation and collision
datablock StaticShapeData(Glass2)
{
   category = "DamageItems";
   shapeFile = "~/data/shapes/glass2.dts";

   maxDamage = 1;
   destroyedLevel = 1;
   isBroken = false;
};

//DTS with no collision (after its broken)
datablock StaticShapeData(Glass3)
{
   category = "DamageItems";
   shapeFile = "~/data/shapes/glass3.dts";
};

//Functions to handle Glass2 operations
function Glass2::create(%block)
{
   %obj = new StaticShape()
   {
      dataBlock = %block;
   };
   return(%obj);
}

function Glass2::onCollision(%this,%obj,%collider)
{
	echo("Glass2 collision");
}

function Glass2::damage(%this, %obj, %sourceObject, %position, %damage, %damageType)
{
   echo("GlassTube::damage() obj=" @ %obj @ ", source=" @ %sourceObject @ ", damage=" @ %damage);
	//Apply damage and play smashing animation
	%obj.applyDamage("1");
	%obj.playThread(0,"ambient");
	//only break glass if it isn't already broken
	if (!%obj.isBroken)
    {
		echo("breaking glass");
		//Set the broken flag
		%obj.isBroken = true;
		//create and play the smash sound
		%smashsound = new AudioEmitter() 
         {
            position = %obj.position;
            fileName = "~/data/sound/smash.ogg";
            description = AudioClose3d;  //for loud sound
         };
		//This schedules the audio emitter to delete itself when done playing the sound.
		//If you use a longer sound, change the value of 1000 to a length of time long enough
		//to finish your sound before deleting the emitter.
		echo("scheduling killsound for item" SPC %smashsound);
        schedule(1000,0,"KillSound",%smashsound);
        
        //Swap the DTS with the collision and animation for the
        //DTS with no collision and no animation.
        echo("scheduling Swapblock for item" SPC %obj);
        schedule(1200,"SwapBlock",%obj, Glass3);
    }   
}

function Glass2::onDamage(%this, %obj, %delta)
{
   echo("GlassTube::onDamage() obj=" @ %obj @ ",delta=" @ %delta);
}

//Swap one dtatblock for another so we can use different
//shapes at different points in the objects lifetime.
function SwapBlock(%this, %block)
{
	echo("Swapblock called");
	%this.setDataBlock(%block);
}

function KillSound(%soundtokill)
{
	//Stop the schedule reoccuring
	cancel( %soundtokill.scheduleId );
	//remove sound from mission
	%soundtokill.delete();
}
#18
02/24/2005 (5:30 am)
First off, I don't see any indication of a "Glass3::create(%block)" function to even make the block. Second, I think you would be better off using...


function StaticShapeData::create(%data)
{
   // The mission editor invokes this method when it wants to create
   // an object of the given datablock type.

	%obj = new StaticShape()
	{
		dataBlock = %data;
	};
	return %obj;
}

and sending "Glass2" and "Glass3" to that to have their blocks created.

When you try to swap a block, if the block doesn't exist, it pretty much does nothing to stay fault tolerant. Check and see if that helps.
#19
02/24/2005 (10:02 am)
You are still missing the purpose of %this. If you have a method (class member function) in script, you need to use the following format for the function declaration:
function SomeObject::someMethod( %this, %arg1, %arg2, etc... )

and when you call it you do:
%someInstanceOfSomeObject.someMethod( "arg1", "arg2", etc... );

And that will translate to this:
SomeObject::someMethod( %someInstanceOfSomeObject, "arg1", "arg2", etc... );

Things may not be working right, because when this method is called:
Glass2::create(%block)

The object ID for a Glass2 object is going to be put into %block.
#20
02/24/2005 (10:21 pm)
Here is my code to do the same thing--a different way to do it. You just need to stuff your own particle emitters in (or not):
datablock StaticShapeData(WindowA)
{
   category    = "windows";
   shapeFile    = "~/data/shapes/splody/window1.dts";
   damageRadius     = 10;
   radiusDamage   = 50;
   damageType   = WindowAdebris;
   maxDamage      = 5;
};

datablock StaticShapeData(Shards)
{
   category    = "windows";
   shapeFile    = "~/data/shapes/splody/shards.dts";
};

function WindowA::Damage(%theDatablock,%aWindow,%sourceObject,%pos,%damage,%damagetype)
{
	%aWindow.applyDamage(%damage);
	if(%aWindow.getDamageLevel() >= %theDatablock.maxDamage)
		%theDatablock.Shatter( %aWindow, %pos, %sourceObject);
}


function WindowA::Shatter(%theDatablock, %aWindow, %position, %sourceObject)
{
 if(%aWindow.exploded)
     return;
 %aWindow.exploded = true;
 %smash= new Explosion()
 {
   datablock = GlassShatter;
   position  = %position;
 };
 MissionCleanup.add(%smash);
 radiusDamage(%aWindow,%position,%theDatablock.damageRadius,
 %theDatablock.radiusDamage,%sourceObject.damageType,%theDatablock.damageImpulse);
 %aWindow.schedule(500, "delete");

 %slivers = new StaticShape()
 {
    datablock = Shards;
    position  = %position;
 };
 MissionCleanup.add(%slivers);
}

This works well, even without the Explosion emitters.
Page «Previous 1 2