# Oxygen We (the Flame organization) built an ECS (Entity Component System) named Oxygen. If you want to use Oxygen specifically for Flame as a replacement for the FCS(Flame Component System) you should use our bridge library [flame_oxygen](https://github.com/flame-engine/flame/tree/main/packages/flame_oxygen) and if you just want to use it in a Dart project you can use the [oxygen](https://github.com/flame-engine/oxygen) library directly. If you are not familiar with Oxygen yet we recommend you read up on its [documentation](https://github.com/flame-engine/oxygen/tree/main/doc). To use it in your game you just need to add `flame_oxygen` to your `pubspec.yaml`, as can be seen in the [Oxygen example](https://github.com/flame-engine/flame/tree/main/packages/flame_oxygen/example) and in the `pub.dev` [installation instructions](https://pub.dev/packages/flame_oxygen). ## OxygenGame (Game extension) If you are going to use Oxygen in your project it can be a good idea to use the Oxygen specific extension of the `Game` class. It is called `OxygenGame` and it will give you full access to the Oxygen framework while also having full access to the Flame game loop. Instead of using `onLoad`, as you are used to with Flame, `OxygenGame` comes with the `init` method. This method is called in the `onLoad` but before the world initialization, allowing you to register components and systems and do anything else that you normally would do in `onLoad`. A simple `OxygenGame` implementation example can be seen in the [example folder](https://github.com/flame-engine/flame/tree/main/packages/flame_oxygen/example). The `OxygenGame` also comes with it's own `createEntity` method that automatically adds certain default components on the entity. This is especially helpful when you are using the [BaseSystem](#basesystem) as your base. ## Systems Systems define the logic of your game. In FCS you normally would add your logic inside a component with Oxygen we use systems for that. Oxygen itself is completely platform agnostic, meaning it has no render loop. It only knows `execute`, which is a method equal to the `update` method in Flame. On each `execute` Oxygen automatically calls all the systems that were registered in order. But in Flame we can have different logic for different loops (render/update). So in `flame_oxygen` we introduced the `RenderSystem` and `UpdateSystem` mixin. These mixins allow you to add the `render` method and the `update` method respectively to your custom system. For more information see the [RenderSystem](#mixin-rendersystem) and [UpdateSystem](#mixin-updatesystem) section. If you are coming from FCS you might expect certain default functionality that you normally got from the `PositionComponent`. As mentioned before components do not contain any kind of logic, but to give you the same default functionality we also created a class called `BaseSystem`. This system acts almost identical to the prerender logic from the `PositionComponent` in FCS. You only have to subclass it to your own system. For more information see the [BaseSystem](#basesystem) section. Systems can be registered to the world using the `world.registerSystem` method on [OxygenGame](#oxygengame-game-extension). ### mixin GameRef The `GameRef` mixin allows a system to become aware of the `OxygenGame` instance its attached to. This allows easy access to the methods on the game class. ```dart class YourSystem extends System with GameRef { @override void init() { // Access to game using the .game propery } // ... } ``` ### mixin RenderSystem The `RenderSystem` mixin allows a system to be registered for the render loop. By adding a `render` method to the system you get full access to the canvas as you normally would in Flame. ```dart class SimpleRenderSystem extends System with RenderSystem { Query? _query; @override void init() { _query = createQuery([/* Your filters */]); } void render(Canvas canvas) { for (final entity in _query?.entities ?? []) { // Render entity based on components } } } ``` ### mixin UpdateSystem The `MixinSystem` mixin allows a system to be registered for the update loop. By adding a `update` method to the system you get full access to the delta time as you normally would in Flame. ```dart class SimpleUpdateSystem extends System with UpdateSystem { Query? _query; @override void init() { _query = createQuery([/* Your filters */]); } void update(double dt) { for (final entity in _query?.entities ?? []) { // Update components values } } } ``` ### BaseSystem The `BaseSystem` is an abstract class whoms logic can be compared to the `PositionComponent` from FCS. The `BaseSystem` automatically filters all entities that have the `PositionComponent` and `SizeComponent` from `flame_oxygen`. On top of that you can add your own filters by defining a getter called `filters`. These filters are then used to filter down the entities you are interested in. The `BaseSystem` is also fully aware of the game instance. You can access the game instance by using the `game` property. This also gives you access to the `createEntity` helper method on `OxygenGame`. On each render loop the `BaseSystem` will prepare your canvas the same way the `PositionComponent` from FCS would (translating, rotating and setting the anchor. After that it will call the `renderEntity` method so you can add your own render logic for that entity on a prepared canvas. The following components will be checked by `BaseSystem` for the prepartion of the canvas: - `PositionComponent` (required) - `SizeComponent` (required) - `AnchorComponent` (optional, defaults to `Anchor.topLeft`) - `AngleComponent` (optional, defaults to `0`) ```dart class SimpleBaseSystem extends BaseSystem { @override List> get filters => []; @override void renderEntity(Canvas canvas, Entity entity) { // The canvas is translated, rotated and fully prepared for rendering. } } ``` ### ParticleSystem The `ParticleSystem` is a simple system that brings the Particle API from Flame to Oxygen. This allows you to use the [ParticleComponent](#particlecomponent) without having to worry about how it will render or when to update it. As most of that logic is already contained in the Particle itself. Simply register the `ParticleSystem` and the `ParticleComponent` to your world like so: ```dart world.registerSystem(ParticleSystem()); world.registerComponent(() => ParticleComponent); ``` You can now create a new entity with a `ParticleComponent`. For more info about that see the [ParticleComponent](#particlecomponent) section. ## Components Components in Oxygen are different than the ones from FCS mainly because instead of containing logic they only contain data. This data is then used in systems which in turn define the logic. To accomdate people who are switching from FCS to Oxygen we implemented a few components to help you get started. Some of these components are based on the multiple functionalities that the `PositionComponent` from FCS has. Others are just easy wrappers around certain Flame API functionality, they are often accompanied by predefined systems that you can use. Components can be registered to the world using the `world.registerComponent` method on [OxygenGame](#oxygengame-game-extension). ### PositionComponent The `PositionComponent` is as its name implies is a component that describe the position of an entity. And it is registered to the world by default. Creating a positioned entity using OxygenGame: ```dart game.createEntity( position: Vector2(100, 100), size: // ... ); ``` Creating a positioned entity using the World: ```dart world.createEntity() ..add(Vector2(100, 100)); ``` ### SizeComponent The `SizeComponent` is as its name implies is a component that describe the size of an entity. And it is registered to the world by default. Creating a sized entity using OxygenGame: ```dart game.createEntity( position: // ... size: Vector2(50, 50), ); ``` Creating a sized entity using the World: ```dart world.createEntity() ..add(Vector2(50, 50)); ``` ### AnchorComponent The `AnchorComponent` is as its name implies is a component that describe the anchor position of an entity. And it is registered to the world by default. This component is especially useful when you are using the [BaseSystem](#basesystem). But can also be used for your own anchoring logic. Creating an anchored entity using OxygenGame: ```dart game.createEntity( position: // ... size: // ... anchor: Anchor.center, ); ``` Creating an anchored entity using the World: ```dart world.createEntity() ..add(Anchor.center); ``` ### AngleComponent The `AngleComponent` is as its name implies is a component that describe the angle of an entity. And it is registered to the world by default. The angle is in radians. This component is especially useful when you are using the [BaseSystem](#basesystem). But can also be used for your own angle logic. Creating an angled entity using OxygenGame: ```dart game.createEntity( position: // ... size: // ... angle: 1.570796, ); ``` Creating an angled entity using the World: ```dart world.createEntity() ..add(1.570796); ``` ### FlipComponent The `FlipComponent` can be used to flip your rendering on either the X or Y axis. It is registered to the world by default. This component is especially useful when you are using the [BaseSystem](#basesystem). But can also be used for your own flipping logic. Creating an entity that is flipped on it's X axis using OxygenGame: ```dart game.createEntity( position: // ... size: // ... flipX: true ); ``` Creating an entity that is flipped on it's X axis using the World: ```dart world.createEntity() ..add(FlipInit(flipX: true)); ``` ### SpriteComponent The `SpriteComponent` is as its name implies is a component that describe the sprite of an entity. And it is registered to the world by default. This allows you to assigning a Sprite to an Entity. Creating an entity with a sprite using OxygenGame: ```dart game.createEntity( position: // ... size: // ... )..add( SpriteInit(await game.loadSprite('pizza.png')), ); ``` Creating an entity with a sprite using World: ```dart world.createEntity() ..add( SpriteInit(await game.loadSprite('pizza.png')), ); ``` ### TextComponent The `TextComponent` is as its name implies is a component that adds a text component to an entity. And it is registered to the world by default. This allows you to add text to your entity, combined with the `PositionComponent` you can use it as a text entity. Creating an entity with text using OxygenGame: ```dart game.createEntity( position: // ... size: // ... )..add( TextInit( 'Your text', config: const TextPaintConfig(), ), ); ``` Creating an entity with text using World: ```dart world.createEntity() ..add( TextInit( 'Your text', config: const TextPaintConfig(), ), ); ``` ### ParticleComponent The `ParticleComponent` wraps a `Particle` from Flame. Combined with the [ParticleSystem](#particlesystem) you can easily add particles to your game without having to worry about how to render a particle or when/how to update one. Creating an entity with a particle using OxygenGame: ```dart game.createEntity( position: // ... size: // ... )..add( // Your Particle. ); ``` Creating an entity with a particle using World: ```dart world.createEntity() ..add( // Your Particle. ); ```