
Un motor de juego 2D basado en ECS y escrito en 100% Swift para iOS, MacOS, TVOS y Visisos.
Precaución
? El único mantenedor ya no actualiza este proyecto.
? Me he mudado a Godot. ¡Mira Comedot ← Mi marco basado en componentes para juegos 2D en Godot!
Importante
❕ Octopuskit requiere octoposcoro. La funcionalidad que no es de juego se dividió en un repositorio separado para su uso en aplicaciones generales. Para la última versión independiente, consulte 4.0.0-beta-5
Si has intentado hacer un juego en Swift mientras te quedas con las API oficiales, ¡esto puede ser para ti! Octopuskit envuelve y extiende los marcos de Apple:
• Gameplaykit para una arquitectura de sistema de componente de entidad flexible para componer dinámicamente el comportamiento del juego.
• Spritekit para gráficos 2D, física y sombreadores de GPU.
• Swiftui para diseñar rápidamente HUD fluidos y escalables con una sintaxis declarativa.
• Metal para garantizar el mejor rendimiento nativo debajo del capó.
• Los componentes independientes del sistema operativo le permiten manejar la entrada de mouse/tacto o teclado/gamepad con el mismo código, y compilar de forma nativa para iOS + macOS sin necesidad de catalizador.

Octopuskit es un trabajo constante en progreso y todavía estoy aprendiendo a medida que avanzo, por lo que puede cambiar rápidamente sin mantener la compatibilidad al revés o la actualización de la documentación.
Este proyecto es el resultado de mis intentos de hacer juegos en Pure Swift. Me enamoré del lenguaje, pero no pude encontrar ningún motor que lo apoyara o tuviera el tipo de arquitectura que encontré intuitiva, así que comencé a hacer el mío.
¡Comentarios bienvenidos! - Shinryakutako
Ansioso por bucear? Agregue Octopuskit como una dependencia de Swift Package Manager a un proyecto Swiftui y use la plantilla QuickStart (que también sirve como una pequeña demostración).
? Usando con 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 )
}
}? Creando un sprite animado
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 " ) ] )? Agregar control de jugador
// 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 ( ) ] )? Eliminar dinámicamente el control del jugador o cambiar a un método de entrada diferente
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 componente específico del juego personalizado
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
}
}? Uso de un cierre personalizado para cambiar la animación basada en el movimiento del jugador
// 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.? Cargando una escena construida en el editor de escenas Xcode y creando múltiples entidades de sprites identificados por un nombre compartido
// 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 utiliza una arquitectura "entidad-componente-sistema", donde:
? Un juego se organiza en estados como Mainmenu , jugando y se detiene . Cada estado está asociado con una vista Swiftui que muestra la interfaz de usuario, y una escena de SpriteKit que presenta el juego para ese estado utilizando entidades , componentes y sistemas .
Puedes dividir tu juego en tantos o tan pocos estados como quieras. por ejemplo, un solo "PlayState" que también maneja el menú principal, pausas, escenas, etc.
Los estados, las escenas y las opiniones de Swiftui pueden tener relaciones de muchos a muchos que pueden cambiar durante el tiempo de ejecución.
? Las entidades son simplemente colecciones de componentes . No contienen lógica, excepto los constructores de conveniencia que inicializan grupos de componentes relacionados.
? Los componentes (que también podrían llamarse comportamientos, efectos, características o rasgos) son el concepto central en Octopuskit, que contiene las propiedades y la lógica* que componen cada elemento visual o abstracto del juego. Un componente ejecuta su código cuando se agrega a una entidad, cuando se actualiza un marco y/o cuando se elimina de una entidad. Los componentes pueden consultar su entidad para otros componentes y afectar el comportamiento de los demás para formar dependencias dinámicas durante el tiempo de ejecución. El motor viene con una biblioteca de componentes personalizables para gráficos, juego, física, etc.
⛓ Los sistemas son simplemente colecciones de componentes de una clase específica. No realizan ninguna lógica*, pero una escena está organizada en una matriz para ejecutar componentes de todas las entidades en un orden determinista en cada cuadro, de modo que los componentes que se basan en otros componentes se actualizan después de sus dependencias.
* Estas definiciones pueden diferir de otros motores, como la unidad, donde toda la lógica está contenida dentro de los sistemas.
? Los elementos de la interfaz de usuario , como botones, listas y HUD, están diseñados en Swiftui . Esto permite animaciones de fluidos, texto afilado, formas vectoriales, vistas previas en vivo, actualizaciones automáticas basadas en datos y más de 1,500 iconos de alta calidad de los símbolos SF de Apple.
Consulte la documentación de la arquitectura para obtener un desglose detallado de la jerarquía de objetos.
Su flujo de trabajo principal será escribir clases de componentes para cada "parte" de los gráficos y el juego, luego combinarlas para construir entidades que aparecen en pantalla o entidades abstractas que manejan datos en el "backend".
Por ejemplo, dice una atención de paralaje que contiene un componente de nubes , un componente de colinas y un componente de árboles , o un gamenSessionIdity que contiene un componente mundial y un componente multijugador .
Rendimiento: aunque aún no se han realizado puntos de referencia extensos, OK puede mostrar más de 5000 sprites en un iPhone XS a 60 cuadros por segundo ; Cada sprite representado por una entidad con múltiples componentes actualizados en cada cuadro y que responde a la entrada táctil.
A medida para Swift : Swift, Swift, Swift! El marco debe seguir las pautas establecidas para el diseño de la API Swift. Todo debe tener sentido dentro de Swift y fluir a la perfección con modismos rápidos tanto como sea posible.
Vitamina 2D : en este momento, OK es principalmente un marco para los juegos 2D, pero no le impide usar tecnologías como ScineKit o Vistas de metal de bajo nivel, y puede usarse para aplicaciones no juegos.
Hombros de Ettins : el motor aprovecha SpriteKit, Gameplaykit, Swiftui y otras tecnologías proporcionadas por Apple. No debe tratar de "lucharlos", reemplazarlos o ocultarlos detrás de demasiadas abstracciones.
OK se implementa principalmente a través de subclases y extensiones personalizadas de las clases de SpriteKit y Gameplaykit, sin "oscurecerlos" o bloquearlo de interactuar con las clases base. Esto le permite adoptar este marco de forma incremental, y le permite integrar su juego con las herramientas IDE XCode como el editor de escenas cuando sea posible.
El acoplamiento apretado con las API de Apple también asegura que su juego sea a prueba de futuro; Cada vez que Apple mejora estos marcos, Octopuskit y sus juegos también deberían obtener algunos beneficios "gratis". Por ejemplo, cuando se introdujo el metal, Spritekit se actualizó para usar automáticamente el metal en lugar de OpenGL debajo del capó, dando a muchos juegos existentes un impulso de rendimiento. (WWDC 2016, sesión 610)
El código es lo primero : OK es principalmente un motor "programático"; Casi todo se hace en código. Esto también ayuda con el control de la fuente. El editor de la escena de Xcode se relega al estado de "ciudadano de segunda clase" debido a su incompletitud y errores (a partir de mayo de 2018, Xcode 9.4), pero es compatible donde sea conveniente. Ver el siguiente punto.
Puede diseñar diseños/maquetas de alto nivel en el editor de escenas, utilizando nodos de marcador de posición con nombres (identificadores). Luego puede crear entidades de esos nodos y agregarles componentes en código.
Ahora con Swiftui, la programación para las plataformas Apple se dirige hacia un enfoque en el código en lugar de los editores visuales de todos modos.
Personalización y flexibilidad : el motor se esfuerza por ser flexible y le brinda la libertad de estructurar su juego de varias maneras. Dado que tiene acceso completo al código fuente del motor, puede modificar o extender cualquier cosa para satisfacer las necesidades exactas de cada proyecto.
Puede usar cualquiera de los siguientes enfoques para construir sus escenas, en orden de soporte del motor:
- Realice la creación y colocación de nodos principalmente en código. Use el editor de escenas Xcode con poca frecuencia, para diseñar y obtener una vista previa de algunos elementos individuales, como entidades con posiciones específicas, etc., no escenas completas, y use
SKReferenceNodepara cargarlos en código.
- Use el editor de escenas Xcode como punto de partida, para crear escenas de plantilla que puedan cargarse como instancias
SKReferenceNodede nivel superior de unOKScene. Este enfoque permite un mínimo de diseño visual "wysiwyg".
- Cree una escena casi por completo en el editor de escenas Xcode, agregando cualquier componente compatible, acciones, cuerpos de física, gráficos de navegación y texturas, etc. Justo en el IDE.
Establezca la clase personalizada de la escena comoOKSceneo una subclase de ella. Cargue la escena llamandoOKViewController.loadAndPresentScene(fileNamed:withTransition:), por ejemplo, durante el eventodidEnter.from(_:)de unOKGameState.
- No tiene que usar ninguna de las arquitecturas y patrones sugeridos aquí; No tienes que usar los estados de juego, y tus objetos de juego ni siquiera tienen que heredar de ninguna clase OK. Puede usar su propia arquitectura y simplemente usar OK para algunos métodos de ayuda, etc., manteniendo solo lo que necesita de este marco y excluyendo el resto de la compilación.
Continutación de autosuficiencia : no debe descargar o mantenerse al día con otras bibliotecas de terceros si su propio proyecto no las requiere; Todo lo que OK usa está dentro de los marcos OK o Apple, por lo que se usa completamente fuera de la caja.
Lea la guía de uso rápido y de uso. Necesitará Xcode 12, iOS 14 y MacOS Big Sur (aunque OK puede funcionar en versiones anteriores con algunas modificaciones manuales).
Nivel de habilidad: Intermedio : aunque OK no se presenta en una forma diseñada para principiantes absolutos, principalmente porque soy demasiado vago para escribir documentación del paso cero, tampoco es material de nivel "avanzado"; Si has leído el libro de idiomas Swift e intenta hacer un juego de SpriteKit en Xcode, ¡estás listo para usar OK!
También debe leer sobre los patrones de "composición sobre herencia" y "entidad -componente -sistema" si aún no está familiarizado con esos conceptos, aunque la implementación de estos de OK puede ser diferente de lo que espera.
Vea también los tutoriales de Apple para Swiftui.
Para obtener una descripción detallada de la arquitectura del motor, ver arquitectura.
¿Atascado? Ver consejos y solución de problemas.
¿Se pregunta si algo se hizo intencionalmente como es o por qué? Convenciones de codificación y decisiones de diseño pueden tener una explicación.
¿Quieres vigilar lo que viene o ayudar con el desarrollo de las características faltantes? Ver el TODO & Roadmap.
Colaboradores y seguidores ❤︎
Este proyecto puede referirse como Octopuskit, "Ok" o "Okio" (para "Octopuskit invadiendo el pulpo") pero "IOOK" suena raro.
¡El nombramiento es una combinación de inspiración de compañías como Rogue Amoeba, el dominio .io y el anime Shinryaku! Ika Musume .
El espacio antes del último ]) en la sección Ejemplos es para mayor claridad. :)
Licencia: Apache 2.0
Incorpora sombreadores de Shaderkit © Paul Hudson, con licencia bajo la licencia MIT (ver encabezados en archivos relevantes).
Dime lo increíble o terrible que es todo: Discord, Twitter o ?Ctopus?it@?nvading?CTOPUS.ⓘⓞ
Sin embargo, rara vez lo reviso, por lo que la mejor manera de hacer una pregunta puede ser abrir un problema en el repositorio de GitHub.
Apoya mi estilo de vida decadente para que pueda concentrarme en hacer cosas insalicables: mi patreon
Este proyecto no está afiliado de ninguna manera con Apple.
Octopuskit © 2023 Invading Octopus • Licencia de Apache 2.0