
A 2D game engine based on ECS and written in 100% Swift for iOS, macOS, tvOS and visionOS.
Vorsicht
? This project is no longer updated by the sole maintainer.
? Ich bin nach Godot gezogen. Check out Comedot ← my components-based framework for 2D games in Godot!
Wichtig
❕ OctopusKit requires OctopusCore. Non-game functionality was split into a separate repository for use in general apps. Für die letzte eigenständige Version finden Sie 4.0.0-beta-5
If you've tried making a game in Swift while sticking to the official APIs, this may be for you! OctopusKit wraps and extends Apple's frameworks:
• Gameplaykit für eine flexible Entitätskomponenten-System-Architektur, um das Spielverhalten dynamisch zu komponieren.
• SpriteKit for 2D graphics, physics and GPU shaders.
• SwiftUI for quickly designing fluid, scalable HUDs with a declarative syntax.
• Metal to ensure the best native performance under the hood.
• Mit OS-unabhängigen Komponenten können Sie Maus/Touch- oder Tastatur-/Gamepad-Eingaben mit demselben Code verarbeiten und nativ für iOS + macOS kompilieren, ohne einen Katalysator zu benötigen.

Octopuskit ist eine ständige Arbeit in Arbeit, und ich lerne immer noch, wie ich gehe, so dass es sich schnell ändern kann, ohne die Kompatibilität rückwärts zu behalten oder die Dokumentation zu aktualisieren.
This project is the result of my attempts to make games in pure Swift. Ich verliebte mich in die Sprache, konnte aber keine Motoren finden, die sie unterstützten, oder hatte die Art von Architektur, die ich intuitiv fand, also begann ich meine eigenen zu machen.
Feedback welcome! - Shinryakutako
Eager to dive in? Fügen Sie Octopuskit als Abhängigkeit von Swift Paket Manager zu einem Swiftui -Projekt hinzu und verwenden Sie die QuickStart -Vorlage (die auch als kleine Demo dient).
? Verwendung mit Swiftui
import SwiftUI
import OctopusKit
struct ContentView : View {
// The coordinator object manages your game's scenes and global state.
@ StateObject var gameCoordinator = OKGameCoordinator ( states : [
MainMenu ( ) ,
Lobby ( ) ,
Gameplay ( ) ] )
var body : some View {
// The container view combines SpriteKit with SwiftUI,
// and presents the coordinator's current scene.
OKContainerView ( )
. environmentObject ( gameCoordinator )
. statusBar ( hidden : true )
}
}? Creating an animated sprite
var character = OKEntity ( components : [
// Start with a blank texture.
NodeComponent ( node : SKSpriteNode ( color : . clear , size : CGSize ( widthAndHeight : 42 ) ) ) ,
// Load texture resources.
TextureDictionaryComponent ( atlasName : " PlayerCharacter " ) ,
// Animate the sprite with textures whose names begin with the specified prefix.
TextureAnimationComponent ( initialAnimationTexturePrefix : " Idle " ) ] )? Hinzufügen von Spielersteuerung
// Add a component to the scene that will be updated with input events.
// Other components that handle player input will query this component.
// This lets us handle asynchronous events in sync with the frame-update cycle.
// A shared event stream is more efficient than forwarding events to every entity.
// PointerEventComponent is an OS-agnostic component for touch or mouse input.
let sharedPointerEventComponent = PointerEventComponent ( )
scene . entity ? . addComponent ( sharedPointerEventComponent )
character . addComponents ( [
// A relay component adds a reference to a component from another entity,
// and also fulfills the dependencies of other components in this entity.
RelayComponent ( for : sharedPointerEventComponent ) ,
// This component checks the entity's PointerEventComponent (provided here by a relay)
// and syncs the entity's position to the touch or mouse location in every frame.
PointerControlledPositioningComponent ( ) ] )? Dynamisches Entfernen der Spielersteuerung oder das Wechsel zu einer anderen Eingabemethode
character . removeComponent ( ofType : PointerControlledPositioningComponent . self )
character . addComponents ( [
// Add a physics body to the sprite.
PhysicsComponent ( ) ,
RelayComponent ( for : sharedKeyboardEventComponent ) ,
// Apply a force to the body based on keyboard input in each frame.
KeyboardControlledForceComponent ( ) ] )? Eine benutzerdefinierte spielspezifische Komponente
class AngryEnemyComponent : OKComponent , RequiresUpdatesPerFrame {
override func didAddToEntity ( withNode node : SKNode ) {
node . colorTint = . angryMonster
}
override func update ( deltaTime seconds : TimeInterval ) {
guard let behaviorComponent = coComponent ( EnemyBehaviorComponent . self ) else { return }
behaviorComponent . regenerateHP ( )
behaviorComponent . chasePlayerWithExtraFervor ( )
}
override func willRemoveFromEntity ( withNode node : SKNode ) {
node . colorTint = . mildlyInconveniencedMonster
}
}? Using a custom closure to change the animation based on player movement
// Add a component that executes the supplied closure every frame.
character . addComponent ( RepeatingClosureComponent { component in
// Check if the entity of this component has the required dependencies at runtime.
// This approach allows dynamic behavior modification instead of halting the game.
if let physicsBody = component . coComponent ( PhysicsComponent . self ) ? . physicsBody ,
let animationComponent = component . coComponent ( TextureAnimationComponent . self )
{
// Change the animation depending on whether the body is stationary or mobile.
animationComponent . textureDictionaryPrefix = physicsBody . isResting ? " Idle " : " Moving "
}
} )
// This behavior could be better encapsulated in a custom component,
// with many different game-specific animations depending on many conditions.? Laden einer Szene, die im Xcode -Szene -Editor eingebaut ist und mehrere Entitäten aus Sprites erstellen, die durch einen gemeinsamen Namen identifiziert wurden
// Load a ".sks" file as a child node.
if let editorScene = SKReferenceNode ( fileNamed : " EditorScene.sks " ) {
scene . addChild ( editorScene )
}
// Search the entire tree for all nodes named "Turret",
// and give them properties of "tower defense" turrets,
// and make them independently draggable by the player.
for turretNode in scene [ " //Turret " ] {
// Create a new entity for each node found.
scene . addEntity ( OKEntity ( components : [
NodeComponent ( node : turretNode ) ,
RelayComponent ( for : sharedPointerEventComponent ) ,
// Hypothetical game-specific components.
HealthComponent ( ) ,
AttackComponent ( ) ,
MonsterTargetingComponent ( ) ,
// Track the first touch or mouse drag that begins inside the sprite.
NodePointerStateComponent ( ) ,
// Let the player select and drag a specific sprite.
// This differs from the PointerControlledPositioningComponent in a previous example,
// which repositions nodes regardless of where the pointer began.
PointerControlledDraggingComponent ( ) ] ) )
}
// Once the first monster wave starts, you could replace PointerControlledDraggingComponent
// with PointerControlledShootingComponent to make the turrets immovable but manually-fired.Octopuskit verwendet eine Architektur "Entity-Component-System", wobei:
? Ein Spiel ist in Staaten wie Mainmenu , Spielen und Pause organisiert. Jeder Status ist einer Swiftui -Ansicht zugeordnet, in der die Benutzeroberfläche angezeigt wird, und einer Spritekit -Szene , in der das Gameplay für diesen Status mithilfe von Entitäten , Komponenten und Systemen vorgestellt wird.
Sie können Ihr Spiel in so viele oder so wenige Staaten unterteilen, wie Sie möchten. eg A single "PlayState" which also handles the main menu, pausing, cutscenes etc.
States, Scenes, and SwiftUI views may have many-to-many relationships that may change during runtime.
? Entitäten sind einfach Sammlungen von Komponenten . They contain no logic, except for convenience constructors which initialize groups of related components.
? Komponenten (die auch als Verhalten, Effekte, Merkmale oder Merkmale bezeichnet werden können) sind das Kernkonzept im Octopuskit, das die Eigenschaften sowie die Logik* enthält, aus denen jedes visuelle oder abstrakte Element des Spiels besteht. A component runs its code when it's added to an entity, when a frame is updated, and/or when it's removed from an entity. Komponenten können ihre Entität für andere Komponenten abfragen und das Verhalten des anderen beeinflussen, um während der Laufzeit dynamische Abhängigkeiten zu bilden. Die Engine verfügt über eine Bibliothek mit anpassbaren Komponenten für Grafiken, Gameplay, Physik usw.
⛓ Systeme sind einfach Sammlungen von Komponenten einer bestimmten Klasse. Sie führen keine Logik aus*, aber sie sind von einer Szene in einem Array angeordnet, um Komponenten von allen Entitäten in einer deterministischen Reihenfolge in jedem Rahmen auszuführen, sodass Komponenten, die auf anderen Komponenten angewiesen sind, nach ihren Abhängigkeiten aktualisiert werden.
* Diese Definitionen können sich von anderen Motoren unterscheiden, wie die Einheit, bei denen die gesamte Logik in Systemen enthalten ist.
? Benutzeroberflächenelemente wie Schaltflächen, Listen und HUDs sind in Swiftui gestaltet. Dies ermöglicht fließende Animationen, scharfe Text, Vektorformen, Live-Vorschau, automatische datengesteuerte Updates und über 1.500 hochwertige Symbole von Apples SF-Symbolen.
In der Architekturdokumentation finden Sie eine detaillierte Aufschlüsselung der Objekthierarchie.
Ihr primärer Workflow schreibt Komponentenklassen für jeden "Teil" der Grafik und des Gameplays und kombiniert sie dann, um Entitäten zu erstellen, die auf dem Bildschirm erscheinen, oder abstrakte Entitäten, die Daten zum "Backend" verarbeiten.
z. B. eine Parallaxbackgroundentität , die eine Cloudscomponent , einen Hillscomponent und eine Bäume enthält, oder eine Gamesessionentity mit einem Weltmapkomponenten und einem MultiplayerSyncccomponent .
Leistung: Obwohl umfangreiche Benchmarks noch nicht durchgeführt wurden, kann OK über 5000 Sprites auf einem iPhone XS mit 60 Bildern pro Sekunde über 5000 Sprites angezeigt werden. Jedes Sprite wird von einer Entität dargestellt, in der mehrere Komponenten auf jedem Frame aktualisiert werden, und reagieren auf den Berührungseingang.
Für Swift zugeschnitten : Swift, Swift, Swift! Der Rahmen muss den festgelegten Richtlinien für das Swift -API -Design folgen. Alles muss in schnellem Sinn machen und mit schnellen Redewendungen so weit wie möglich nahtlos fließen.
Vitamin 2D : Im Moment ist OK in erster Linie ein Framework für 2D-Spiele, verhindern jedoch nicht, dass Sie Technologien wie Szenenkit oder Metallansichten auf niedriger Ebene verwenden, und es kann für Nicht-Spiel-Apps verwendet werden.
Schultern von Ettins : Der Motor nutzt Spritekit, Gameplaykit, Swiftui und andere von Apple bereitgestellte Technologien. Es sollte nicht versuchen, sie zu "kämpfen", sie zu ersetzen oder sie hinter zu vielen Abstraktionen zu verbergen.
OK wird hauptsächlich durch benutzerdefinierte Unterklassen und Erweiterungen von Spritekit- und Gameplaykit -Klassen implementiert, ohne sie zu "verdecken" oder Sie daran zu hindern, mit den Basisklassen zu interagieren. Auf diese Weise können Sie dieses Framework inkrementell übernehmen und Ihr Spiel nach Möglichkeit in die Xcode -IDE -Tools wie den Szenenditor integrieren.
Die enge Kopplung mit Apple APIs stellt auch sicher, dass Ihr Spiel zukunftssicher ist. Immer wenn Apple diese Frameworks verbessert, sollten Octopuskit und Ihre Spiele auch einige Vorteile "kostenlos" erhalten. Als Metall beispielsweise eingeführt wurde, wurde Spritekit aktualisiert, um Metal anstelle von OpenGL unter der Motorhaube automatisch zu verwenden, was vielen vorhandenen Spielen einen Leistungssteiger erzielt. (WWDC 2016, Sitzung 610)
Der Code kommt zuerst : OK ist in erster Linie eine "programmatische" Engine. Fast alles wird im Code gemacht. Dies hilft auch bei der Quellenkontrolle. Der Xcode-Szenen-Editor wird aufgrund seiner Unvollständigkeit und Fehler (bis Mai 2018, Xcode 9.4) in den Status "zweiter Klasse" verwiesen, wird jedoch überall unterstützt. Siehe den nächsten Punkt.
Sie können hochrangige Layouts/Modelle im Szeneneditor entwerfen, wobei Sie Platzhalterknoten mit Namen (Bezeichnungen) verwenden.
Mit Swiftui fällt das Programmieren für Apple -Plattformen sowieso auf einen Fokus auf Code anstelle von visuellen Redaktoren.
Anpassbarkeit und Flexibilität : Der Motor ist bestrebt, flexibel zu sein, und bietet Ihnen die Freiheit, Ihr Spiel auf verschiedene Weise zu strukturieren. Da Sie vollen Zugriff auf den Quellcode der Engine haben, können Sie alles ändern oder erweitern, um den genauen Anforderungen jedes Projekts zu entsprechen.
Sie können die folgenden Ansätze zum Aufbau Ihrer Szenen in der Reihenfolge der Motorunterstützung verwenden:
- Führen Sie die Erstellung und Platzierung von Knoten hauptsächlich im Code durch. Verwenden Sie den Xcode -Szeneneditor selten, um einige einzelne Elemente wie Entitäten mit bestimmten Positionen usw. zu entwerfen und anzunehmen, nicht in ganze Szenen, und verwenden Sie
SKReferenceNode, um sie in Code zu laden.
- Verwenden Sie den Xcode-Szeneneditor als Ausgangspunkt, um Vorlagenszenen zu erstellen, die möglicherweise als
SKReferenceNodeInstanzen auf oberster Ebene einerOKScenegeladen werden. Dieser Ansatz ermöglicht ein Modicum von "Wysiwyg" visuellem Design und Vorschau.
- Erstellen Sie eine Szene, die fast ausschließlich im Xcode -Szene -Editor ist, und fügen Sie alle unterstützten Komponenten, Aktionen, Physikkörper, Navigationsgraphen und Texturen usw. hinzu.
Stellen Sie die benutzerdefinierte Klasse der Szene alsOKSceneoder als Unterklasse davon fest. Laden Sie die Szene, indem SieOKViewController.loadAndPresentScene(fileNamed:withTransition:), zB während derdidEnter.from(_:)Ereignis einesOKGameState.
- Sie müssen keine der hier vorgeschlagenen Architekturen und Muster verwenden. Sie müssen keine Spielstaaten verwenden, und Ihre Spielobjekte müssen nicht einmal von OK -Klassen erben. Sie können Ihre eigene Architektur verwenden und nur OK für ein paar Helfermethoden usw. verwenden, nur das, was Sie benötigen, von diesem Rahmen und den Rest von der Kompilierung ausschließen.
Selbstversorgung : Sie sollten keine anderen Bibliotheken von Drittanbietern herunterladen oder Schritt halten müssen, wenn Ihr eigenes Projekt sie nicht benötigt. Alles, was OK verwendet, ist in OK- oder Apple Frameworks, sodass es vollständig nutzbar ist.
Lesen Sie den QuickStart- und Verwendungshandbuch. Sie benötigen Xcode 12, iOS 14 und MacOS Big Sur (obwohl OK möglicherweise bei älteren Versionen mit manuellen Änderungen funktioniert.)
Skill Level: Intermediate : Obwohl OK nicht in einem Formular für absolute Anfänger präsentiert wird, hauptsächlich weil ich zu faul bin, um Dokumentation aus Schritt Null zu schreiben, ist es auch nicht "erweitert". Wenn Sie das Swift Language Book gelesen und versucht haben, in Xcode ein Spritekit -Spiel zu erstellen, sind Sie bereit, OK zu verwenden!
Sie sollten auch über die "Komposition über Vererbung" und "Entity -Component -System" -Muster lesen, wenn Sie mit diesen Konzepten noch nicht vertraut sind, obwohl die Umsetzung von OK von diesen möglicherweise anders sein kann als das, was Sie erwarten.
Siehe auch Apples Tutorials für Swiftui.
Eine detaillierte Übersicht über die Architektur des Motors finden Sie unter Architecture.
Gesteckt? Siehe Tipps und Fehlerbehebung.
Sie fragen sich, ob etwas absichtlich so getan wurde, wie es ist oder warum? Codierungskonventionen und Entwurfsentscheidungen können eine Erklärung haben.
Möchten Sie im Auge behalten, was kommt oder mit der Entwicklung fehlender Funktionen helfen? Sehen Sie die Todo & Roadmap.
Mitwirkende und Unterstützer ❤︎
Dieses Projekt kann als Octopuskit, "OK" oder "Okio" bezeichnet werden (für "Octopuskit durch Eindringen von Octopus"), aber "iook" klingt seltsam.
Die Benennung ist eine Kombination aus Inspiration von Unternehmen wie Rogue Amoeba, The .io Domain und dem Anime Shinryaku! Ika Musume .
Der Raum vor dem letzten ]) ist im Abschnitt Beispiele für Klarheit. :)
Lizenz: Apache 2.0
Enthält Shader aus Shaderkit © Paul Hudson, lizenziert unter MIT -Lizenz (siehe Header in relevanten Dateien).
Sag mir, wie großartig oder schrecklich alles ist: Discord, Twitter oder ?Ctopus?it@?nvading?ctopus.ⓘⓞ
Ich überprüfe diese jedoch selten. Der beste Weg, eine Frage zu stellen, kann darin bestehen, ein Problem im Github -Repository zu eröffnen.
Unterstützen Sie meinen dekadenten Lebensstil, damit ich mich darauf konzentrieren kann, unverdscheidbare Sachen zu machen: mein Patreon
Dieses Projekt ist in keiner Weise mit Apple verbunden.
Octopuskit © 2023 Eindringlicher Oktopus • Apache -Lizenz 2.0