# Follow a curve using physics or transform manipulation

 0 I'm in the early stages of a new game, and need help developing the movement. The problem boils down to this: Imagine a donut shaped tunnel (i.e. a cyclotron/torus), with objects that move('float') within the lumen of tunnel. I'd like those objects to continuously circle around the tunnel. I can simuluate the motion using splining, but there will be many objects flying around, and I like them to float through the tunnel more randomly/realistically, using either physics or direct manipulation of the transforms. I've tried just using physics, and applying a forward force, but eventually the object just ends up sliding along the outer wall of the tunnel (see this link http://www.orgoquest.com/unitytest/temp.html ). My latest idea was to have the object move forward along it's z-axis, do a raycast to the right from the object to the outer wall, get the normal of that hit point, and rotate the object so that it's z axis is directed 90 degrees to the normal, and then move forward along the z-axis. In my mind, this would cause the object to move around the curve at a constant distance from the outer wall, but it's not working. Maybe because I'm doing something wrong with the vector math. I was hoping someone could point me in the right direction to try to accomplish this, either using the idea above, or anything else out there. Thanks. Edit: Although I'm using a torus now, in the future the shape will be a tunnel of arbitrary direction, not necessarily in a circle. The way the cells move in this video http://www.youtube.com/watch?v=tKgroDE4DHo&feature=player_embedded at the 46-49 second mark is what I'm trying to recreate. more ▼ asked Sep 15 '10 at 06:05 PM unityRookie 56 ● 4 ● 4 ● 9 add new comment (comments are locked) 10|3000 characters needed characters left ▼ Viewable by all users

# Moving inside a torus

I never took Bio, so while I correctly assumed the meaning of lumen in this context, I had to look it up to be sure.

Because the shape is constant, we can make some assumptions and do some simple calculations to make this work because we're just moving in a circle.

## Without physics

The simple solution is to center the pivot of motion at the center of the torus with the object positioned inside the tunnel and then just rotate. This can be done with some simple parenting and rotating the parent, changing the pivot itself or just getting the center of the torus which is quite easy especially if the parent is the torus.

``````//assuming the parent is at the center of the torus
transform.RotateAround(transform.parent.position, transform.parent.up, Time.deltaTime*speed);
``````

## With physics

To fly in a circle with forces is a pain. You must constantly apply a relative force in the direction that you are turning, so you have to keep track of this direction. Something like turning the object with torque, using drag, no gravity and no angular drag:

``````function Start() {
}

function FixedUpdate() {
}
``````

The problem is that you can't really control the circle terribly well and if you get moved off your center, it becomes trying to get it back under control.

As an alternative, you could also apply a sort of "gravity" towards the center of the torus as well, to keep the object's rotation under control, but this becomes a bit harder to maintain as a circle.

``````//With no drag, this should give you a circle
//With drag, you have to add force every update to move forward
function Start() {
}

function FixedUpdate() {
}
``````

Using a kinematic rigidBody, you could just do something like the orbit camera script where you rotate the object and translate along an axis.

``````var distance : float = 10.0;
var angle : float = 0.0;
function FixedUpdate() {
angle += Time.deltaTime*speed;
while(angle >= 360) angle-= 360; //wrap around
while(angle < 0) angle += 360; //wrap the other way

//Rotate around the parent's up axis
var rotation = Quaternion.AngleAxis(angle, transform.parent.up);
var position = rotation * Vector3(distance, 0.0, 0.0) + transform.parent.position;

rigidbody.MoveRotation(rotation);
rigidbody.MovePosition(position);
}
``````

# Random movement

In the natural world, there is nothing truly random, but the motion in a system that we would perceive as "random" is a product of a reasonably undetermined start motion/position + well tuned forces and adjustments. Between the complexities of force occlusion, surface interaction and pressure systems for multiple objects in even a stable medium, it's rather challenging to calculate the reality of how objects would react, so in general randomness as well as physics systems provide approximations.

Believable randomness can be a pain to create. One of the best solutions I've seen was to sample random noise (see this Unite presentation). There are too many ways to do randomness to mention, but the important part is not to directly assign random values to positions unless you know that they will smoothly interpolate. I also recommend taking a look at some of the flocking scripts as they provide some useful information on following a direction, but doing so less strictly.

Assuming you're rotated into position (which you can control by a random speed too if you wanted), you only have two axes left to worry about for random motion along the axes extending from the center and to the object and the axis you rotated around. If you orient the object relative to its orientation around the torus, it's actually a lot simpler as the two axes are actually two axes of the object's transform.

You could generate a random point along the plane formed by these axes and move towards it (or even specifically within the circle defined by the interior of your torus). You could create a speed vector of adjustment and adjust it's values by small random amounts, moving at this random vector speed, changing the speed's direction away from the walls as you get further from the calculated position so that you never hit the walls. Move randomly as your use case best dictates.

## With physics forces

If you're not too concerned by the motion in the circle being a bit inaccurate, you could consider calculating the position where it should be as was done in the non-force driven methods and applying a force in that direction. You can then add random motion by either offsetting the point relative to the parent or applying a force along the plane formed by the object and the center of the torus at set intervals. You don't want to apply the random changes all the time because they can really mess up your simulation unless they are quite small.

Because this doesn't set the position explicitly, even with fairly strong random forces and collisions, as long as the object doesn't get stuck, it should continue along the initial circuit. If it does get stuck, the next time the calculations bring the destination back around, it is possible that it will re-align itself.

``````var distance : float = 10.0;
var angle : float = 0.0;

function FixedUpdate() {
angle += Time.deltaTime*speed;
while(angle >= 360) angle-= 360; //wrap around
while(angle < 0) angle += 360; //wrap the other way

//Rotate around the parent's up axis
var rotation = Quaternion.AngleAxis(angle, transform.parent.up);
var position = rotation * Vector3(distance, 0.0, 0.0) + transform.parent.position;
//You could randomly change position or some offset you are applying to it.

//head to where we should (Normalize if you want the adjustment more subtle)
rigidbody.AddForce((position - transform.position) * 10, ForceMode.Impulse);
//Or with a timer you could apply some force here to offset the motion
}
``````

# Moving inside arbitrary shapes

This is a bit more problematic because we can't assume much.

The general solution to this problem is to find the "forward" direction at that point in the tunnel and keep it moving that way, regardless of what else happens, assuming that your intent is to have it continue along that tunnel (like being in a stream of water, applying "constant" force from "behind"). The first problem with arbitrary shapes is how you decide what forward is and finding this can be much less obvious.

Programmatically, you could find the center/direction by performing raycasts, but with truly arbitrary shapes, assuming you aren't aligning yourself to a wall or something, you don't necessarily know which way to raycast at any given point and even if you do, it still leaves you with at least two directions (positive and negative) to use for the forward direction and very little way to really be sure which is correct.

The approach I would take is to set a center point probably with a series of waypoints and I might even set them up as bezier curves to get something smoother and I would most importantly know which way is forward by the order of the points. Using waypoints, you will of course need to know where you are along the path, which can be generally determined to some extent by your distance from the current (and subsequent/preceding if applicable) waypoints. Knowing my center point and direction, I would move my object with the path. Note that by stretching, skewing waypoint distances, you can also indicate speed adjustments based on flow, etc. Your waypoints could even be what you use to define your shape in the first place if you are generating your shape from a series of points and then your points could contain additional information about size of the shape at that point, etc.

To achieve random motion, I could do something like the above adjustments by random speeds or offsets, or set up alternate waypoints at certain points and have the object randomly interpolate between the two equations as appropriate and that would look sort of more natural while still being tunable.

As an alternative to waypoints, you could set up a series of trigger volumes that would apply force in the direction of the tunnel at that point, but this could lead to a lot of these for more complex tunnels and may get to be too much overhead depending on your use case. Also, remember to disable/enable and/or create/destroy stuff based on some LOD.

The point is that you know what forward is at any given point and push in that direction, while not immediately losing the initial motion prior to the forward motion being applied.

# Sliding along the wall

If you're using physics, have you considered tuning your physic materials? Try adding things like bounciness and lowering the friction as this may be more like what you actually meant by random motion and at the very least should address your sticking to the wall some, as long as you aren't constantly pushing towards the walls.. If you do it this way, in a system without (or with very little) drag, you could apply a random force at the start and then apply forces along the tunnel's curves and narrows/expanses to adjust the direction/speed as appropriate, you can just let the physics engine drive it for you with bounces, etc.

If this doesn't resolve that issue or if you're not using physics, you could maintain a variable that stores your movement vector (or even use rigidbody velocity if you need) and, on collision calculate a reflected vector away from the surface and ensure that it moves in this vector.

``````//This is a rough idea of forcing your object to bounce
//You may have to disable collisions for a brief moment afterwards if collisions are
//happening too frequently and generating wacky behaviour

var direction : Vector3;
function OnCollisionEnter(collision : Collision) {
if(collision.contacts[0]) { //I'm only checking one point
direction = Vector3.Reflect(-direction, collision.contacts[0].normal);
//Do something with the direction here or elsewhere
//Like setting the velocity on a rigidbody
//or the one used in your own movement calculations
}
}
``````
more ▼

answered Sep 15 '10 at 08:58 PM

skovacs1
10k 11 25 91

Thanks for the detailed response. I should have mentioned that although I'm currently using a torus for developing the movement, in the future it will be through a tunnel of arbitrary orientation, not a nice symmetrical torus now. I'll parse through your recs and see if I can wrap my head around them, esp. the last point about moving through arbitrary shapes. The way the cells move in this video http://www.youtube.com/watch?v=tKgroDE4DHo&feature=player_embedded at the 46-49 second mark is what I'm trying to recreate, albeit it more natural.

Sep 16 '10 at 03:41 AM

I've gone through the options trying to implement as needed, but likely lack the skills to figure it out (so far). I'm focusing on the moving inside arbitrary shapes and sliding along walls solutions. In sliding along the wall solution, you have direction = Vector3.Reflect(direction, collision.contacts[0].normal);...what is the direction parameter in the first argument of the Reflect method? I tried using the rigidbody.velocity, but that didn't work right. Was there something specific it should be?

Sep 17 '10 at 06:00 PM

Sorry. I missed a minus sign. Fixed now. Incoming directional vector reflected across the surface normal will still be directed at the surface, You need to add a minus sign either to the reflected direction or incoming direction in order to direct it away from the surface.

Sep 20 '10 at 09:00 PM

By Email:

Topics:

x2155
x1864
x573
x43

asked: Sep 15 '10 at 06:05 PM

Seen: 4689 times

Last Updated: Sep 16 '10 at 03:44 AM