Skip to content
Merged
2 changes: 2 additions & 0 deletions .github/.cspell/gamedev_dictionary.txt
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ multitap # support from a device to recognize many taps at the same time
orientable # can be oriented
pathfinding # computer algorithm to find the best path through a world or maze
perlin # Perlin Noise, a type of noise generating algorithm
platformers # plural of platformer, a genre of video game
quadtree # a tree-based data structure where each node has exactly 4 children
rasterizing
respawn # when the player character dies and is brought back after some time and penalties
Expand All @@ -42,6 +43,7 @@ retarget # to direct (something) toward a different target
RGBA # red green blue alpha
RGBO # red green blue opacity
scos # cosine of a rotation multiplied by the scale factor
scrollers # plural of scroller, a genre of video game
shaderbundle # a file extension used to bundle shaders for GLSL
slerp # short for spherical linear interpolation, a method to interpolate quaternions
spritesheet # a single image packing multiple sprites, normally in a grid
Expand Down
4 changes: 2 additions & 2 deletions doc/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ void main() {

In Flame we provide a concept called the Flame Component System (FCS), which is a way to organize
your game objects in a way that makes it easy to manage them. You can read more about it in the
[Components](flame/components.md) section.
[Components](flame/components/components.md) section.

When you want to start a new game you either have to extend the `FlameGame` class or the `World`
class. The `FlameGame` is the root of your game and is responsible for managing the game loop and
Expand Down Expand Up @@ -126,7 +126,7 @@ overridden the `onLoad` method to set the sprite of the component to a sprite th
image file called `player.png`. The image has to be in the `assets/images` directory in your project
(see the [Assets Directory Structure](flame/structure.md)) and you have to add it to the
[assets section](https://docs.flutter.dev/ui/assets/assets-and-images) of your `pubspec.yaml` file.
In this class we also set the size of the component to 200x200 and the [anchor](flame/components.md#anchor)
In this class we also set the size of the component to 200x200 and the [anchor](flame/components/position_component.md#anchor)
to the center of the component by sending them to the `super` constructor. We also let the user of
the `Player` class set the position of the component when creating it
(`Player(position: Vector2(0, 0))`).
Expand Down
25 changes: 16 additions & 9 deletions doc/flame/camera.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
# Camera & World

In most games the world is larger than what fits on screen at once. The camera controls which
portion of the game world is visible and how it is projected onto the player's display, handling
panning, zooming, and following characters. This is similar to how a
[`Viewport`](https://api.flutter.dev/flutter/rendering/RenderViewport-class.html) in Flutter determines
which part of a scrollable area is visible, but tailored for the free-form 2D coordinate space of
a game.

Example of a simple game structure:

```text
Expand Down Expand Up @@ -39,7 +46,7 @@ statically rendered below the world.

This component should be used to host all other components that comprise your
game world. The main property of the `World` class is that it does not render
through traditional means -- instead it is rendered by one or more
through traditional means; instead it is rendered by one or more
[CameraComponent](#cameracomponent)s to "look at" the world. In the `FlameGame` class there is
one `World` called `world` which is added by default and paired together with
the default `CameraComponent` called `camera`.
Expand Down Expand Up @@ -82,7 +89,7 @@ which is paired together with the default `world`, so you don't need to create
or add your own `CameraComponent` if your game doesn't need to.

A `CameraComponent` has two other components inside: a [Viewport](#viewport) and a
[Viewfinder](#viewfinder), those components are always children of a camera.
[Viewfinder](#viewfinder). Those components are always children of a camera.

The `FlameGame` class has a `camera` field in its constructor, so you can set
what type of default camera that you want, like this camera with a
Expand Down Expand Up @@ -124,8 +131,8 @@ final camera = CameraComponent.withFixedResolution(
);
```

This will create a camera with a viewport centered in the middle of the screen, taking as much
space as possible while still maintaining the 4:3 (800x600) aspect ratio, and showing a game world region
This will create a camera with a viewport centered in the middle of the screen, taking as much space
as possible while still maintaining the 4:3 (800x600) aspect ratio, and showing a game world region
of size 800 x 600.

A "fixed resolution" is very simple to work with, but it will underutilize the user's available
Expand All @@ -148,14 +155,14 @@ components.

The following viewports are available:

- `MaxViewport` (default) -- this viewport expands to the maximum size allowed
- `MaxViewport` (default): this viewport expands to the maximum size allowed
by the game, i.e. it will be equal to the size of the game canvas.
- `FixedResolutionViewport` -- keeps the resolution and aspect ratio fixed, with black bars on the
- `FixedResolutionViewport`: keeps the resolution and aspect ratio fixed, with black bars on the
sides if it doesn't match the aspect ratio.
- `FixedSizeViewport` -- a simple rectangular viewport with predefined size.
- `FixedAspectRatioViewport` -- a rectangular viewport which expands to fit
- `FixedSizeViewport`: a simple rectangular viewport with predefined size.
- `FixedAspectRatioViewport`: a rectangular viewport which expands to fit
into the game canvas, but preserving its aspect ratio.
- `CircularViewport` -- a viewport in the shape of a circle, fixed size.
- `CircularViewport`: a viewport in the shape of a circle, fixed size.


If you add children to the `Viewport` they will appear as static HUDs in front of the world.
Expand Down
77 changes: 40 additions & 37 deletions doc/flame/collision_detection.md
Original file line number Diff line number Diff line change
@@ -1,24 +1,29 @@
# Collision Detection

Almost every game needs to know when objects touch or overlap. Without collision detection a player
could walk through walls, bullets would pass through enemies, and coins could never be collected.
Flame provides a built-in collision detection system so you can focus on what *happens* when objects
collide rather than writing the intersection math yourself.

Collision detection is needed in most games to detect and act upon two components intersecting each
other. For example an arrow hitting an enemy or the player picking up a coin.
other. For example, an arrow hitting an enemy or the player picking up a coin.

In most collision detection systems you use something called hitboxes to create more precise
bounding boxes of your components. In Flame the hitboxes are areas of the component that can react
to collisions (and make [gesture input](inputs/gesture_input.md#gesturehitboxes)) more accurate.
to collisions and make [gesture input](inputs/gesture_input.md#gesturehitboxes) more accurate.

The collision detection system supports three different types of shapes that you can build hitboxes
from, these shapes are Polygon, Rectangle and Circle. Multiple hitbox can be added
to a component to form the area which can be used to either detect collisions
or whether it contains a point or not,
the latter is very useful for accurate gesture detection. The collision detection does not handle
what should happen when two hitboxes collide, so it is up to the user to implement what will happen
when for example two `PositionComponent`s have intersecting hitboxes.
from, these shapes are Polygon, Rectangle and Circle. Multiple hitboxes can be added to a
component to form the area which can be used to either detect collisions or determine whether it
contains a point. The latter is very useful for accurate gesture detection. The collision
detection does not handle what should happen when two hitboxes collide, so it is up to the user
to implement what will happen when for example two `PositionComponent`s have intersecting
hitboxes.

Do note that the built-in collision detection system does not take collisions between two hitboxes
that overshoot each other into account, this could happen when they either move very fast or
`update` being called with a large delta time (for example if your app is not in the foreground).
This behavior is called tunneling, if you want to read more about it.
that overshoot each other into account. This could happen when they either move very fast or
`update` is called with a large delta time (for example if your app is not in the foreground).
This behavior is called tunneling.

Also note that the collision detection system has a limitation that makes it not work properly if
you have certain types of combinations of flips and scales of the ancestors of the hitboxes.
Expand Down Expand Up @@ -104,7 +109,7 @@ The set of points is where the edges of the hitboxes intersect.
Note that the `onCollision` method will be called on both `PositionComponent`s if they have both
implemented the `onCollision` method, and also on both hitboxes. The same goes for the
`onCollisionStart` and `onCollisionEnd` methods, which are called when two components and hitboxes
starts or stops colliding with each other.
start or stop colliding with each other.

When a `PositionComponent` (and hitbox) starts to collide with another `PositionComponent`
both `onCollisionStart` and `onCollision` are called, so if you don't need to do something specific
Expand Down Expand Up @@ -172,11 +177,10 @@ class MyComponent extends PositionComponent {
```

If you don't add any arguments to the hitbox, like above, the hitbox will try to fill its parent as
much as possible. Except for having the hitboxes trying to fill their parents,
there are two ways to
initiate hitboxes and it is with the normal constructor where you define the hitbox by itself, with
a size and a position etc. The other way is to use the `relative` constructor which defines the
hitbox in relation to the size of its intended parent.
much as possible. Apart from having the hitboxes fill their parents, there are two ways to
initialize hitboxes. One is with the normal constructor where you define the hitbox by itself,
with a size and a position etc. The other way is to use the `relative` constructor which defines
the hitbox in relation to the size of its intended parent.


In some specific cases you might want to handle collisions only between hitboxes, without
Expand Down Expand Up @@ -217,7 +221,7 @@ class MySpecialHitbox extends RectangleHitbox {
```

You can read more about how the different shapes are defined in the
[ShapeComponents](components.md#shapecomponents) section.
[ShapeComponents](components/shape_components.md) section.

Remember that you can add as many `ShapeHitbox`s as you want to your `PositionComponent` to make up
more complex areas. For example a snowman with a hat could be represented by three `CircleHitbox`s
Expand Down Expand Up @@ -256,7 +260,7 @@ about at the moment but that might later come back in to view so they are not co
from the game.

These are just examples of how you could use these types, there will be a lot more use cases for
them so don't doubt to use them even if your use case isn't listed here.
them so don't hesitate to use them even if your use case isn't listed here.


### PolygonHitbox
Expand All @@ -270,20 +274,20 @@ default calculated from the size of the collidable that they are attached to, bu
polygon can be made in an infinite number of ways inside of a bounding box you have to add the
definition in the constructor for this shape.

The `PolygonHitbox` has the same constructors as the [](components.md#polygoncomponent), see that
section for documentation regarding those.
The `PolygonHitbox` has the same constructors as the [](components/shape_components.md#polygoncomponent),
see that section for documentation regarding those.


### RectangleHitbox

The `RectangleHitbox` has the same constructors as the [](components.md#rectanglecomponent), see
that section for documentation regarding those.
The `RectangleHitbox` has the same constructors as the [](components/shape_components.md#rectanglecomponent),
see that section for documentation regarding those.


### CircleHitbox

The `CircleHitbox` has the same constructors as the [](components.md#circlecomponent), see that
section for documentation regarding those.
The `CircleHitbox` has the same constructors as the [](components/shape_components.md#circlecomponent),
see that section for documentation regarding those.


## ScreenHitbox
Expand Down Expand Up @@ -315,7 +319,7 @@ worry about the broad phase system that is used, so if the standard implementati
enough for you, you probably don't have to read this section.

A broad phase is the first step of collision detection where potential collisions are calculated.
Calculating these potential collisions is faster than to checking the intersections exactly,
Calculating these potential collisions is faster than checking the intersections exactly,
and it removes the need to check all hitboxes against each other and
therefore avoiding O(n²).

Expand Down Expand Up @@ -386,9 +390,9 @@ class Bullet extends PositionComponent with CollisionCallbacks {
// do NOT collide with Player or Water
return false;
}
// Just return true if you're not interested in the parent's type check result.
// Or call super and you will be able to override the result with the parent's
// result.
// Just return true if you're not interested in
// the parent's type check result. Or call super
// to override the result with the parent's result.
return super.onComponentTypeCheck(other);
}

Expand Down Expand Up @@ -470,7 +474,7 @@ range. For such cases, an optional `maxDistance` can be provided.

To use the ray casting functionality you have to have the `HasCollisionDetection` mixin on your
game. After you have added that, you can call `collisionDetection.raycast(...)` on your game class,
or with the `HasGameReference` Mixin from other components as well.
or with the `HasGameReference` mixin from other components as well.

Example:

Expand Down Expand Up @@ -505,10 +509,10 @@ The result from this operation will either be `null` if the ray didn't hit anyth

- Which hitbox the ray hit
- The intersection point of the collision
- The reflection ray, i.e. how the ray would reflect on the hitbox that it hix
- The reflection ray, i.e. how the ray would reflect on the hitbox that it hit
- The normal of the collision, i.e. a vector perpendicular to the face of the hitbox that it hits

If you are concerned about performance you can pre create a `RaycastResult` object that you send in
If you are concerned about performance you can pre-create a `RaycastResult` object that you send in
to the method with the `out` argument, this will make it possible for the method to reuse this
object instead of creating a new one for each iteration. This can be good if you do a lot of
ray casting in your `update` methods.
Expand Down Expand Up @@ -587,7 +591,7 @@ class MyGame extends FlameGame with HasCollisionDetection {
```

In the example above we send out a ray from (0, 100) diagonally down to the right
and we say that we want it the bounce on at most 100 hitboxes,
and we say that we want it to bounce on at most 100 hitboxes,
it doesn't necessarily have to get 100 results since at
some point one of the reflection rays might not hit a hitbox and then the method is done.

Expand All @@ -613,14 +617,13 @@ as a dependency.
But if you have a simpler use-case and just want to check for collisions of components and improve
the accuracy of gestures, Flame's built-in collision detection will serve you very well.

If you have the following needs you should at least consider to use
[Forge2D](https://github.com/flame-engine/forge2d):
If you have the following needs you should at least consider using [Forge2D](https://github.com/flame-engine/forge2d):

- Interacting realistic forces
- Realistic interacting forces
- Particle systems that can interact with other bodies
- Joints between bodies

It is a good idea to just use the Flame collision detection system if you on the other hand only
On the other hand, it is a good idea to just use the Flame collision detection system if you only
need some of the following things (since it is simpler to not involve Forge2D):

- The ability to act on some of your components colliding
Expand Down
Loading