
Un moteur de jeu 2D basé sur ECS et écrit en 100% Swift pour iOS, MacOS, TVOS et VisionOS.
Prudence
? Ce projet n'est plus mis à jour par le seul mainteneur.
? J'ai déménagé à Godot. Découvrez COMEDOT ← Mon framework basé sur les composants pour les jeux 2D dans Godot!
Important
❕ Octopuskit nécessite OctopUCCore. La fonctionnalité non-jeu a été divisée en un référentiel distinct pour une utilisation dans les applications générales. Pour la dernière version autonome, voir 4.0.0-beta-5
Si vous avez essayé de faire un jeu à Swift tout en vous en tendant aux API officielles, cela peut être pour vous! Octopuskit s'enroule et étend les frameworks d'Apple:
• Gameplaykit pour une architecture entité-composante-système flexible pour composer dynamiquement le comportement de jeu.
• Spritekit pour les graphiques 2D, la physique et les shaders GPU.
• Swiftui pour concevoir rapidement des HUD fluide et évolutifs avec une syntaxe déclarative.
• Métal pour assurer la meilleure performance native sous le capot.
• Les composants indépendants du système d'exploitation vous permettent de gérer l'entrée de souris / tactile ou de clavier / manche de jeu avec le même code et de compiler nativement pour iOS + macOS sans avoir besoin de catalyseur.

Octopuskit est un travail constant en cours et j'apprends toujours au fur et à mesure, il peut donc changer rapidement sans maintenir la compatibilité en arrière ni mettre à jour la documentation.
Ce projet est le résultat de mes tentatives de faire des jeux en pur rapide. Je suis tombé amoureux de la langue mais je n'ai trouvé aucun moteur qui le soutenait ou qui avait le genre d'architecture que j'ai trouvé intuitif, alors j'ai commencé à faire le mien.
Retour bienvenue! - Shinryakutako
Désireux de plonger? Ajoutez Octopuskit en tant que dépendance Swift Package Manager à un projet Swiftui et utilisez le modèle QuickStart (qui sert également de démo.)
? En utilisant avec 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 )
}
}? Création d'un sprite animé
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 " ) ] )? Ajout de contrôle des joueurs
// 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 ( ) ] )? Suppression dynamique du contrôle des joueurs ou passant à une autre méthode d'entrée
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 ( ) ] )? Un composant spécifique au jeu personnalisé
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
}
}? Utilisation d'une fermeture personnalisée pour changer l'animation en fonction du mouvement des joueurs
// 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.? Chargement d'une scène construite dans l'éditeur de scène Xcode et créant plusieurs entités à partir de sprites identifiés par un nom partagé
// 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 utilise une architecture "entité-composant-système", où:
? Un jeu est organisé en États tels que MainMenu , jouant et arrêté . Chaque état est associé à une vue Swiftui qui affiche l'interface utilisateur et une scène Spritekit qui présente le gameplay pour cet état à l'aide d'entités , de composants et de systèmes .
Vous pouvez diviser votre jeu en autant ou aussi peu d'états que vous le souhaitez. par exemple un seul "État placée" qui gère également le menu principal, une pause, des cinématiques, etc.
Les États, les scènes et les vues Swiftui peuvent avoir des relations multiples à plusieurs qui peuvent changer pendant l'exécution.
? Les entités ne sont que des collections de composants . Ils ne contiennent aucune logique, sauf pour les constructeurs de commodité qui initialisent des groupes de composants associés.
? Les composants (qui pourraient également être appelés comportements, effets, caractéristiques ou traits) sont le concept principal de Octopuskit, contenant les propriétés ainsi que la logique * qui constituent chaque élément visuel ou abstrait du jeu. Un composant exécute son code lorsqu'il est ajouté à une entité, lorsqu'un cadre est mis à jour et / ou lorsqu'il est supprimé d'une entité. Les composants peuvent interroger leur entité pour d'autres composants et affecter le comportement de l'autre pour former des dépendances dynamiques pendant l'exécution. Le moteur est livré avec une bibliothèque de composants personnalisables pour les graphiques, le gameplay, la physique, etc.
⛓ Les systèmes sont simplement des collections de composants d'une classe spécifique. Ils n'effectue aucune logique *, mais ils sont disposés par une scène dans un tableau pour exécuter des composants de toutes les entités dans un ordre déterministe à chaque trame, de sorte que les composants qui reposent sur d'autres composants sont mis à jour après leurs dépendances.
* Ces définitions peuvent différer des autres moteurs, comme l'unité, où toute la logique est contenue dans les systèmes.
? Des éléments d'interface utilisateur comme les boutons, les listes et les HUD sont conçus dans Swiftui . Cela permet des animations fluides, du texte nette, des formes de vecteur, des aperçus en direct, des mises à jour automatiques basées sur les données et plus de 1 500 icônes de haute qualité des symboles SF d'Apple.
Voir la documentation de l'architecture pour une ventilation détaillée de la hiérarchie des objets.
Votre flux de travail principal sera d'écrire des classes de composants pour chaque "partie" des graphiques et du gameplay, puis de les combiner pour créer des entités qui apparaissent à l'écran, ou des entités abstraites qui gèrent les données sur le "backend".
Par exemple, disons une parallaxbackgroundtentity contenant un CloudsComponent , un HillsComponent et uncomponent d'arbres , ou une GamesesSessentity contenant uncomposant WorldMapComponent et un multijoueur .
Performances: Bien que les références étendues n'aient pas encore été réalisées, OK peut afficher plus de 5000 sprites sur un iPhone XS à 60 images par seconde ; Chaque sprite représenté par une entité avec plusieurs composants étant mis à jour à chaque trame et répondant à l'entrée tactile.
Tadavé pour Swift : Swift, Swift, Swift! Le cadre doit suivre les directives établies pour la conception de l'API rapide. Tout doit avoir du sens dans Swift et Flow de manière transparente avec des idiomes rapides autant que possible.
Vitamine 2D : Pour le moment, OK est principalement un cadre pour les jeux 2D, mais il ne vous empêche pas d'utiliser des technologies comme SceneKit ou des vues de métal de bas niveau, et il peut être utilisé pour les applications non-jeu.
Épaules d'Ettins : Le moteur exploite Spritekit, Gameplaykit, Swiftui et d'autres technologies fournies par Apple. Il ne devrait pas essayer de les "combattre", de les remplacer ou de les cacher derrière trop d'abstractions.
OK est principalement implémenté via des sous-classes personnalisées et des extensions des classes Spritekit et Gameplaykit, sans les "obscurcir" ou vous empêcher d'interagir avec les classes de base. Cela vous permet d'adopter ce cadre progressivement et vous permet d'intégrer votre jeu avec les outils Xcode IDE tels que l'éditeur de scène lorsque cela est possible.
Le couplage serré avec les API de pomme garantit également que votre jeu est à l'épreuve des futurs; Chaque fois qu'Apple améliore ces cadres, Octopuskit et vos jeux devraient également obtenir des avantages "gratuitement". Par exemple, lorsque le métal a été introduit, Spritekit a été mis à jour pour utiliser automatiquement le métal au lieu d'OpenGL sous le capot, donnant à de nombreux jeux existants une augmentation des performances. (WWDC 2016, session 610)
Le code vient en premier : OK est principalement un moteur "programmatique"; Presque tout est fait dans le code. Cela aide également au contrôle de la source. L'éditeur de scène Xcode est relégué au statut de "citoyen de deuxième classe" en raison de son incomplétude et de ses bugs (en mai 2018, Xcode 9.4), mais il est pris en charge où que ce soit est pratique. Voir le point suivant.
Vous pouvez concevoir des dispositions / maquettes de haut niveau dans l'éditeur de scène, en utilisant des nœuds d'espace pour noms (identificateurs.) Vous pouvez ensuite créer des entités à partir de ces nœuds et y ajouter des composants dans le code.
Maintenant, avec Swiftui, la programmation pour les plates-formes Apple se dirige vers le code au lieu des éditeurs visuels de toute façon.
Personnalisation et flexibilité : le moteur s'efforce d'être flexible et vous donne la liberté de structurer votre jeu de diverses manières. Étant donné que vous avez un accès complet au code source du moteur, vous pouvez modifier ou étendre n'importe quoi pour répondre aux besoins exacts de chaque projet.
Vous pouvez utiliser l'une des approches suivantes pour construire vos scènes, par ordre de support du moteur:
- Effectuez la création et le placement des nœuds principalement dans le code. Utilisez rarement l'éditeur de scène Xcode, pour concevoir et prévisualiser quelques éléments individuels tels que des entités avec des positions spécifiques, etc., pas des scènes entières, et utilisez
SKReferenceNodepour les charger en code.
- Utilisez l'éditeur de scène Xcode comme point de départ, pour créer des scènes de modèle qui peuvent être chargées comme des instances
SKReferenceNodede niveau supérieur d'unOKScene. Cette approche permet un minimum de conception visuelle "Wysiwyg" et de prévisualisation.
- Créez une scène presque entièrement dans l'éditeur de scène Xcode, en ajoutant tous les composants pris en charge, les actions, les corps de physique, les graphiques de navigation et les textures, etc. dans l'IDE.
Définissez la classe personnalisée de la scène en tantOKSceneou une sous-classe de celui-ci. Chargez la scène en appelantOKViewController.loadAndPresentScene(fileNamed:withTransition:), par exemple pendant ledidEnter.from(_:)événement d'unOKGameState.
- Vous n'avez pas besoin d'utiliser les architectures et les modèles suggérés ici; Vous n'avez pas besoin d'utiliser des états de jeu et vos objets de jeu n'ont même pas à hériter des classes OK. Vous pouvez utiliser votre propre architecture et utiliser OK pour quelques méthodes d'assistance, etc., en gardant uniquement ce dont vous avez besoin de ce cadre et en excluant le reste de la compilation.
Auto-contoration : vous ne devriez pas avoir besoin de télécharger ou de suivre d'autres bibliothèques tierces si votre propre projet ne les nécessite pas; Tout ce que OK utilise est dans les frameworks OK ou Apple, donc il est entièrement utilisable à l'extérieur de la boîte.
Lisez le guide QuickStart et Utilisation. Vous aurez besoin de Xcode 12, iOS 14 et MacOS Big Sur (bien que OK puisse fonctionner sur des versions plus anciennes avec des modifications manuelles.)
Niveau de compétence: Intermédiaire : Bien que OK ne soit pas présenté sous une forme conçue pour les débutants absolus, principalement parce que je suis trop paresseux pour écrire la documentation de l'étape zéro, ce n'est pas non plus des trucs "avancés"; Si vous avez lu le Swift Language Book et que vous avez tenté de faire un jeu Spritekit dans Xcode, vous êtes prêt à utiliser OK!
Vous devez également lire sur les modèles "Composition sur l'héritage" et "Entity-Component-System" si vous n'êtes pas déjà familier avec ces concepts, bien que la mise en œuvre d'OK soit différente de ce que vous attendez.
Voir également les tutoriels d'Apple pour Swiftui.
Pour un aperçu détaillé de l'architecture du moteur, voir l'architecture.
Bloqué? Voir Conseils et dépannage.
Vous vous demandez si quelque chose était intentionnellement fait tel qu'il est, ou pourquoi? Les conventions de codage et les décisions de conception peuvent avoir une explication.
Vous voulez garder un œil sur ce qui se passe ou aider avec le développement de fonctionnalités manquantes? Voir la feuille de route et de route.
Contributeurs et supporters ❤︎
Ce projet peut être appelé Octopuskit, "OK" ou "Okio" (pour "Octopuskit en envahissant Octopus") mais "iook" semble bizarre.
La dénomination est une combinaison d'inspiration de sociétés comme Rogue Amoeba, le domaine .io et l'anime shinryaku! Ika Musume .
L'espace avant le dernier ]) dans la section Exemples est pour plus de clarté. :)
Licence: Apache 2.0
Incorpore les shaders de Shaderkit © Paul Hudson, sous licence MIT (voir les en-têtes dans les fichiers pertinents).
Dites -moi à quel point tout est génial ou terrible: Discord, Twitter ou ?ctopus?it@?nvading?ctopus.ⓘⓞ
Je les vérifie rarement, donc la meilleure façon de poser une question peut être en ouvrant un problème sur le référentiel GitHub.
Soutenez mon style de vie décadent pour que je puisse me concentrer sur la fabrication de trucs invendables: mon Patreon
Ce projet n'est pas affilié à Apple.
Octopuskit © 2023 Invasing Octopus • Licence Apache 2.0