controllable orbit question
by Levi Walton · in Torque Game Builder · 02/04/2010 (6:32 pm) · 25 replies
I would like to make an object orbit around another, being able to adjust the direction of the orbit and even the radius at times. I've searched and havent really found anything terribly useful. I thought it would involve polar coordinates being converted to cartesian, but in some of my searching it said that tgb doesnt use cart coordinates, i had some sucess with that, but the problems i had might be due to this. i have also noticed several torque scripts with references to "polar", such as setPolarVelocity etc. are these the commands i should be looking at? any and all info would be appreciated. thanks
#2
this is the equivalent of
Changing direction is just changing the angle and you can modify the radius by changing it to a "%this.radius" and modifying it in the onUpdate, too.
02/04/2010 (11:53 pm)
Can't you just do something in an onUpdate like%this.currentAngle += 1.0; // Or whatever %center = %targetObj.getPosition(); // You'll need to change this %radius = 100; // and this, too. %vector = mCos( %this.currentAngle ) SPC mSin( %this.currentAngle ); %vector = t2dVectorScale( %vector, %radius ); %vector = t2dVectorAdd( %vector, %center );
this is the equivalent of
f(angle, center) = radius * <cos(angle), sin(angle)> + center;
Changing direction is just changing the angle and you can modify the radius by changing it to a "%this.radius" and modifying it in the onUpdate, too.
#3
02/05/2010 (11:41 am)
forgive me, I'm still learning, i dont guess i quite understand, i thought it made sense, but i tried to implement and it doesnt seem to work (im sure its error on my part). would it be possible to give a little more explanation? meanwhile ill continue to study it. thanks again.
#4
Imagine that you added 2 objects in the TGB editor and named them "Moon" and "Planet". Then, you might add to your scripts something like the following:
Note: I didn't actually try this, so there might be an error. But it's a good place to start.
02/05/2010 (4:27 pm)
No problem.Imagine that you added 2 objects in the TGB editor and named them "Moon" and "Planet". Then, you might add to your scripts something like the following:
function Moon::onLevelLoaded( %this, %scene )
{
%this.enableUpdateCallback();
%this.currentAngle = 0.0;
%this.radius = 100.0;
}
function Moon::onUpdate( %this )
{
%this.currentAngle += 1.0; // Or whatever
%center = Planet.getPosition();
%vector = mCos( %this.currentAngle ) SPC mSin( %this.currentAngle );
%vector = t2dVectorScale( %vector, %this.radius );
%vector = t2dVectorAdd( %vector, %center );
%this.setPosition( %vector );
}Note: I didn't actually try this, so there might be an error. But it's a good place to start.
#5
02/05/2010 (4:34 pm)
thanks, i really appreciate. im going to look over this and try and it out.
#6
02/08/2010 (10:13 am)
I did a quick test of this William, nice bit of code!
#7
02/08/2010 (10:51 am)
Didn't Conor O'Kane do something like this in Go Beryllium? Maybe the script source helps.
#8
02/08/2010 (12:06 pm)
agreed, i tried out the code and it works great. but like i said im a bit new so im going to study it and then try and implement player controls. thank you so much. Stefan thanks for pointing that out, im going to check that out too. thanks for all the help guys.
#9
(P.S. Thanks, Patrick!)
02/08/2010 (6:54 pm)
I think in Go Beryllium (which was implemented very nicely), Conor O'Kane used rotating mounts. To my knowledge, I don't think you can change the radius when you do that.(P.S. Thanks, Patrick!)
#10
It's basically just...
...where $attractor is the big heavy thing %this is orbiting and $gravityConstant is whatever number makes the whole thing look good.
Unlike real gravity, this ignores the distance between the objects, their masses and any other objects, but surprisingly, it looks quite good anyway!
I usually call it in an onTimer() callback every 50 or 100ms depending on how smooth I need the motion.
On the plus side, this creates very smooth, natural looking motion and it's not too computationally expensive. On the down side though, you have very little control over the whole situation. All you can do is slow the object down or speed it up to decrease or increase its orbital radius at the opposite end of its oribt, and if it gets into a crazy elliptical orbit there's not a lot you can do about it without very careful adjustments.
Feel free to send me any questions you have on the source.
p.s. I highly recommend you play the game Osmos if you want to get an intuitive understanding of how to manipulate an orbit without the need for any mathematics.
02/09/2010 (9:20 am)
Indeed I used rotating mounts for the electrons orbiting the atoms, as their radius never changes, although you could change their radius by smoothly scaling the mount target. However for the enemy atoms orbiting 'attractor points' and the seeking boson bullets I used a pseudo-gravitational force to create their orbits.It's basically just...
%gravity = t2dVectorScale(t2dVectorNormalise(t2dVectorSub($attractor.getPosition(), %this.getPosition())), $gravityConstant); %this.setLinearVelocity(t2dVectorAdd(%this.getLinearVelocity(), %gravity)));
...where $attractor is the big heavy thing %this is orbiting and $gravityConstant is whatever number makes the whole thing look good.
Unlike real gravity, this ignores the distance between the objects, their masses and any other objects, but surprisingly, it looks quite good anyway!
I usually call it in an onTimer() callback every 50 or 100ms depending on how smooth I need the motion.
On the plus side, this creates very smooth, natural looking motion and it's not too computationally expensive. On the down side though, you have very little control over the whole situation. All you can do is slow the object down or speed it up to decrease or increase its orbital radius at the opposite end of its oribt, and if it gets into a crazy elliptical orbit there's not a lot you can do about it without very careful adjustments.
Feel free to send me any questions you have on the source.
p.s. I highly recommend you play the game Osmos if you want to get an intuitive understanding of how to manipulate an orbit without the need for any mathematics.
#11
02/09/2010 (4:00 pm)
Just wanted to say thanks for everything so far, its really helping me out. but now im trying to implement player controls to controll the moon object. im setting it up like in the shooter tutorial, i set the keybinds with moonleft/right functions, basically sayin if the left or right key is press its left or right is true ( except i do not add the updateMovement function call). then in the onUpdate function, instead of %this.currentAngle += 1.0, i put if (%this.moveLeft){%this.currentAngle += 1.0} . but there is no orbiting and the keys dont respond. am i implementing controls wrong? any thoughts. thanks again guys.
#12
02/09/2010 (5:35 pm)
Make sure you are setting "Moon.moveLeft" to true. If you're doing that, I'd probably need to see a little more code to note what might be going wrong.
#13
02/09/2010 (5:57 pm)
forgive me if i didnt post this correctly, but here is what im working with.function Moon::onLevelLoaded( %this, %scene )
{
%this.enableUpdateCallback();
%this.currentAngle = 0.0;
%this.radius = 10.0;
moveMap.bindCmd(keyboard,"left", "moonLeft();", "moonLeftStop();");
moveMap.bindCmd(keyboard,"right", "moonRight();", "moonRightStop();");
}
function moonLeft()
{
%this.moveLeft = true;
}
function moonLeftStop()
{
%this.moveLeft = false;
}
function moonRight()
{
%this.moveRight = true;
}
function moonRightStop()
{
%this.moveRight = false;
}
function Moon::onUpdate( %this )
{
if (%this.moveRight) {
%this.currentAngle += 0.3; // Or whatever
}
if (%this.moveLeft) {
%this.currentAngle -= 0.3; // Or whatever
}
%center = Planet.getPosition();
%vector = mCos( %this.currentAngle ) SPC mSin( %this.currentAngle );
%vector = t2dVectorScale( %vector, %this.radius );
%vector = t2dVectorAdd( %vector, %center );
%this.setPosition( %vector );
}
#14
2 ways to fix this:
You could name the moon "moon1" in the editor and then use functions like this...
or make your move function a method on the moon class like this...
In the onLevelLoaded function change the bindCmds to:
and then change the move functions to:
Also, you need to add some error checking to your input code. What will happen if the player presses right, and left at the same time?
Read player.cs in the Go Beryllium source to see a complete movement system for keyboard and joystick.
02/09/2010 (10:16 pm)
The function moonLeft() is not a method on the moon class, so there's no %this in the header. %this has no meaning in such a function.2 ways to fix this:
You could name the moon "moon1" in the editor and then use functions like this...
function moonRightStop() { moon1.moveRight = false; }or make your move function a method on the moon class like this...
In the onLevelLoaded function change the bindCmds to:
moveMap.bindCmd(keyboard,"left", "moon1.moveLeft(true);", "moon1.moveLeft(false);");
and then change the move functions to:
function moon.moveLeft(%this, %state) { %this.moveLeft = %state; }Also, you need to add some error checking to your input code. What will happen if the player presses right, and left at the same time?
Read player.cs in the Go Beryllium source to see a complete movement system for keyboard and joystick.
#15
02/09/2010 (11:08 pm)
ok i think i see what your saying, i was basically calling a function on nothing right? or did i misunderstand? i will surely check out the source for go beryllium, i have a feeling it will help me out a lot. and i actually did have some lines checking if both were pressed but i took it out for trying for a bit of brevity, but in hind sight that i shouldve left it. thanks for the help, this one forum post has be very educational for me.
#16
In any case, I think it is cleaner to use ActionMap::bindObj(...):
and then
02/10/2010 (12:21 am)
You were calling a valid function, but the function was not defined as part of the Moon class (or namespace, or whatever they are called in torquescript :) ), and when it the function was called it was not attached to a particular instance or object type.In any case, I think it is cleaner to use ActionMap::bindObj(...):
moveMap.bindObj(keyboard, "left", "moveLeft(true)", %this);
and then
function moon::moveLeft(%this, %state){
%this.moveLeft = %state;
}
#17
but im having trouble with the angle, i have tried
looking in the console it said something about returning it in radians, does it need to be converted to degrees somehow? or is my logic wrong?
02/10/2010 (3:41 pm)
man you guys are johnny on the spot with knowledge, and i really hate to overstay my welcome here but i have another question. im trying to get the the angle and the radius set to whatever position i locate them in the editor. i have the radius working:%this.radius = t2dVectorDistance(Planet.getPosition(), moon1.getPosition());
but im having trouble with the angle, i have tried
%this.currentAngle = mAtan(moon1.getPositionY()/moon1.getPositionX());
looking in the console it said something about returning it in radians, does it need to be converted to degrees somehow? or is my logic wrong?
#18
That being said, you should beware that mAtan(moon1.getPositionY()/moon1.getPositionX()) is not guaranteed to return the angle that the moon is at. If x is 0 you get a divide by zero (so you need to test first and set the angle to +pi/2 or -pi/2 depending on the value of y), and if x<0 then the angle returned will be exactly diametrically opposed to the one you after (so you need to add or subtract pi).
A lot of programming languages have a convenience function (atan2) which takes the X and Y coordinates separately and is guaranteed to give you the angle no matter what quadrant the moon lies in - I'm not sure if torquescript has that function or not but you could check.
02/10/2010 (5:27 pm)
atan does in fact return an angle in radians, though I'm surprised the console said anything about it. I believe there is a builtin command to convert back but it's easy enough to x=x*180/3.141582.That being said, you should beware that mAtan(moon1.getPositionY()/moon1.getPositionX()) is not guaranteed to return the angle that the moon is at. If x is 0 you get a divide by zero (so you need to test first and set the angle to +pi/2 or -pi/2 depending on the value of y), and if x<0 then the angle returned will be exactly diametrically opposed to the one you after (so you need to add or subtract pi).
A lot of programming languages have a convenience function (atan2) which takes the X and Y coordinates separately and is guaranteed to give you the angle no matter what quadrant the moon lies in - I'm not sure if torquescript has that function or not but you could check.
#19
02/10/2010 (5:31 pm)
There's a better function called t2dAngleToPoint. Call it with your Planet's position first, then the Moon's position.
#20
i tried
but that still returns an angle of 0.0. ive tried several things but all seem to be putting the angle at 0.0 no matter what i do.
02/11/2010 (2:21 pm)
i actually used t2dAngleToPoint to get the moon to point to the planet as it orbits, but i cant seem to get it to set the %this.currentAngle according to the editor.i tried
%this.currentAngle = t2dAngleToPoint(Planet.getPosition(), moon1.getPosition());
but that still returns an angle of 0.0. ive tried several things but all seem to be putting the angle at 0.0 no matter what i do.
Torque Owner David Helmer
The Kids