# SimulationBall

### Overview <a href="#overview" id="overview"></a>

SimulationBall is an object that calculates the ball's movement in advance and then plays back the result. Compared to a regular physics ball, it is easier to predict the trajectory and can represent more stable results even when multiple players are viewing the same ball.

It is especially useful in the following cases:

* Games where the ball trajectory is important, such as soccer or basketball
* Situations where you need to create bouncing movement against walls or floors
* Cases where you want to preview the ball path and adjust gameplay accordingly

### How to Use <a href="#how-to-use" id="how-to-use"></a>

#### Create a SimulationBall and a Bound Collision Group <a href="#create-a-simulationball-and-a-bound-collision-group" id="create-a-simulationball-and-a-bound-collision-group"></a>

Create a `SimulationBall` in the Level Browser and place it where you want to use it.

<figure><img src="https://2064130887-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FhrvYlLq1mQAq0V0vwPsb%2Fuploads%2FkJx3tjzZKb1otb3eFdHn%2Fimage.png?alt=media&#x26;token=b45c5dfd-d97f-4961-9398-131a29f193d3" alt=""><figcaption></figcaption></figure>

Create a Collision Group. Set the Collision Group name to `Bound`.

Objects that the ball should collide with, such as walls or floors, must be assigned to this Collision Group.

<figure><img src="https://2064130887-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FhrvYlLq1mQAq0V0vwPsb%2Fuploads%2Fd5Va3wA9qXWLmtfZv5JK%2Fimage.png?alt=media&#x26;token=fcfa18b9-df1e-48a9-913a-e12a949ef2ed" alt=""><figcaption></figcaption></figure>

{% hint style="warning" %}
`SimulationBall` is currently restricted to performing collision simulations for the 5th Collision Group only. This logic will be updated upon the implementation of Collision Profiles
{% endhint %}

#### Controlling Simulation with a Script <a href="#controlling-simulation-with-a-script" id="controlling-simulation-with-a-script"></a>

Find the SimulationBall, set the starting position and velocity, and run the simulation.

`Simulate()` does not finish instantly when called. Since the simulation is processed internally in asynchronous chunks, the result may not be ready immediately after `Simulate()` is called.

```lua
local Workspace = game:GetService("Workspace")
local Ball = Workspace:WaitForChild("SimulationBall")

-- EnablePathMarker displays the predicted trajectory of the SimulationBall on screen.
Ball.EnablePathMarker = true


local Params = BallSimParams.new()
Params.Mass = 0.43
Params.InitialCFrame = CFrame.new(0, 100, -800)
Params.InitialVelocity = Vector3.new(300, 900, 0)
Params.Simsteps = 120
Params.DeltaTime = 1 / 30

-- If you add spin values below, the ball can bounce in the spin direction on the ground
-- or create a Magnus effect (curve ball) while in the air.
--Params.InitialSpinAxis = Vector3.new(0, 1, 0)
--Params.InitialSpinSpeed = 0

Ball:Simulate(Params)
task.wait()
Ball:Play()
```

{% embed url="<https://files.gitbook.com/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FhrvYlLq1mQAq0V0vwPsb%2Fuploads%2FaeR6mxgSCxEW6nmNUill%2Fsimball.mp4?alt=media&token=e0c9d163-ff93-48d9-a898-c20520da7fa8>" %}

#### Checking the Result <a href="#checking-the-result" id="checking-the-result"></a>

When you run the game, the ball moves in the configured direction, and if path markers are enabled, you can also see the predicted trajectory.

For your first test, it is recommended to check the following:

1. Whether the ball starts from the expected position
2. Whether the ball moves in the intended direction
3. Whether the speed is too fast or too slow
4. Whether collisions against the floor or walls look natural

#### Main BallSimParams Settings <a href="#main-ballsimparams-settings" id="main-ballsimparams-settings"></a>

You can adjust the ball's behavior by changing the main settings of `BallSimParams` .

<table><thead><tr><th width="220">Property</th><th>Description</th></tr></thead><tbody><tr><td><strong>InitialCFrame</strong></td><td>Defines the starting position of the ball.</td></tr><tr><td><strong>InitialVelocity</strong></td><td>Defines the launch direction and force of the ball.</td></tr><tr><td><strong>InitialSpinAxis</strong></td><td>Defines the axis the ball rotates around.</td></tr><tr><td><strong>InitialSpinSpeed</strong></td><td>Defines the rotation speed of the ball.</td></tr><tr><td><strong>Mass</strong></td><td>Used to adjust the weight feeling of the ball.</td></tr><tr><td><strong>BaseGravity</strong></td><td>Adjusts how strongly the ball falls downward. The default is 980. If set to 0, the ball becomes weightless, and if set to a negative value, gravity works in the opposite direction.</td></tr><tr><td><strong>EnablePathMarker</strong></td><td>Allows you to see the ball trajectory on screen.</td></tr><tr><td><strong>SpinMagnusWeight</strong></td><td>Defines the weight of the Magnus effect applied when the ball is spinning. The larger the value, the more the trajectory curves.</td></tr><tr><td><strong>Simsteps</strong></td><td>Defines how many steps the simulation uses internally. Higher values can improve precision but also increase calculation cost.</td></tr><tr><td><strong>DeltaTime</strong></td><td>The time interval of each simulation step. Together with `Simsteps`, it determines the total simulation length and precision.</td></tr></tbody></table>

For example, if you want the ball to travel farther, increase `InitialVelocity`. If you want it to start from a higher point, increase the height value of `InitialCFrame`.

### Additional SimulationBall Features <a href="#additional-simulationball-features" id="additional-simulationball-features"></a>

Unlike a regular real-time physics simulation, SimulationBall pre-calculates the ball trajectory and collisions from the given BallSimParams and then plays the result.

Because of this, you can inspect the ball path or collision position before calling `Play()`.

#### Get the Next Bounce Position <a href="#get-the-next-bounce-position" id="get-the-next-bounce-position"></a>

After the simulation is processed, SimulationBall can tell you where the ball will bounce next.

This is useful in cases such as:

* When you want to know which wall the ball will hit next
* When you want to place an effect at the next bounce position
* When AI or game logic needs to predict the next collision point

```lua
local Workspace = game:GetService("Workspace")
local Ball = Workspace:WaitForChild("SimulationBall")

local Params = BallSimParams.new()

Params.Mass = 0.43
Params.InitialCFrame = CFrame.new(0, 100, 0)
Params.InitialVelocity = Vector3.new(100, 900, 0)
Params.Simsteps = 120
Params.DeltaTime = 1 / 30


Ball:Simulate(Params)
task.wait()
local NextBounce = Ball:FindNextBallBounce()

if NextBounce.BouncedTime > 0 then
    print("Next Bounce Time:", NextBounce.BouncedTime)
    print("Next Bounce Position:", NextBounce.BouncedPosition)
end

Ball:Play()
```

This example uses `FindNextBallBounce()` to get information about the next bounce.\
The returned value contains the bounce time and bounce position, so you can inspect where the ball will bounce in advance.

However, if you call `FindNextBallBounce()` immediately after `Simulate()`, the calculation may not be finished yet. As shown in the example, you should wait briefly with `task.wait()` before calling it.

#### Get the Ball Physics Values After N Seconds <a href="#get-the-ball-physics-values-after-n-seconds" id="get-the-ball-physics-values-after-n-seconds"></a>

SimulationBall can also return the state of the ball at a specific future time.

This is useful in the following cases:

* When you want to know the position of the ball after N seconds
* When you want to check the speed of the ball at a later time
* When you want to predict future rotation as well as movement

```lua
local Workspace = game:GetService("Workspace")
local Ball = Workspace:WaitForChild("SimulationBall")

local Params = BallSimParams.new()
Params.Mass = 0.43
Params.InitialCFrame = CFrame.new(0, 100, 0)
Params.InitialVelocity = Vector3.new(100, 900, 0)
Params.Simsteps = 120
Params.DeltaTime = 1 / 30

Ball:Simulate(Params)
task.wait()

local CheckTime = 2.0

local FutureCFrame = Ball:GetCFrameAtTime(CheckTime)
local FutureVelocity = Ball:GetLinearVelocityAtTime(CheckTime)
local FutureSpeed = Ball:GetSpeedAtTime(CheckTime)
local FutureAngularVelocity = Ball:GetAngularVelocityAtTime(CheckTime)

print("Position in 2s:", FutureCFrame.Position)
print("Velocity vector in 2s:", FutureVelocity)
print("Speed in 2s:", FutureSpeed)
print("Angular velocity in 2s:", FutureAngularVelocity)
```

This example reads the ball physics values after `2 seconds`.

* `GetCFrameAtTime()` : position and rotation at that time
* `GetLinearVelocityAtTime()` : movement direction and speed at that time
* `GetSpeedAtTime()` : speed only as a number
* `GetAngularVelocityAtTime()` : angular velocity at that time

In other words, SimulationBall can do more than just play a ball path. It can also let you inspect the **future position, velocity, and rotation** in advance.

Here as well, avoid reading values immediately after `Simulate()`. It is better to wait briefly with `task.wait()` first.

Also, if `CheckTime` is outside the current simulation range, you may not get the expected result. Make sure `Simsteps × DeltaTime` is large enough to cover the time you want to query.

### Notes <a href="#notes" id="notes"></a>

{% hint style="warning" %}
To enable collisions with `SimulationBall` under the current temporary system, please ensure the target wall or floor is assigned to the 5th Collision Group. Note that this requirement will be replaced by a more flexible system once CollisionProfiles are implemented.
{% endhint %}

* `Simulate()` does not finish immediately and is processed internally in asynchronous chunks. Therefore, you should wait briefly with `task.wait()` before calling `Play()` or reading results.
* The `SimulationBall` name must match the name used in the script.
* You must run the simulation before playing the ball.
* If the velocity value is too small, the ball may appear to barely move.
* During testing, enabling `EnablePathMarker` helps a lot when checking whether things are working correctly.

### Reference Documents <a href="#reference-documents" id="reference-documents"></a>

{% content-ref url="../../../development/api-reference/classes/simulationball" %}
[simulationball](https://docs.overdare.com/development/api-reference/classes/simulationball)
{% endcontent-ref %}

{% content-ref url="../../../development/api-reference/datatype/ballsimparams" %}
[ballsimparams](https://docs.overdare.com/development/api-reference/datatype/ballsimparams)
{% endcontent-ref %}
