Fizz X

Fizz is a 2D axis-aligned physics library for the Lua programming language. Fizz is useful in environments where external option like Box2D are unavailable.
The source code is available on GitHub and the official documentation is on 2dengine.com

Example

fizz = require("fizzx")
fizz.setGravity(0, 100)
ball = fizz.addDynamic('circle', 300, 100, 10) wall = fizz.addStatic('rect', 300, 400, 200, 10)
ball.bounce = 0.5
function love.update(dt) fizz.update(dt) end
function love.draw() love.graphics.circle("fill", ball.x, ball.y, ball.r) love.graphics.rectangle("fill", wall.x - wall.hw, wall.y - wall.hh, wall.hw*2, wall.hh*2) end

Shapes

Fizz supports three different shape types: circles, rectangles and line segments. Note that rectangles are represented by a center point and half-width and half-height extents. Rectangles are always axis-aligned and cannot have rotation. Line segments are useful for making slopes and possibly "one-sided" platforms. The direction of line segments affects how they handle collisions. Line segments "push" other intersecting shapes at 90 degrees counter-clockwise of the segment slope.
In addition, there are three classes of shapes: static, kinematic and dynamic. Static shapes are immobile and do not respond to collisions or gravity. Static shapes can be used to represent walls and platforms in your game. Kinematic shapes do not respond to collisions or gravity, but can be moved by manually changing their velocity. Kinematic shapes can be used to simulate moving platforms and doors. Dynamic shapes respond to collisions and gravity. Dynamic shapes can be used to simulate the moving objects in your game.
Shapes have the following properties:

shape.x, shape.y

Center position of circle and rectangle shapes. Starting point for line segments.

shape.x2, shape.y2

Ending point for line segments.

shape.r

Radius for circle shapes.

shape.hw, shape.hh

Half-width and half-height extents for rectangle shapes.

shape.xv, shape.yv

Velocity of a dynamic or kinematic shape.

shape.sx, shape.sy

Accumulated displacement vector of the shape.

shape.mass, shape.imass

Mass and inverse mass of the shape.

shape.friction

Friction value applied when the edges of two shapes are touching. As this value increases, the shape will slow down when sliding on top of other shapes. Must be between 0 and 1.

shape.bounce

Bounce or restitution value of the shape. As this value increases, the shape will bounce more elastically when colliding with other shapes. Must be between 0 and 1.

shape.damping

Linear damping of the shape. The damping value slows the velocity of moving shapes over time. Must be between 0 and infinity.

shape.gravity

Gravity scale of the shape which is multiplied by the global gravity value. Set this to 0 and your shape will not be affected by gravity. When negative, the shape will levitate.

shape.onCollide(a, b, nx, ny, pen)

Collision callback providing the two colliding shapes, the collision normal and the penetration depth. If this callback returns false the collision will be ignored. Shapes should not be moved or destroyed during this callback.

Limitations

Torque

Torque and rotation are not supported. This has several implications, most notably with circle shapes. Circle shapes are axis-aligned, so they never "spin" or "roll". Axis-aligned circles with friction behave like the wheels of a car while the breaks are on. If you want to simulate torque, I would suggest a more sophisticated library, like Box2D. For simple platform games, you could always draw or animate your objects as if they are rotating.

Tunneling

Since the library uses non-continuous collision detection, it's possible for shapes that move at a high velocity to "tunnel" or pass through other shapes. This problem can be accommodated in a few ways. First, make sure fizz.maxVelocity is defined within a reasonable range. Second, set up your game loop to update the simulation with a constant time step. This will make sure that the game will play the same on any machine. Here is an example of how to update the simulation with a constant time step:
accum = 0
step = 1/60
function update(dt)
  accum = accum + dt
  while accum >= step do
    fizz.update(step)
    accum = accum - step
  end
end

Partitioning

Fizz uses flat grid partitioning to reduce the number of collision tests. You can adjust the default grid cell size if the performance is not up to par.
Manually changing the position of shapes affects the partitioning system. After modifying these values, you have to repartition the particular shape, for example:
shape.x = 100
shape.y = 100
fizz.repartition(shape)
An alternative approach is to use the built-in functions:
fizz.positionShape(100, 100)
Note that changing the size of shapes affects the partition system as well:
circle.r = circle.r + 5
fizz.repartition(circle)
If you explicitly disable partitioning, then you can ignore this limitation.

Stacking

Piling two or more dynamic shapes results in jittery behavior, because there is no simple way to figure out which collision pair should be resolved first. This may cause one shape to overlap another in the stack even after their collisions have been resolved.

Ledges

This issue occurs with rows of static rectangle shapes. When a dynamic shape is sliding on top of the row it may get "blocked" by the ledge between rects. The best solution is to use line segments to represent platforms.

Credits

This library is based and builds upon the original work of Taehl
Please support our work so we can release more free software in the future.

Fizz X > fizz

fizz

The main module that you need to require in your game
fizz.addDynamic(shape, Center)
fizz.addKinematic(shape, Center)
fizz.addStatic(shape, Center)
fizz.getCollisionCount()
fizz.getDisplacement(shape)
fizz.getGravity()
fizz.getMass(shape, mass)
fizz.getPosition(shape)
fizz.getVelocity(shape)
fizz.removeShape(shape)
fizz.setDensity(s, d)
fizz.setGravity(x, y)
fizz.setMass(shape, mass)
fizz.setMaxVelocity(velocity)
fizz.setPosition(shape, X, Y)
fizz.setVelocity(shape, xv, yv)
fizz.update(delta, iterations)

fizz.addDynamic(shape, Center)

Creates a dynamic shape. Dynamic shapes can move and collide with other shapes.
Arguments
tstringshape
Shape type: "rect", "circle" or "line"
argCenter
position and extents for rectangles, radius for circles or starting and ending point for lines
Returns
shape New shape object

fizz.addKinematic(shape, Center)

Creates a kinematic shape. Kinematic shapes have a velocity but do not respond to collisions. This can be useful for simulating moving platforms.
Arguments
tstringshape
Shape type: "rect", "circle" or "line"
argCenter
position and extents for rectangles, radius for circles or starting and ending point for lines
Returns
shape New shape object

fizz.addStatic(shape, Center)

Creates a static shape. Static shapes are immovable and do not move or respond to collisions
Arguments
tstringshape
Shape type: "rect", "circle" or "line"
argCenter
position and extents for rectangles, radius for circles or starting and ending point for lines
Returns
shape New shape object

fizz.getCollisionCount()

Gets the number of collision checks performed between pairs of shapes during the last update.
Returns
number Number of collision checks

fizz.getDisplacement(shape)

Returns the accumulated separation vector of a shape for the last collision step.
Arguments
tableshape
Shape
Returns
number X separation
number Y separation

fizz.getGravity()

Gets the global gravity
Returns
number X-component of gravity
number Y-component of gravity

fizz.getMass(shape, mass)

Gets the mass of shape.
Arguments
tableshape
Shape
numbermass
Mass value
Returns
number Mass

fizz.getPosition(shape)

Gets the position of a shape (starting point for line shapes).
Arguments
tableshape
Shape
Returns
number X position
number Y position

fizz.getVelocity(shape)

Returns the velocity of a shape.
Arguments
tableshape
Shape
Returns
number X velocity
number Y velocity

fizz.removeShape(shape)

Removes a shape from the simulation.
Arguments
tableshape
Shape

fizz.setDensity(s, d)

Arguments
values
valued

fizz.setGravity(x, y)

Arguments
valuex
valuey

fizz.setMass(shape, mass)

Sets the mass of shape.
Arguments
tableshape
Shape
numbermass
Mass

fizz.setMaxVelocity(velocity)

Sets the maximum velocity treshold.
Arguments
numbervelocity
Maximum velocity

fizz.setPosition(shape, X, Y)

Moves the shape to a given position. This function is used to "teleport" shapes.
Arguments
tableshape
Shape
numberX
position
numberY
position

fizz.setVelocity(shape, xv, yv)

Sets the velocity of a shape
Arguments
tableshape
Shape
numberxv
X velocity
numberyv
Y velocity

fizz.update(delta, iterations)

Updates the simulation. To avoid tunneling, you want to use a fixed time step.
Arguments
numberdelta
Delta value
numberiterations
Number of iterations

Fizz X > partition

partition

Broad-phase partitioning code
partition.check(shape, ...)
partition.getCellsize()
partition.insert(shape, x, y, hw, hh)
partition.remove(shape)
partition.setCellsize(cellsize)

partition.check(shape, ...)

Arguments
valueshape
value...

partition.getCellsize()

partition.insert(shape, x, y, hw, hh)

Arguments
valueshape
valuex
valuey
valuehw
valuehh

partition.remove(shape)

Arguments
valueshape

partition.setCellsize(cellsize)

Arguments
valuecellsize

Fizz X > shape

shape

Shapes intersection code
shape.area(s)
shape.bounds(shape)
shape.create.circle(x, y, r)
shape.create.line(x, y, x2, y2)
shape.create.rect(x, y, hw, hw)
shape.test(a, b, dt)
shape.tests.circle.circle(a, b, dt)
shape.tests.circle.line(a, b, dt)
shape.tests.line.line(a, b, dt)
shape.tests.rect.circle(a, b, dt)
shape.tests.rect.line(a, b, dt)
shape.tests.rect.rect(a, b, dt)
shape.translate(shape, dx, dy)

shape.area(s)

Arguments
values

shape.bounds(shape)

Returns center position and half width/height extents for any shape
Arguments
tableshape
Shape
Returns
number X-position
number Y-position
number Width extent
number Height extent

shape.create.circle(x, y, r)

Creates a new circle shape
Arguments
numberx
Center x-position
numbery
Center y-position
numberr
Radius
Returns
table New shape

shape.create.line(x, y, x2, y2)

Creates a new line segment shape
Arguments
numberx
Starting point x-position
numbery
Starting point y-position
numberx2
Ending point x-position
numbery2
Ending point x-position
Returns
table New shape

shape.create.rect(x, y, hw, hw)

Creates a new rectangle shape
Arguments
numberx
Center x-position
numbery
Center y-position
numberhw
Half-width extent
numberhw
Half-height extent
Returns
table New shape

shape.test(a, b, dt)

Arguments
valuea
valueb
valuedt

shape.tests.circle.circle(a, b, dt)

Tests two circles for intersection
Arguments
tablea
Circle shape
tableb
Circle shape
numberdt
Time interval
Returns
number Penetration normal x-component
number Penetration normal y-component
number Penetration depth

shape.tests.circle.line(a, b, dt)

Tests a circle versus a line segment for intersection
Arguments
tablea
Circle shape
tableb
Line segment shape
numberdt
Time interval
Returns
number Penetration normal x-component
number Penetration normal y-component
number Penetration depth

shape.tests.line.line(a, b, dt)

Tests two line segments for intersection
Arguments
tablea
First line segment
tableb
Second line segment
numberdt
Time interval

shape.tests.rect.circle(a, b, dt)

Tests a rectangle versus a circle for intersection
Arguments
tablea
Rectangle shape
tableb
Circle shape
numberdt
Time interval
Returns
number Penetration normal x-component
number Penetration normal y-component
number Penetration depth

shape.tests.rect.line(a, b, dt)

Tests a rectangle versus a line segment for intersection
Arguments
tablea
Rectangle shape
tableb
Line segment shape
numberdt
Time interval
Returns
number Penetration normal x-component
number Penetration normal y-component
number Penetration depth

shape.tests.rect.rect(a, b, dt)

Tests two rectangles for intersection
Arguments
tablea
First rectangle shape
tableb
Second rectangle shape
numberdt
Time interval
Returns
number Penetration normal x-component
number Penetration normal y-component
number Penetration depth

shape.translate(shape, dx, dy)

Changes the position of a shape
Arguments
tableshape
Shape
numberdx
Change in x-position
numberdy
Change in y-position

This document was last updated on October 09, 2024, by 2dengine LLC. © All rights reserved.