# How to make balls (water, or fluid) through pipe

I'm working on a project and get stuck for days. I want to make balls going through the pipe like this game:

You can watch this Youtube video for more detail.

How can i replicate this game machenis?

• This looks like a very simple use of transform.position and a spline to control the path of travel. There are any number of Unity tutorials with titles like "move object on path" that cover this kind of action. How have you tried implementing this so far, based on the research you've done, and where did you get stuck? Aug 5 '20 at 4:02
• i stuck at making the balls going through the pipe. Because the pipe is dynamic and can be changed at runtime Aug 5 '20 at 4:55
• @tnhoanglonghd Then change the spline to fit the pipe Sep 4 '20 at 8:41

## 1 Answer

So there are going to be various steps to this. I'm not going to write all the code, because any solutions will be moderately complex and certainly more than we can go into here, but I am going to give you the basic building blocks.

Step 1: Basic graph & linear motion

You need to get this working before addressing curved paths.

Create a linear graph where each node is the edge of a section of pipe. That is, for n pipes, there will be n+1 edges. This graph can be as simple as a List<Vector2> in C#.

Hardcode some positions in, and change them later as you like:

List<Vector2> edgePositions = new List<Vector2>();
list.push(new Vector2(10, 10));
list.push(new Vector2(30, 0));
list.push(new Vector2(50, 100));


Now let's say you have points [0], [1], and [2] in that List. And that you have just one ball in the first section of pipe [0]-[1] (and not the second section which is the range [1]-[2]). This ball's position in the pipe can be described by t, a value between 0.0 and 1.0. Let's say that right now, the ball is at t=0.25between point [0] and point [1]. Now let's translate this into concrete terms.

First we need to get the difference vector between the two points:

Vector2 distFull = list[1] - list[0]; //(30,0) - (10,10) = (20,-10)

...So that is the full distance between these two points. The ball is 0.25 or 1/4 of the way along this difference vector, from point [0] (because [0] is the starting point):

Vector2 dist = diffFull * t; //(20, -10) * 0.25 = (5, -2.5)
Vector2 pos = list[0] + dist; //(10, 10) + (5, -2.5) = (15, 7.5)


We now have the ball at the current t. All we need to do is change t at each update:

float t = 0.0f;
float increment = 0.01f; //pretty small as it will need several frames before it reaches 1.0
...
FixedUpdate()
{
t += increment;
//do all the above stuff here, utilising t to get pos
ball.transform.position = pos;
}


t=0.25 should show the ball 1/4 of the way along the pipe section.

Step 2: Moving between pipe sections & t-remainders

You will know you have reached the end of a section when t > 1.0 (let's say 1.04 for sake of example). You now need to take that remainder and use it to move the ball through the next section of pipe:

FixedUpdate()
{
t += increment;
if (t > 1.0f)
{
let tRemainder = t - 1.0f;
//increase the pipe section index
p++;
t = tRemainder; //now we are using this 0.04 as the distance into the next pipe section
}
...
}


Step 3: Curvilinear motion

I would suggest seeking a C# Bezier curve library to make this easier for you. You will need to do a similar thing with t and input this into the curve's parametric function, however: (Bezier) curves are by nature non-linear, so for a naive Bezier curve function, t=0.25 will not show the ball at 1/4 of the way along the curved section of pipe.

Rather use a library whose curve function takes in the bezier curve control points and t, and returns a linear position along the curve that approximates t - so the library will do the work to get as close to 1/4 of the way along the curve as possible, when you input t=0.25, for example.

Step 4: Branching pipes

This is optional, but I've included it as it is shown in the game you linked.

You will need to understand the basics of graphs_ and how they are constructed in code (usually just Nodes with references to other Nodes which they connect to). You will have to then forego your nice easy List<Vector2> above in favour of these Nodes.