
一个基于ECS的2D游戏引擎,并用100%Swift为iOS,MacOS,TVOS和Visionos编写。
警告
?该项目不再由唯一的维护者更新。
?我搬到了戈多。查看Comedot ←我在Godot的2D游戏的基于组件的框架!
重要的
❕章鱼需要章鱼。非游戏功能被分为一个单独的存储库,以供一般应用中使用。有关最后一个独立版本,请参见4.0.0-Beta-5
如果您在坚持官方API时尝试在Swift制作游戏,这可能适合您! Octopuskit包裹并扩展了Apple的框架:
•对于灵活的实体 - 组件系统体系结构的GamePlayKit ,可以动态构成游戏行为。
•用于2D图形,物理和GPU着色器的SpriteKit 。
• SwiftUI用于快速设计具有声明语法的流体,可扩展的HUD。
•金属以确保引擎盖下的最佳本地性能。
•独立于OS的组件,您可以使用相同的代码处理鼠标/触摸或键盘/GAMEPAD输入,并为iOS + MacOS本地编译而无需催化剂。

Octopuskit是一项不断的工作,我仍在学习,因此它可能会迅速变化而不维护向后兼容或更新文档。
这个项目是我尝试将游戏制作纯Swift的结果。我爱上了这种语言,但找不到任何支持它的引擎或发现直觉的建筑,所以我开始制作自己的。
欢迎反馈! - Shinryakutako
渴望潜水吗?将Octopuskit作为Swift Package Manager依赖性添加到SwiftUI项目中,并使用QuickStart模板(也可以用作一个小演示。)。
?与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 )
}
}?创建动画精灵
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 " ) ] )?添加播放器控件
// 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 ( ) ] )?动态删除播放器控制或更改为其他输入方法
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 ( ) ] )?定制游戏的组件
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
}
}?使用自定义闭合根据玩家运动更改动画
// 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.?加载Xcode场景编辑器内置的场景并从共享名称标识的Sprites创建多个实体
// 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使用“实体 - 组件系统”体系结构,其中:
?游戏被组织成Mainmenu等州,玩耍和暂停。每个状态都与显示用户界面的SwiftUI视图相关联,以及使用实体,组件和系统为该状态提供游戏玩法的SpriteKit场景。
您可以根据需要将游戏分为多数或很少的状态。例如,一个“ Playstate”也可以处理主菜单,暂停,过场动画等。
各州,场景和Swiftui视图可能在运行时可能会发生多种关系。
?实体只是组件的集合。它们不包含逻辑,除了便利构造函数初始化相关组件的组。
?组成部分(也可以称为行为,效果,特征或特征)是Octopuskit中的核心概念,其中包含属性以及构成游戏中每个视觉或抽象元素的逻辑*。当组件添加到实体,更新帧时和/或将其从实体中删除时,将其代码运行。组件可能会查询其实体对其他组件,并影响彼此的行为,以在运行时形成动态依赖性。该引擎配备了用于图形,游戏玩法,物理等的可自定义组件库。
⛓系统只是特定类的组件的集合。他们没有执行任何逻辑*,但是它们由数组中的场景安排,以确定性顺序从所有帧中执行所有实体的组件,因此依赖其他组件的组件在其依赖项之后会更新。
*这些定义可能与其他引擎(例如Unity)不同,其中所有逻辑都包含在系统中。
?用户界面元素(例如按钮,列表和HUD)在SwiftUI中设计。这允许流体动画,清晰的文本,矢量形状,实时预览,自动数据驱动的更新以及苹果SF符号的1,500多个高质量图标。
有关对象层次结构的详细分解,请参见架构文档。
您的主要工作流程将为图形和游戏玩法的每个“部分”编写组件类,然后将它们组合在一起,以构建出现在屏幕上的实体,或者在“后端”上处理数据的抽象实体。
例如,说一个包含云的component , hillscomponent和treescomponent或包含WorldMapComponent和多人游戏的游戏性的视差。
性能:尽管尚未完成广泛的基准测试,但OK可以以每秒60帧的速度在iPhone XS上显示超过5000个精灵;每个精灵由一个实体表示,每个帧都会更新每个帧,并响应触摸输入。
为Swift量身定制:Swift,Swift,Swift!该框架必须遵循Swift API设计的既定准则。一切都必须在Swift中有意义,并且尽可能多地使用Swift Idioms无缝地流动。
维生素2D :目前,OK主要是2D游戏的框架,但它并不能阻止您使用Scenekit或低级金属视图之类的技术,并且可以用于非游戏应用程序。
Ettins的肩膀:发动机利用SpriteKit,GamePlayKit,Swiftui和Apple提供的其他技术。它不应尝试“与他们进行战斗”,更换它们或将它们隐藏在太多的抽象后面。
OK主要是通过自定义子类和SpriteKit和GamePlayKit类的扩展来实现的,而不会“掩盖”它们或阻止您与基础类互动。这使您可以逐步采用此框架,并让您在可能的情况下将游戏与Xcode IDE工具(例如场景编辑器)集成在一起。
与Apple API的紧密耦合也确保您的游戏是防前的;每当苹果改进这些框架时,Actopuskit和您的游戏也应该“免费”获得一些好处。例如,当引入金属时,SpriteKit被更新以自动使用金属而不是openGL在引擎盖下,从而使许多现有的游戏都提高了性能。 (WWDC 2016,第610节)
代码首先出现:确定主要是“编程”引擎;几乎所有内容都是用代码完成的。这也有助于源控制。 Xcode场景编辑器由于其不完整和错误(截至2018年5月,Xcode 9.4)而被降级为“二等公民”状态,但在方便的情况下得到支持。请参阅下一点。
您可以在场景编辑器中设计高级布局/模型,使用带有名称的占位符节点(标识符。)然后,您可以从这些节点创建实体,并在代码中添加组件。
现在,有了Swiftui,Apple平台编程即将重点关注代码,而不是视觉编辑器。
可定制性和灵活性:发动机努力保持灵活性,并为您提供以各种方式构建游戏的自由。由于您可以完全访问引擎的源代码,因此可以修改或扩展任何内容以满足每个项目的确切需求。
您可以根据引擎支持顺序使用以下任何方法来构建场景:
- 主要在代码中执行节点的创建和放置。不经常使用Xcode场景编辑器来设计和预览一些单独的元素,例如具有特定位置等的实体,而不是整个场景,并使用
SKReferenceNode将它们加载到代码中。
- 使用Xcode场景编辑器作为起点,创建可能加载的模板场景,以作为
OKScene的顶级SKReferenceNode实例加载。这种方法允许“ Wysiwyg”视觉设计和预览。
- 在Xcode场景编辑器中几乎完全创建场景,添加了IDE中的任何受支持的组件,动作,物理体,导航图和纹理等。
将场景的自定义类设置为OKScene或IT的子类。通过调用OKViewController.loadAndPresentScene(fileNamed:withTransition:),例如在didEnter.from(_:)OKGameState的事件中,加载场景。
- 您不必使用此处建议的任何架构和模式;您不必使用游戏状态,并且您的游戏对象甚至不必从任何确定的类中继承。您可以使用自己的体系结构,只需将OK用于几种辅助方法等,仅保留此框架所需的东西,而将其余的排除在汇编之外。
自我范围:如果您自己的项目不需要它们,则不需要下载或跟上任何其他第三方库;确定使用的所有内容都在确定或Apple Framework中,因此它可以完全可用。
阅读快速启动和使用指南。您将需要Xcode 12,iOS 14和Macos Big Sur(尽管可以使用一些手动修改的旧版本。)
技能级别:中级:尽管没有以专为绝对初学者设计的形式出现,这主要是因为我懒得从步骤零来编写文档,但它也不是“高级”级别的内容;如果您已经阅读了Swift语言书,并试图用Xcode制作SpriteKit游戏,则可以使用OK!
如果您还不熟悉这些概念,那么您还应该阅读有关“继承的组成”和“实体 - 组件 - 系统”模式,尽管OK的实现可能与您的期望有所不同。
另请参阅苹果的Swiftui教程。
有关引擎架构的详细概述,请参见体系结构。
卡住?请参阅提示和故障排除。
想知道是否有意按照自己的方式完成某事?编码约定和设计决策可能有解释。
是否想了解即将发生的事情或帮助丢失功能的发展?请参阅托多和路线图。
贡献者和支持者❤︎
该项目可以称为章鱼,“ OK”或“ OKIO”(对于“ Incopuskit in Inting Octopus”),但“ Iook”听起来很奇怪。
命名是来自Rogue Amoeba,.io Domain和Anime Shinryaku等公司的灵感的结合! ika妈妈。
示例部分中最后一个])空间是为了清晰。 :)
许可证:Apache 2.0
合并了ShaderKit的着色器©Paul Hudson,根据MIT许可证获得许可(请参阅相关文件中的标题)。
告诉我一切有多棒或可怕:Discord,Twitter或?ctopus?it@?nvading?
我很少检查这些问题,因此提出问题的最佳方法可能是通过在GitHub存储库上打开问题。
支持我decade废的生活方式,这样我就可以专注于制作不足的东西:我的patreon
该项目与苹果没有任何隶属关系。
Octopuskit©2023入侵章鱼•Apache许可证2.0