pogo 0.2.2

  • Readme
  • Changelog
  • Example
  • Installing
  • 60

🌕 Pogo Game Engine #

Pogo is a 2D game engine for Flutter (Android, iOS) (web in beta) (desktop in alpha).

Pogo implements what I'm calling a "Pseudo Entity Component System" for lack of a better term. Pogo's Pseudo ECS is very similar to the design pattern of other game engines that are extremely popular for rapid game development. Pogo games are made entirely of game entities (a.k.a. game objects). Game entities are built with modular components that are easy to understand.

Why a Pseudo ECS instead of a more pure ECS? (1) I didn't see myself as having time to go that far into the ECS pattern; and (2) I believe this pattern is quicker to ramp up on while still being more than robust enough for any game written in Dart.

example app preview

Documentation #

Showcase games #

GameAndroidiOSmacOSLinuxWindowsWeb
Pogo Bugreleasedtodobeta
example appreleased

Background #

Pogo was forked from Flame 0.18.1 and redesigned with the goal of making it twice as easy to understand and use. And... I believe I succeeded, with features like: game entities, better component design, intrinsic entity hierarchy, dynamic Z ordering, sensible sprite and animation components, fewer red herrings, and better docs.

All due credit to inu-no-policemen on Reddit and Luan Nico of Flame for setting up the core, which remains fairly unchanged. The rest of Flame, however, was showing growing pains, plus a reluctance to large changes in design. Thus, I launched a new project which will, hopefully, be more agile to needed change before version 1.0. Even at Pogo 0.0.1, just about everything above Flame's core was changed. I also added many new features critical to how I build games. See the first CHANGELOG entry for an overview of just how enormously different Pogo is from Flame.

Therefore, if you find a pre-release version of Pogo you like, lock it in, or be prepared for possible breaking changes. (Although, if I did a decent job with round one here, there shouldn't be any more major shifts in design coming -- just shifts isolated to parts still in need of refactoring. We'll see.)

The name, Pogo, comes from Pogo Bug -- the game I built this engine for. (Pogo Bug was originally written in QtQuick/QML but not released from that codebase due to Qt's difficult licensing issues.) Thus, this engine is tried and tested on my own small-but-complete game from day one. It took maybe 10x longer to work up this Flutter/Dart-based engine than to write the original Qt game. Judging by how quickly I then ported Pogo Bug to Pogo, versus how much trouble Flame was giving me, it seems Pogo was worth the effort. Pogo feels nearly as quick to build a game in as QtQuick was... and with better performance.

Contributing #

Hit me with a PR and I'll try to find time to engage it. No promises, but I'll try. Hopefully others will jump in and help. I pay close attention to naming and API consistency more so than code style -- code can be refactored without breaking things, naming and structure cannot.

There is still much to be done. I quickly hacked through some components from the previous engine that I didn't need at the moment, just to get them working. Thus, some components still need to be refactored to be more like the rest.

NinePatchComponent, ParallaxComponent, and ParticleComponent are some examples of things I just quick-hacked and saved for later. (See the Unreleased section in the changelog for a better TODO list.) Most things still work as Flame had them working, but they may not be fully "Pogo-ized" yet. I also haven't touched Box2D yet because Pogo Bug doesn't need it. (Another game of mine, GRITS Racing, uses Box2D heavily, so I should have the skills to work it in well when I get to it).

The core components I focused on the most are: SpriteComponent, AnimationComponent, and the gesture mixins. TextComponent got a pretty solid work over as well. These should be used as examples for how to refactor the rest.


Getting Started Guide #

What you need to know up front.

Adding the game engine to your project #

Add the pogo package dependency to your project's pubspec.yaml, for example (check your version number):

dependencies:
  pogo: ^0.2.2

A single import is required in each source file to access all the core game engine objects, types, etc.:

import 'package:pogo/game_engine.dart';

Asset files #

All asset files are assumed to be found under the assets folder. This is a limitation of at least one of the current plugins.

Furthermore, some subfolder defaults are set for certain asset types (the default can be changed with setSubPath() if desired).

The default asset tree looks like this:

.
└── assets
    ├── audio
    │   └── explosion.mp3
    ├── images
    │   └── background.png
    └── svgs
        ├── enemy.svg
        └── player.svg

Also, you must list all asset files in your pubspec.yaml file:

flutter:
  assets:
    - assets/audio/explosion.mp3
    - assets/images/background.png
    - assets/svgs/enemy.svg
    - assets/svgs/player.svg

This also works if you want to include all files in a folder (note that you must list each subfolder you want to include):

flutter:
  assets:
    - assets/audio/
    - assets/images/
    - assets/svgs/

Game engine config and startup #

This is the recommended sequence of code to start a game (expect changes here as things evolve):

import 'package:pogo/game_engine.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized(); // required
  await Screen.setFullScreen(); // mobile - not for web app use
  await Screen.setPortrait(); // mobile - not for web app use

  Camera.size = Size(135, 240); // default is native resolution

  System.defaultPivot = Pivot.topLeft; // default default is center
  System.defaultPaint.isAntiAlias = false; // low-res games will want this

  GestureInitializer.detectTaps = true;
  GestureInitializer.detectPans = true;

  await Assets.audioCache.load("explosion.mp3"); // not for web app use
  await Assets.rasterCache.load("background.png");
  await Assets.svgCache.loadAll(["enemy.svg", "player.svg"], scale: 0.75);

  runApp(Game().widget); // required

  await Screen.waitForStartupSizing(); // required

  MainEntity(); // you can name your startup entity whatever you like
}

class MainEntity extends GameEntity {
  MainEntity() {}
}

Note that you must initialize all gestures here that will be used anywhere in your game. More on gestures below.

It is recommended to cache your assets (the ones that currently can be cached). It is not required to cache them your main() but this is a good place to do it for simple games. More complex games will want to use the cache features to load and clear assets.

More game engine details here.

Game entities #

A Pogo game is made entirely of game entities (from the GameEntity class). An entity can be a sprite, a bullet, a container or parent to other entities (such as a scene, menu, or complex player), or whatever you need it to be.

Every game entity has:

  • a transform: position, zOrder, rotation, and scale
  • hierarchy connectors: parent and _children[]
  • the core update() method
  • an enabled property and a few other features

More GameEntity details here.

Game entities are made up of components. Some components are built into the entity (such as position/movable), some are added through mixins (such as the TapDetector mixin), and some are added by calling component classes (such as SpriteComponent).

Class-type components typically come with an update() or a render() method (or both) that must be called from the game entity's own update() in order for them to work.

Note: I may choose to someday automatically register component update() and render() methods so you don't have to call them explicitly... but not today.

The construction of a simple entity looks like this:

class Player extends GameEntity with {
  SpriteComponent playerSprite;
    
  Player(Vector2 position, int zOrder) {
    playerSprite = SpriteComponent.fromSvgCache("player.svg");
    this.position = position;
    this.zOrder = zOrder;
  }
    
  @override
  void update() {
    postition.x += 10 * Time.deltaTime;
    // Don't forget to render your visible components after updating them.
    playerSprite.render();
  }
}

Note the paradigm here that is typical to many game engines: you transform the entity and not the component. Also, components can have size properties, whereas entities only have scale. Components can have a pivot property, whereas entities have position and rotation. (Warning: Not all objects from Flame have been updated to this paradigm yet.)

Regarding the above paradigm, it is therefore unusual to have multiple components of a the same type in a single entity. For example, an entity will not typically have more than one sprite component unless you have images that should be composed, such as a border image and a content image or animation. Entities that use multiple images that need to move independent of each other should instead create a child entity for each part.

Entity hierarchy #

Any entity can be a parent to other entities. The transform (position, scale, etc.) of child entities are then relative to the parent. That is, they move with the parent.

Note that just because an entity (such as a scene) instantiates another entity, this does not automatically make it a child of that entity. The parent/child relationship must be set explicitly. This is done by either setting the parent property or by calling addChild().

The construction of a simple entity with children looks like this:

class Player extends GameEntity with {
  SpriteComponent playerSprite;
  GameEntity rightHand;
  GameEntity leftHand;
  Hat hat;

  Player(Vector2 position, int zOrder) {
    playerSprite = SpriteComponent.fromSvgCache("player.svg");
    this.position = position;
    this.zOrder = zOrder;

    // Instantiate and add children.
    rightHand = Sword(Vecter2(10, 0), 1);
    leftHand = Saber(Vecter2(-10, 0), 1);
    addChild(rightHand);
    addChild(leftHand);

    // Another way to add a child.
    hat = Hat(Vecter2.zero(), -1, parent: this);
  }
  ...
}

Entity gestures #

Gesture recognition is added to entities through mixins such as TapDetector and PanDetector. Note that the GestureArea mixin is also required for most gesture-detector mixins.

Remember to first initialize any needed gestures in your main(). See the example above.

The construction of a simple tappable entity looks like this:

class Enemy extends GameEntity with GestureArea, TapDetector {
  SpriteComponent enemySprite;
    
  Enemy(Vector2 position, int zOrder) {
    enemySprite = SpriteComponent.fromSvgCache("enemy.svg");
    this.position = position;
    this.zOrder = zOrder;
    gestureAreaSize = enemySprite.frameSize;
  }
    
  @override
  void update() {
    postition.x += 10 * Time.deltaTime;
    enemySprite.render();
  }

  @override
  void onTapDown(TapDownDetails details) {
    doSomething();
  }

  @override
  void onTapUp(TapUpDetails details) {}

  @override
  void onTapCancel() {}
}

More gesture details here.

Prefabs #

Prefabricated entities (prefabs) are helper classes for creating one-time-use entities quickly -- that is to say, you don't need to make a custom class for every object in your game. Prefabs are also useful for prototyping and other quick work.

Most class-type components come with a prefab for instantiating just that component. There are no prefabs that recognize gestures.

A very simple use of the SpritePrefab looks like this:

class SomeScene extends GameEntity {
  GameEntity bg;

  SomeScene() {
    bg = SpritePrefab(SpriteComponent.fromRasterCache("background.png"), zOrder: 1000);
  }
}

Entity destruction #

There currently is no automatic cleanup of out-of-scope entities. Therefore, be sure to call destroy() on all entities when you are done with them. Thus, it is a good idea to keep a reference variable to at least every parent entity you instantiate. destroy() is the only way to remove an entity from the update loop (and, hopefully, allow Dart to then garbage collect it).

If you destroy() a parent, all the children will be automatically destroyed for you. If you don't want to destroy a child, detach it first with removeChild() or by setting the child's parent property to null. Thus, you might find yourself creating parent entities whose only purpose it to make scene destruction easy.

(TODO: Think through parenting and destruction more.)


Credits #

Changelog #

All notable changes to this project will be documented in this file.

The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.

Unreleased #

Todo

  • Re-evaluate all audio tools and document. Includes: AudioCache, AudioPool, and Bgm. Should a pool helper class be in the core???
  • NinePatchComponent refactor.
  • ParallaxComponent refactor. Add SVG too. Consider keeping in core or move out. (I don't use this and instead use SpriteComponents to make my own parallaxes.)
  • ParticleComponent and ParticlePrefab refactor. Consider keeping in core or move out.
  • TimerComponent refactor.
  • Take another look at message boxes and text. They're stable for now but there is probably much to do still.
  • Investigate the minor artifacts from non-integer canvas scaling in low-res games.
  • I've noticed math and/or scaling/position problems with the --enable-software-rendering flag in both API 16 and 23 (and likely all others).

Done

0.2.2 - 2020-06-23 #

Changed #

  • Made AudioPool more web-friendly, for what its worth. No more web-performant though. Overlapping web audio is still lousy (depending on browser, luck, and who knows what).
  • WARNING: Breaking changes! Renamed some parameters of AudioPool to better match the rest of Pogo.
  • Added other notes and hints to the docs about audio in web apps.

Removed #

  • Removed dependency on path_provider: ^1.6.6. Don't know what it was left over from. Guessing early audio stuff. Well, it did chase away some warnings due to other plugins that have outdated dependencies on it. If a tool cannot keep up, it should probably be dropped (audioplayers).

0.2.1 - 2020-06-20 #

Changed #

  • Reverted flutter_svg 0.18.0 back to 0.17.3+1 because the latest version depends on a pre-release version of Flutter. Who builds packages like this?

0.2.0 - 2020-06-20 #

Changed #

  • WARNING: Breaking changes!
  • This update introduces "built-in" and "external" components (plugins). Components (and their respective particles and prefabs) that were not deemed necessary for the core of a basic 2D engine were moved to their own projects (pogo_*). This meant, especially, components that rely on 3rd-party libraries: TiledComponent, FlareComponent, and Box2DComponent.
    • Not sure yet about non-3rd-party extras such as: ParticleComponent and ParallaxComponent. These are currently a mess and I can't say I'll ever find time to dig into them.
    • After looking at the continued growing pains of Flame and its willy-nilly addition of any component that doesn't break the engine -- regardless of how muddy or useless it is -- I have once again been inspired to "do it different" with Pogo. Flame has been really helpful in this regard.
    • Moving 3rd-party plugins out should push Pogo significantly towards version 1.0.
    • This should also simplify PR handling and maybe even help these components get the attention they need.

Removed #

  • TiledComponent and TiledPrefab moved out to its own pogo_tiled project.
  • FlareComponent, FlareParticle, and FlarePrefab moved out to its own pogo_rive project. Everything here was renamed from Flare to Rive to match the new branding of the Rive product.
  • All Box2D stuff moved out to its own pogo_box2d project. Moving Box2D out was a tough decision. On one hand, it can be appropriate for a game engine to include a physics engine. On the other hand, Pogo is just a thin layer on top of Flutter and probably should not be dictating which physics engine a game dev should be using. Also, the Box2D integration still needs major analysis and refactoring. Seeing it in Flame as a single "component" or two makes my brain hurt. It should be another type of plugin (perhaps a mixin) that comes with a suite of components.

0.1.2 - 2020-05-27 #

Added #

  • Added web app hints to some docs.

Changed #

  • Removed yet another unused import identified by pub.dev.

Removed #

  • Removed the PogoBinding class that extended BindingBase. This was a relic from Flame (called FlameBinding) of unknown use except for a note that it was used to setup Flutter services. It looked like a singleton. Likely something needed for an early version of Flutter. Anyhow, the latest Flutter in the beta channel doesn't like it, so I simply removed it due to no known references to it.

0.1.1 - 2020-05-24 #

Added #

Changed #

  • pubspec.yaml: updated audioplayers from 0.14.0 to 0.15.1 as suggested by pub.dev.
  • Removed a couple unused imports identified by pub.dev.

0.1.0 - 2020-05-24 #

With the release of Pogo Bug on Android, the Pogo Game Engine is now bona fide and ready for release as v0.1.0.

Changed #

  • pubspec.yaml: updated path_provider from 1.6.0 to 1.6.6 to remove a bug/warning.
  • pubspec.yaml: updated flutter_svg from 0.17.1 to 0.17.4 to work with the latest Flutter update.
  • Minor doc edits.

0.0.3 - 2020-04-25 #

Added #

  • TapAreaPrefab is an experimental prefab to aid in creating simple GUI dialogs (or other objects) that may have more than one hot spot.

Changed #

  • WARNING: Breaking changes!
  • GestureZone etc. renamed to GestureArea etc. to be more consistent with Flutter lingo (I hope). To update, do a non-word global replace that preserves case.

0.0.2 - 2020-04-21 #

Added #

  • AnimationComponent.frameCount property added (not sure where this went or what I was thinking).
  • Pivot.translateWH() method added. Takes two doubles: width and height.
  • AnimationComponent.currentFrameWidth and .currentFrameHeight props added (doubt I'll add size, top, left, offset, rect, but maybe should).
  • System.defaultPaint for setting up the default Paint (namely, isAntiAlias = false for low-res games).

Changed #

  • Various doc edits.
  • The introduction of System.defaultPaint and elimination of palette.dart brought various changes throughout.

Fixed #

  • MessageBox text parsing fixed to handle one line without dropping a char.

Removed #

  • WARNING: Breaking changes!
  • SpritePrefab.empty() constructor removed. Was left over from testing.
  • PaletteEntry and BasicPalette (all of palette.dart) classes removed. These are helper classes that confuse best practice more than helping. I figure less than 1% are likely to use. And, of those, most would be better off with their own solution for Color/Paint constants (or use material.Colors). Dart's Color and Paint classes are not too hard for game dev as they are. Given the need for Paint.isAntiAlias (and possibly other Paint props) in some games, this really complicates a universal helper.

0.0.1 - 2020-04-13 #

This project was forked from Flame 0.18.1 and this is the first commit as Pogo. I have some previous commits after Flame 0.18.1 that were submitted as a PR to Flame but that PR was not accepted. Thus, Pogo was born. Those changes are here along with many more changes to just about every part of the code. This includes the introduction of entities and a significant redefinition of what a component is. I will attempt to give a pretty good overview of all changes here. The degree of changes is too great to hope to list in absolute detail. Just look at the diffs of the commits leading up to this version and you'll see what I mean.

Added #

  • game_engine.dart exports every feature of the engine. Thus, only one import needed now: import 'package:pogo/game_engine.dart';. Still working on best practices for import/export.
  • GameEntity new fundamental class that replaces Component etc. Also comes with new features/properties: enabled, zOrder, scale, parent, addChild(), removeChild(), getChildren().
  • zOrder adds fully-dynamic z-ordering (integer based... but you can pretend it is scaled-int if you like). A critical feature, I think.
  • SpriteImage superclass and subtypes Raster and Svg. For granting equal rights to the new image types to components that can use either.
  • SVG support now built into SpriteComponent by use of the new SpriteImage superclass. This cascades to supporting SVGs in AnimationComponent. (More components need this change.)
  • AnimationComponent.paused feature added. Particularly useful for those that need to control the currentFrame prop in code.
  • AnimationComponent methods: advance(), pause(), resume().
  • GestureInitializer static class in widget_builder.dart for setting up the main GestureDetector.
  • GestureZone mixin for help limiting gestures to just the entity they are attached to.
  • Created a complete set of scale-adaptive, gesture-detector mixins (and renamed Tapable to TapDetector).
  • Created several well-divided static classes: System, Time, Screen, GameCanvas, Camera, Assets, PogoWidget.
  • Assets.svgCache and SvgCache class added.
  • Assets.xxxxxCache.get(filename) method added to encourage explicit cache use.
  • Assets.xxxxxCache.setSubPath(subPath) method added to override default path under /assets.
  • System.defaultPivot added to allow overriding the new default of Pivot.center.
  • Time.now, Time.unscaledNow, Time.frameCount fields added. Note: scaled-time features (like pause) not yet built.
  • Screen.onResize for setting a callback when the screen/window gets resized (in case you want to adjust the Camera or whatever).
  • Camera static class adds a new camera methodology with both offset and size/scaling. Hint: scaling is particularly useful for low-res games.
  • vector_math.dart to promote easy use of Vector2 et al throughout your code, and for easier integration with Box2D.
  • /example -- wrote a new main example app showing a few more features. (Moved the old one to /doc/examples/primatives with a couple interesting changes.)

Changed #

  • WARNING: Breaking changes!
  • Game renamed to GameCore and BaseGame renamed to Game (not that they look much like their former selves).
  • The new Game is now a singleton and GameCore only exists for adventurous souls who want a starting point for their own engine. I am aware of the many differing opinions of the use of singletons, static classes, etc... but I eventually came to the conclusion that the best-practice rules can be different for an engine versus the rules for the apps that run on that engine. Thus, the pros for the Game() singleton far outweighed the cons. Really, the only cons I could find had to do with PogoWidget/PseudoGame and, since that is not a tier-1 feature, it had little weight.
  • update() and render() no longer pass any data (and resize() was completely removed, see Removed section below). The data was moved to static classes. See Time.deltaTime and GameCanvas.main. (render() now also removed.)
  • BaseGame.camera (Position) replaced with a new Camera.rect paradigm.
  • BaseGame.size moved to Screen.size and initialized in more ways (and still probably needs more working out).
  • BaseGame.debugMode() moved to GameCore.debugMode and not propagated to entities either. Use Game().debugMode to read. Look for other changes and new visualizations and data here.
  • More BaseGame changes not bothering to list.
  • The Flame static class and the Util helper class were replaced by several static classes. Most of the contents of Flame was moved to Assets. Most of the contents of Util was moved to Screen.
  • Caches renamed, Flame.images to Assets.rasterCache, Flame.audio to Assets.audioCache (and their respective classes renamed too: FlameAudio to AudioCache, etc.). Others?
  • Cache methods renamed, clear() to remove(), clearCache() to clear(), to be more in line with other Dart objects.
  • Regarding what Flamed called "components," this took a great deal of sorting out -- all the details of which I will not list. The base Component seemed be part-component/part-entity, while handling neither well, and with confusing mixin dependencies. Thus, most feature components had a similar identity crisis where most were some sort of entity/component combo, while others were specialized entities, and others were a difficult mash of entity, component, and/or primitive object. Fixing this broke everything (to put it lightly) and triggered the majority of all the other changes here. In short, and very loosely, Component+PositionComponent+ComposedComponent became GameEntity with true-component features (like size) removed. Some components were renamed to prefabs (such as AnimationComponent to AnimationPrefab, then Animation to AnimationComponent, same with sprites) while most others were demoted to simple components by stripping out the entity stuff. These kept their name and new prefabs were created for them. What this adds up to, for the most part, is that add() (which is no longer used) is replaced by a call to the prefab instead (i.e. add(SpriteComponent()) to SpritePrefab(SpriteComponent())) and then the contained component syntax needs to be fixed, and the new prefab syntax added. Get all that? Yeah, it's gonna be a mess if trying to port a large project from Flame.
  • isHud() replaced by isOverlay. (Not sure what all the functions were about.) More generic term. Not all overlays are HUDs.
  • The static priority() was replaced by zOrder which is also now fully dynamic.
  • angle renamed to rotation (and added rotationDeg).
  • Anchor class renamed to Pivot and expanded with more translate methods. "Anchor" was not incorrect. I wanted to clarify the nuances between anchoring in UI engines and pivoting in game engines.
  • Changed default pivot (anchor) from topLeft to center. Default can now also be set in System.
  • All Sprite and Animation (renamed to SpriteComponent and AnimationComponent) constructors refactored with focus on simplifying, clarifying, and flexibility. (This is where I first started into this can of worms, BTW.) Most properties are now included as optional named parameters in the constructors. (Modeled loosely after Qt's AnimatedSprite.) All async instantiations have been moved to Future<> methods.
  • The flexibility from the above changes eliminates the need for the animation sequence constructor... as well as the entire spritesheet module. Admittedly, the new way can get a bit wordy (as seen in the updated spritesheet example app) but can also be beautifully simple (as seen in the updated particles example app).
  • Raster image slicing now happens via integer parameters instead of doubles (when using the raster-specific constructors). I find it very odd if have to do counter-intuitive things like width: image.height.toDouble() to slice an image for an animation. Don't worry, the sprites and animations are still positioned and sized with doubles.
  • Because I was breaking so much, I went a little further than normal in renaming a few minor things. textureWidth etc. are now frameWidth etc. currentIndex is now currentFrame (and the previous currentFrame getter was removed). done() is now isFinished. getSprite() is now getCurrentSprite(). Others I'm probably forgetting (like whatever frameCount was before).
  • Animation.reversed() replaced by a new and fancy AnimationComponent.reverse mechanism instead. reversed() was a surprising deep-copy function. If wanting a deep-copy feature, be less surprising about it, and then reverse it if wanted.
  • FlareComponent refactored similar to sprite and SVG handling. FlareAnimation renamed to FlareComponent, FlareComponent renamed to FlarePrefab among other things like adding a pivot.
  • TextConfig.render() moved to TextComponent because it gave the TextConfig type too much personality while TextComponent didn't have enough. This forced all example apps to a better practice of using text components and/or prefabs. Debug-mode text reverted to lower-level code and painting. Regarding debug-mode text, if you really need helpers for drawing such text, then create a debug-mode-specific helper elsewhere.
  • TextConfig.withXxxx() helpers replaced by more flexible and more standard copyWith().
  • NineTileBoxComponent renamed to NinePatchComponent to match Flutter and other sources.
  • TextBoxComponent renamed to MessageBoxComponent because, well, a box with text in it is not always a text box. Also underwent lingo and many other changes. Still much to do, it appears.
  • TimerComponent has some lingo changes, and also still in need of rethink.
  • ComponentParticle renamed to EntityParticle.
  • WidgetBuilder now ignores unneeded/deprecated events (assuming I understand GestureDetector mojo correctly, which I may not).
  • Many, many source files split/renamed/moved/deleted. Folders too.
  • All example apps fixed, axed, or replaced. Well, okay, a couple still give some trouble that I can't seem to care about much right now.
  • All docs totally rewritten. "Totally." Tried to remove all conflicting info and also write something easier to ramp up on. This took almost as much time as the rest.

Removed #

  • WARNING: Breaking changes!
  • resize() method and all related objects. Not needed with the new camera and resize callback. This feature has confused me since I haven't seen anything like it before and I fail to see why camera position and scaling can't handle everything. But, well, maybe someone has a use case they can show me.
  • render() removed after finding little reason to keep it. Things run just fine without it and, given Flutter's control of these lower-lever things like execution order, why pretend otherwise?
  • Spritesheet helper class. Not needed with the new sprite and animation constructors.
  • SvgComponent thingy class. SVG support built into the new SpriteComponent.
  • ComposedComponent mixin. Concept built-in with new design.
  • HasGameRef mixin. Made moot by Game() singleton.
  • Position data type. Replaced by Vector2 or Offset.
  • renderFlipX/Y props. Replaced by negative scaling which does the same thing.
  • angleBetween() helper. Made redundant by position.angleTo().
  • distance() helper. Made redundant by position.distanceTo().
  • prepareCanvas() made redundant by new design.
  • add(Component) is no longer needed to add objects to the game loop. "Adding" is now automatic in the entity constructor.
  • /doc/examples/tapable example app removed as it became redundant to gestures. At least one other I don't recall.

Flame 0.18.1 - 2020-02-09 #

example/lib/main.dart

import 'dart:math';

import 'package:pogo/game_engine.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Screen.setFullScreen();
  await Screen.setPortrait();

  GestureInitializer.detectTaps = true;

  await Assets.svgCache.load("planet.svg", scale: 2.0);
  await Assets.svgCache.load("moon.svg", scale: 0.27 * 2.0);

  runApp(Game().widget);

  await Screen.waitForStartupSizing();

  MainEntity();
}


class MainEntity extends GameEntity {

  static const double rotationFactor  = 4.0;
  static const double stretchFactor   = 0.25;
  static const double moonScaleFactor = 0.5;
  static const double moonDistance    = 200.0;

  double startTime = Time.now;

  GameEntity planet;
  Moon moon;
  Vector2 moonCenter = Vector2.zero();

  // Construct the MainEntity and other entities and content.
  MainEntity() {
    // Create some sprite entities, in various ways.
    planet = SpritePrefab(
      SpriteComponent.fromSvgCache("planet.svg"),
      position: Vector2(Screen.size.width / 2, Screen.size.height / 2),
      zOrder: 100,
    );

    moonCenter = Vector2(Screen.size.width / 2, Screen.size.height / 2);

    moon = Moon(moonCenter.clone(), 0);
  }

  // Main game loop.
  @override
  void update() {
    // Rotate the moon (on the wrong axis... this is 2D so why not?).
    moon.rotation += moon.spinDirection * rotationFactor * Time.deltaTime;
    moon.rotation %= 2 * pi; // trims the rotation value to keep it in bounds

    // Set up for the next trick: clock-based transformations.
    double delta = Time.now - startTime;
    if (delta >= 4.0) {
      delta -= 4.0;
      startTime += 4.0; // reset the sequence start time
    }

    // Do more scientifically-wrong stuff while showing off more features
    // like scaling and dynamic Z ordering!
    if (delta < 1.0 || delta >= 4.0) {
      planet.scale.x  = 1 + delta * stretchFactor;
      planet.scale.y  = 1 - delta * stretchFactor;
      moon.scale.x    = moon.scale.y = 1 + sin((1 - delta) * pi / 2) * moonScaleFactor;
      moon.position.y = moonCenter.y - moonDistance * cos((1 - delta) * pi / 2);
    } else if (delta < 2.0) {
      delta -= 1.0;
      planet.scale.x  = 1 + (1 - delta) * stretchFactor;
      planet.scale.y  = 1 - (1 - delta) * stretchFactor;
      moon.scale.x    = moon.scale.y = 1 - sin(delta * pi / 2) * moonScaleFactor;
      moon.position.y = moonCenter.y - moonDistance * cos(delta * pi / 2);
      moon.zOrder     = 200;
    } else if (delta < 3.0) {
      delta -= 2.0;
      planet.scale.x  = 1 - delta * stretchFactor;
      planet.scale.y  = 1 + delta * stretchFactor;
      moon.scale.x    = moon.scale.y = 1 - sin((1 - delta) * pi / 2) * moonScaleFactor;
      moon.position.y = moonCenter.y + moonDistance * cos((1 - delta) * pi / 2);
    } else if (delta < 4.0) {
      delta -= 3.0;
      planet.scale.x  = 1 - (1 - delta) * stretchFactor;
      planet.scale.y  = 1 + (1 - delta) * stretchFactor;
      moon.scale.x    = moon.scale.y = 1 + sin(delta * pi / 2) * moonScaleFactor;
      moon.position.y = moonCenter.y + moonDistance * cos(delta * pi / 2);
      moon.zOrder     = 0;
    }
  }

}


class Moon extends GameEntity with GestureArea, TapDetector {
  SpriteComponent moonSprite;
  int spinDirection = -1;

  Moon(Vector2 position, int zOrder) {
    moonSprite = SpriteComponent.fromSvgCache("moon.svg");
    this.position = position;
    this.zOrder = zOrder;
    gestureAreaSize = moonSprite.frameSize;
  }

  @override
  void update() {
    moonSprite.render();
  }

  @override
  void onTapDown(TapDownDetails details) {
    // Toggle the spin direction.
    spinDirection *= -1;
  }

  @override
  void onTapUp(TapUpDetails details) {
  }

  @override
  void onTapCancel() {
  }

}

Use this package as a library

1. Depend on it

Add this to your package's pubspec.yaml file:


dependencies:
  pogo: ^0.2.2

2. Install it

You can install packages from the command line:

with Flutter:


$ flutter pub get

Alternatively, your editor might support flutter pub get. Check the docs for your editor to learn more.

3. Import it

Now in your Dart code, you can use:


import 'package:pogo/game_engine.dart';
import 'package:pogo/pseudo_game.dart';
  
Popularity:
Describes how popular the package is relative to other packages. [more]
24
Health:
Code health derived from static analysis. [more]
100
Maintenance:
Reflects how tidy and up-to-date the package is. [more]
90
Overall:
Weighted score of the above. [more]
60
Learn more about scoring.

We analyzed this package on Jul 8, 2020, and provided a score, details, and suggestions below. Analysis was completed with status completed using:

  • Dart: 2.8.4
  • pana: 0.13.14
  • Flutter: 1.17.5

Analysis suggestions

Package does not support Flutter platform android

Because:

  • package:pogo/game_engine.dart that imports:
  • package:pogo/src/particles/sprite_particle.dart that imports:
  • package:pogo/src/components/sprite_component.dart that imports:
  • package:pogo/src/game/assets_static.dart that imports:
  • package:pogo/src/caches/audio_cache.dart that imports:
  • package:audioplayers/audio_cache.dart that imports:
  • package:path_provider/path_provider.dart that imports:
  • package:path_provider_linux/path_provider_linux.dart that declares support for platforms: linux

Package does not support Flutter platform ios

Because:

  • package:pogo/game_engine.dart that imports:
  • package:pogo/src/particles/sprite_particle.dart that imports:
  • package:pogo/src/components/sprite_component.dart that imports:
  • package:pogo/src/game/assets_static.dart that imports:
  • package:pogo/src/caches/audio_cache.dart that imports:
  • package:audioplayers/audio_cache.dart that imports:
  • package:path_provider/path_provider.dart that imports:
  • package:path_provider_linux/path_provider_linux.dart that declares support for platforms: linux

Package does not support Flutter platform linux

Because:

  • package:pogo/game_engine.dart that imports:
  • package:pogo/src/particles/sprite_particle.dart that imports:
  • package:pogo/src/components/sprite_component.dart that imports:
  • package:pogo/src/game/assets_static.dart that imports:
  • package:pogo/src/caches/audio_cache.dart that imports:
  • package:audioplayers/audio_cache.dart that declares support for platforms: android, ios, macos, web

Package does not support Flutter platform macos

Because:

  • package:pogo/game_engine.dart that imports:
  • package:pogo/src/particles/sprite_particle.dart that imports:
  • package:pogo/src/components/sprite_component.dart that imports:
  • package:pogo/src/game/assets_static.dart that imports:
  • package:pogo/src/caches/audio_cache.dart that imports:
  • package:audioplayers/audio_cache.dart that imports:
  • package:path_provider/path_provider.dart that imports:
  • package:path_provider_linux/path_provider_linux.dart that declares support for platforms: linux

Package does not support Flutter platform web

Because:

  • package:pogo/game_engine.dart that imports:
  • package:pogo/src/particles/sprite_particle.dart that imports:
  • package:pogo/src/components/sprite_component.dart that imports:
  • package:pogo/src/game/assets_static.dart that imports:
  • package:pogo/src/caches/audio_cache.dart that imports:
  • package:audioplayers/audio_cache.dart that imports:
  • package:path_provider/path_provider.dart that declares support for platforms: android, ios, linux, macos

Package does not support Flutter platform windows

Because:

  • package:pogo/game_engine.dart that imports:
  • package:pogo/src/particles/sprite_particle.dart that imports:
  • package:pogo/src/components/sprite_component.dart that imports:
  • package:pogo/src/game/assets_static.dart that imports:
  • package:pogo/src/caches/audio_cache.dart that imports:
  • package:audioplayers/audio_cache.dart that declares support for platforms: android, ios, macos, web

Package not compatible with SDK dart

Because:

  • pogo that is a package requiring null.

Health suggestions

Fix lib/src/game/game_core.dart. (-0.50 points)

Analysis of lib/src/game/game_core.dart reported 1 hint:

line 122 col 41: Close instances of dart.core.Sink.

Format lib/src/audio/audio_pool.dart.

Run flutter format to format lib/src/audio/audio_pool.dart.

Format lib/src/audio/bgm.dart.

Run flutter format to format lib/src/audio/bgm.dart.

Fix additional 45 files with analysis or formatting issues.

Additional issues in the following files:

  • lib/src/caches/audio_cache.dart (Run flutter format to format lib/src/caches/audio_cache.dart.)
  • lib/src/caches/raster_cache.dart (Run flutter format to format lib/src/caches/raster_cache.dart.)
  • lib/src/caches/svg_cache.dart (Run flutter format to format lib/src/caches/svg_cache.dart.)
  • lib/src/caches/text_file_cache.dart (Run flutter format to format lib/src/caches/text_file_cache.dart.)
  • lib/src/components/animation_component.dart (Run flutter format to format lib/src/components/animation_component.dart.)
  • lib/src/components/message_box_component.dart (Run flutter format to format lib/src/components/message_box_component.dart.)
  • lib/src/components/nine_patch_component.dart (Run flutter format to format lib/src/components/nine_patch_component.dart.)
  • lib/src/components/parallax_component.dart (Run flutter format to format lib/src/components/parallax_component.dart.)
  • lib/src/components/sprite_component.dart (Run flutter format to format lib/src/components/sprite_component.dart.)
  • lib/src/components/sprite_image.dart (Run flutter format to format lib/src/components/sprite_image.dart.)
  • lib/src/components/text_component.dart (Run flutter format to format lib/src/components/text_component.dart.)
  • lib/src/components/text_config.dart (Run flutter format to format lib/src/components/text_config.dart.)
  • lib/src/components/timer_component.dart (Run flutter format to format lib/src/components/timer_component.dart.)
  • lib/src/entities/game_entity.dart (Run flutter format to format lib/src/entities/game_entity.dart.)
  • lib/src/entities/mixins/gesture_mixins.dart (Run flutter format to format lib/src/entities/mixins/gesture_mixins.dart.)
  • lib/src/game/assets_static.dart (Run flutter format to format lib/src/game/assets_static.dart.)
  • lib/src/game/camera_static.dart (Run flutter format to format lib/src/game/camera_static.dart.)
  • lib/src/game/game_canvas_static.dart (Run flutter format to format lib/src/game/game_canvas_static.dart.)
  • lib/src/game/game_main.dart (Run flutter format to format lib/src/game/game_main.dart.)
  • lib/src/game/pogo_widget_static.dart (Run flutter format to format lib/src/game/pogo_widget_static.dart.)
  • lib/src/game/screen_static.dart (Run flutter format to format lib/src/game/screen_static.dart.)
  • lib/src/game/system_static.dart (Run flutter format to format lib/src/game/system_static.dart.)
  • lib/src/game/time_static.dart (Run flutter format to format lib/src/game/time_static.dart.)
  • lib/src/game/widget_builder.dart (Run flutter format to format lib/src/game/widget_builder.dart.)
  • lib/src/particles/accelerated_particle.dart (Run flutter format to format lib/src/particles/accelerated_particle.dart.)
  • lib/src/particles/animation_particle.dart (Run flutter format to format lib/src/particles/animation_particle.dart.)
  • lib/src/particles/computed_particle.dart (Run flutter format to format lib/src/particles/computed_particle.dart.)
  • lib/src/particles/entity_particle.dart (Run flutter format to format lib/src/particles/entity_particle.dart.)
  • lib/src/particles/moving_particle.dart (Run flutter format to format lib/src/particles/moving_particle.dart.)
  • lib/src/particles/paint_particle.dart (Run flutter format to format lib/src/particles/paint_particle.dart.)
  • lib/src/particles/rotating_particle.dart (Run flutter format to format lib/src/particles/rotating_particle.dart.)
  • lib/src/particles/scaled_particle.dart (Run flutter format to format lib/src/particles/scaled_particle.dart.)
  • lib/src/particles/translated_particle.dart (Run flutter format to format lib/src/particles/translated_particle.dart.)
  • lib/src/pivot.dart (Run flutter format to format lib/src/pivot.dart.)
  • lib/src/prefabs/animation_prefab.dart (Run flutter format to format lib/src/prefabs/animation_prefab.dart.)
  • lib/src/prefabs/message_box_prefab.dart (Run flutter format to format lib/src/prefabs/message_box_prefab.dart.)
  • lib/src/prefabs/nine_patch_prefab.dart (Run flutter format to format lib/src/prefabs/nine_patch_prefab.dart.)
  • lib/src/prefabs/parallax_prefab.dart (Run flutter format to format lib/src/prefabs/parallax_prefab.dart.)
  • lib/src/prefabs/particle_prefab.dart (Run flutter format to format lib/src/prefabs/particle_prefab.dart.)
  • lib/src/prefabs/sprite_prefab.dart (Run flutter format to format lib/src/prefabs/sprite_prefab.dart.)
  • lib/src/prefabs/tap_area_prefab.dart (Run flutter format to format lib/src/prefabs/tap_area_prefab.dart.)
  • lib/src/prefabs/text_prefab.dart (Run flutter format to format lib/src/prefabs/text_prefab.dart.)
  • lib/src/prefabs/timer_prefab.dart (Run flutter format to format lib/src/prefabs/timer_prefab.dart.)
  • lib/src/vector_math.dart (Run flutter format to format lib/src/vector_math.dart.)
  • lib/src/widgets/nine_patch.dart (Run flutter format to format lib/src/widgets/nine_patch.dart.)

Maintenance issues and suggestions

Support latest dependencies. (-10 points)

The version constraint in pubspec.yaml does not support the latest published versions for 1 dependency (flutter_svg).

Dependencies

Package Constraint Resolved Available
Direct dependencies
Dart SDK >=2.3.0 <3.0.0
audioplayers ^0.15.1 0.15.1
flutter 0.0.0
flutter_svg ^0.17.3+1 0.17.4 0.18.0
meta ^1.1.8 1.1.8 1.2.1
synchronized ^2.2.0 2.2.0+1
vector_math >=2.0.0 <3.0.0 2.0.8 2.1.0-nullsafety
Transitive dependencies
charcode 1.1.3
collection 1.14.12 1.14.13
convert 2.1.1
crypto 2.1.5
file 5.2.1
flutter_web_plugins 0.0.0
intl 0.16.1
path 1.7.0
path_drawing 0.4.1
path_parsing 0.1.4
path_provider 1.6.11
path_provider_linux 0.0.1+2
path_provider_macos 0.0.4+3
path_provider_platform_interface 1.0.2
petitparser 3.0.4
platform 2.2.1
plugin_platform_interface 1.0.2
process 3.0.13
sky_engine 0.0.99
typed_data 1.1.6 1.2.0
uuid 2.2.0
xdg_directories 0.1.0
xml 3.7.0 4.2.0
Dev dependencies
flutter_test
test ^1.9.4