Game Development Community

Accessing sceneWindow2D (camera) from a behavior

by Jeremy Anderson · in Torque Game Builder · 04/11/2007 (7:45 am) · 12 replies

I've run into an interesting problem...that could be just a case of me banging my head on the wall in the wrong way:

I'm trying to get the camera coordinates (so I can make a behavior to handle offset and create parallax layers that obey camera movement). When attempting this from within a normal game script (say, game.cs for example) the following would work:

%testpos = sceneWindow2d.getCurrentCameraPosition();

Inserting that same code into a behavior throws the following error in console.log:

Unable to find object: 'sceneWindow2d' attempting to call function 'getCurrentCameraPosition'

I'm sure I must be missing something simple (been awake for too long to be really sharp). Anyone out there got any ideas?

#1
04/11/2007 (8:55 am)
Sure that the default window is called sceneWindow2d at all? :)
#2
04/11/2007 (2:18 pm)
Fairly sure...after all, the script worked from game.cs. I can't see any reason that the name of the default window would change from the time game.cs runs to the time that the behavior loads.
#3
04/11/2007 (2:26 pm)
Thats true, unless behaviors are loaded before anything else is executed.
#4
04/11/2007 (5:18 pm)
Are you putting the code in onBehaviorAdd or onLevelLoaded? I believe onBehaviorAdd may be called before the level is loaded.
#5
04/12/2007 (8:15 am)
Please post your behavior script :)
#6
04/12/2007 (9:56 pm)
I had the same issue trying to call sceneWindow2d.getMousePosition() from onBehaviorAdd (which turned out to not be necessary anyway), so perhaps Mr. Walters is onto something here.
#7
04/13/2007 (7:00 am)
Excelent news. Thanks to your help (Mark and Joseph, you had it...I needed to put the code in onLevelLoaded) I'm over the first big hurdle. Barring any unforseen issues, I should have the 1.0 version of the behavior finished by the end of the day. You guys are studs.
#8
04/13/2007 (8:00 pm)
Well, for those of you interested, I think I am getting awfully close on this one...once again I've run up against some quirky bugs that I'm bashing my head against, but at least I'm seeing some results.

Here's the basic idea: the code should watch the camera and make an X & Y vector of the camera's most recent change per tick. (So if the camera moved 10 units to the right, the value would be 10 on this tick.) At this point, it takes the percentage entered at the UI (100 for normal scroll, 200 for twice as fast, 0 for apparently stationary) and subtracts it from 100 (yeilding 0 for normal scroll, -100 for twice as fast, 100 for stationary). Then we just apply the result to the vector as a percentage (yielding 0 pixels for a normal scroll, -10 pixels effectively doubling scroll speed, and 10 pixels making a stationary scroll).

While it sounds good on paper, it still isn't working right. (Currently the effect is jittery and the compensation doesn't seem to be going properly.) If anyone wants to play with it, here's the source:

if (!isObject(ParallaxObjectBehavior))
{
   %template = new BehaviorTemplate(ParallaxObjectBehavior);
   
   %template.friendlyName = "Parallax Object";
   %template.behaviorType = "Effects";
   %template.description  = "Changes object position based on camera movement.";

   %template.addBehaviorField(xSpeed, "Percentage of horizontal scroll speed", float, 100);
   %template.addBehaviorField(ySpeed, "Percentage of vertical scroll speed", float, 100);
}

function ParallaxObjectBehavior::onBehaviorAdd(%this)
{
	%this.owner.enableUpdateCallback();
}

function ParallaxObjectBehavior::onLevelLoaded(%scenegraph)
{

	%currPos = sceneWindow2d.getCurrentCameraPosition();
	%oldPosX = getWord(%currPos, 0);
	%oldPosY = getWord(%currPos, 1);

}

function ParallaxObjectBehavior::onUpdate(%this)
{
	%currPos = sceneWindow2d.getCurrentCameraPosition();
	%currPosX = getWord(%currPos, 0);
	%currPosY = getWord(%currPos, 1);
	%VectorX = ((%currPosX - %oldPosX)/100)*(100 - xSpeed);
	%VectorY = ((%currPosY - %oldPosY)/100)*(100 - ySpeed);
	%this.owner.setPositionX(%VectorX++);
	%this.owner.setPositionY(%VectorY++);
	%oldPosX = %currPosX;
	%oldPosY = %currPosY;
}

This boy is going to bed. Talk to ya'll later.
#9
04/14/2007 (7:57 am)
I would imagine that it is a bit jittery. I think the basic problem is using the behavior::onUpdate.
A behaviors update gets called at fixed intervals of 32ms. The equates to 31.25 fps. That would create noticable jitter in movement

You may want to look at a different way to interpolate the object movement. Try using the objects moveto method to create a smoother transition to the new position. If your camera has a lot of movement this method will give you odd patterns of movement in your object as the object continually updates its direction trying to catch up to the camera.

I would say play around with the different methods and see if you can find an interpolate method that works for you.

Also your onLevelLoaded method doesn't do anything. You set some local variables, but they will be destroyed as soon as the function ends. If you are trying to save the old position, you need to either store in a tagged field in the behavior object or in a global var. Looking harder at the code, %oldpos is always going to be 0 because the var is being recreated everytime onUpdate is called.


Food for thought - Hope it helps
#10
04/14/2007 (8:50 am)
What you probably want is %this.oldPos... (no need to define fields or anything like that).
#11
04/14/2007 (6:04 pm)
Great news! The behavior is done...I'm posting it to TDN tonight. I managed to fix my variable issues (you can tell I've been working actionscript the last few months...I couldn't remember which were locals, globals, etc.). Next up I need to implement some smothing such as Guy mentioned. (The jittering isn't terrible on smaller objects, but it gets ugly on larger ones.)

If you're still interested, here's how the final code sits:

if (!isObject(ParallaxObjectBehavior))
{
   %template = new BehaviorTemplate(ParallaxObjectBehavior);
   
   %template.friendlyName = "Parallax Object";
   %template.behaviorType = "Effects";
   %template.description  = "Changes object position based on camera movement.";

   %template.addBehaviorField(xSpeed, "Percentage of horizontal scroll speed", float, 100);
   %template.addBehaviorField(ySpeed, "Percentage of vertical scroll speed", float, 100);
}

function ParallaxObjectBehavior::onBehaviorAdd(%this)
{
	%this.owner.enableUpdateCallback();
}

function ParallaxObjectBehavior::onLevelLoaded(%scenegraph)
{

	%currPos = sceneWindow2d.getCurrentCameraPosition();
	%this.oldPosX = getWord(%currPos, 0);
	%this.oldPosY = getWord(%currPos, 1);

}

function ParallaxObjectBehavior::onUpdate(%this)
{
	%currPos = sceneWindow2d.getCurrentCameraPosition();
	%this.currPosX = getWord(%currPos, 0);
	%this.currPosY = getWord(%currPos, 1);
	%VectorX = ((%this.currPosX - %this.oldPosX)/100)*(100 - %this.xSpeed);
	%VectorY = ((%this.currPosY - %this.oldPosY)/100)*(100 - %this.ySpeed);
	%objPosX = %this.owner.getPositionX();
	%objPosY = %this.owner.getPositionY();
	echo (%VectorX);
	%this.owner.setPositionX((%VectorX + %objPosX));
	%this.owner.setPositionY((%VectorY + %objPosY));
	%this.oldPosX = %this.currPosX;
	%this.oldPosY = %this.currPosY;
}

Thanks again for all your help. I was feeling kinda sheepish chiming in with my "I'm sure this is going to look like I'm an idiot" problems.
#12
04/19/2007 (7:51 am)
For those still interested, I've fixed the flickering issue addressed by Guy in his earlier post. The finished behavior is up on TDN.

Cheers!