OctopusKit Tips & Troubleshooting
- Common Mistakes
- Best Practices
- Tips & Tricks
- Pitfalls & Gotchas
- Conditional Compilation Flags & Debugging Aids
🚀 To quickly start using OctopusKit with a template project, see QuickStart.
📖 To see how to do common tasks, check the Usage Guide.
Components not having any effect?
If the component has an
update(deltaTime:)method, make sure it’s registered with a Component System, or is manually updated during the scene’s
update(_:)method, and is only updated once! [TODO: make this automatic]
Does the entity have all the components that the non-functioning component depends on? A component’s dependencies must be added to the entity before the component that depends on them. [TODO: make this automatic]
Check the log.
Components having too much effect?
Make sure that a component is updated (if applicable) only once per frame.
Also make sure that a component system is added to a scene only once!
Gesture recognizer components not working?
- Check their properties for the minimum and maximum number of touches.
Scene, subscene or node not receiving input events?
- Check its
Remember to search the entire source code for
FIXME:etc. comments for any outstanding bugs and their temporary workarounds, if any.
In most cases, try to access the object hierarchy from the “bottom up” instead of “top down.”
Tips & Tricks
- Advanced: Including the OctopusKit code in your main project (instead of as a package dependency) may provide the benefits of Whole Module Optimization.
Pitfalls & Gotchas
- Many methods MUST be overridden in a subclass and/or chained to the superclass implementation, by calling
super.method(). Some methods should call
superat different points (i.e. beginning or end) in the subclass’ implementation. Unfortunately, there is no language-level support for enforcing that, so your best bet is to read the source and comments of the method you’re overriding.
💡 When in doubt, always call
super, and call it at the top of your overriding method.
TODO: make this chaining automatic/enforced when/if Swift supports it
- Components should try to perform their logic only during the
update(deltaTime:)methods. If a component’s behavior must be modified outside of those methods, use flags that are then acted upon in the component’s update method.
This ensures that a component does not affect anything outside of a frame update and can be reliably paused/unpaused.
Note that this does not mean that a component should not define any other methods at all.
Components that respond to asynchronous events, such as a component that moves a node based on input from a gesture recognizer, like
PanControlledRepositioningComponent, or networking components, MUST perform their function inside their
update(deltaTime:)method, and just use the event-handling action method to mark a flag to denote that an event was received.
This prevents the component from being active outside the frame-update cycle, or when it’s [temporarily] removed from the entity or the scene’s systems.
A SpriteKit scene processes touch and other input events outside of its
update(_:)method; when those event handlers update input-processing components, those components will (should) only be able to act on the input data during the scene’s
- OctopusKit components may sometimes cause some “friction” against the SpriteKit API.
e.g.: when adding a
PhysicsComponentto an entity; the SpriteKit node may have its own
PhysicsComponentmay have a different
As a general rule, adding a component to an entity assumes that the component adds its encapsulated functionality to that entity, replacing any identical functionality that already exists.
e.g.: If you add a “blank” component, e.g. a
physicsBody, then the component attempts to “adopt” any existing properties of the underlying SpriteKit object.
In this example, the blank
PhysicsComponentwill set its property to the
physicsBody, if any, of the
SpriteKitComponentnode. After that, other components should access the node’s physics properties through the
PhysicsComponentinstead of the node’s
Entities and components may not always be the answer to everything. Sometimes good old classes and structs may be the better solution. (^ - ^”)
- An entity can/should only have one component of a specific type (not counting generic variants.)
If an entity needs multiple components of the same type but with different parameters, consider using a “master” component that holds a collection of regular classes/struct.
e.g.: a ShipEntity with a WeaponsSystemComponent that holds an array of Gun classes/structs, to represent multiple guns where each gun is mounted on a different side of the ship.
Conditional Compilation Flags & Debugging Aids
Set these in the
Package.swiftmanifest for OctopusKit. Example:
targets: [ .target( name: "OctopusKit", dependencies: , swiftSettings[.define("LOGINPUTEVENTS")])
LOGECSVERBOSE- Logs detailed Entity-Component-System actions.
LOGINPUTEVENTS- Logs all input events and related information via the
LOGPHYSICS- Logs all physics contact/collision events.
⚠️ Setting any of the logging flags may reduce engine performance.
DISABLELOGCHANGES- Suppresses the
@LogChangesproperty modifier. May improve performance.
OctopusKit © 2019 Invading Octopus • Apache License 2.0