
เอ็นจิ้นเกม 2D ที่ใช้ ECS และเขียนด้วย 100% Swift สำหรับ iOS, MacOS, TVOS และ Visionos
คำเตือน
- โครงการนี้ไม่ได้รับการอัปเดตโดยผู้ดูแล แต่เพียงผู้เดียว
- ฉันย้ายไปที่ Godot ตรวจสอบ comedot ←กรอบการทำงานตามส่วนประกอบของฉันสำหรับเกม 2D ใน Godot!
สำคัญ
❕ Octopuskit ต้องการ octopuscore ฟังก์ชั่นที่ไม่ใช่เกมถูกแบ่งออกเป็นที่เก็บแยกต่างหากสำหรับใช้ในแอพทั่วไป สำหรับเวอร์ชันสแตนด์อโลนล่าสุดดู 4.0.0-beta-5
หากคุณได้ลองทำเกมอย่างรวดเร็วในขณะที่ติดกับ API อย่างเป็นทางการนี่อาจเหมาะกับคุณ! Octopuskit ห่อและขยายกรอบของ Apple:
• GamePlayKit สำหรับสถาปัตยกรรมระบบองค์ประกอบที่ยืดหยุ่นเพื่อเขียนพฤติกรรมของเกมแบบไดนามิก
• SpriteKit สำหรับกราฟิก 2D, ฟิสิกส์และ Shaders GPU
• Swiftui สำหรับการออกแบบของเหลวและปรับขนาดได้อย่างรวดเร็วด้วยไวยากรณ์ที่ประกาศ
• โลหะ เพื่อให้แน่ใจว่ามีประสิทธิภาพพื้นเมืองที่ดีที่สุดภายใต้ประทุน
•ส่วนประกอบที่ไม่ขึ้นกับระบบปฏิบัติการช่วยให้คุณจัดการเมาส์/สัมผัสหรือแป้นพิมพ์/อินพุตคีย์บอร์ด/gamepad ด้วยรหัสเดียวกันและรวบรวมโดยธรรมชาติสำหรับ iOS + macOS โดยไม่ต้องใช้ตัวเร่งปฏิกิริยา

Octopuskit เป็น งานที่อยู่ระหว่างดำเนินการ อย่างต่อเนื่องและฉันยังคงเรียนรู้เมื่อฉันไปดังนั้นมันอาจเปลี่ยนแปลงได้อย่างรวดเร็วโดยไม่ต้องรักษาความเข้ากันได้ย้อนหลังหรืออัปเดตเอกสาร
โครงการนี้เป็นผลมาจากความพยายามของฉันในการสร้างเกมใน Pure Swift ฉันตกหลุมรักภาษา แต่ไม่พบเครื่องยนต์ใด ๆ ที่สนับสนุนมันหรือมีสถาปัตยกรรมที่ฉันพบเข้าใจง่ายดังนั้นฉันจึงเริ่มทำเอง
ยินดีต้อนรับข้อเสนอแนะ! - Shinryakutako
กระตือรือร้นที่จะดำน้ำ? เพิ่ม Octopuskit เป็นตัวจัดการแพ็คเกจ Swift พึ่งพาโครงการ 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 และสร้างหลายเอนทิตีจากสไปรต์ที่ระบุด้วยชื่อที่ใช้ร่วมกัน
// 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" เดียวซึ่งจัดการเมนูหลักหยุดชั่วคราว cutscenes ฯลฯ
มุมมองของรัฐฉากและ Swiftui อาจมีความสัมพันธ์แบบหลายต่อหลายครั้งที่อาจเปลี่ยนแปลงในระหว่างการรันไทม์
- เอนทิตี เป็นเพียงคอลเลกชันของ ส่วนประกอบ พวกเขาไม่มีตรรกะยกเว้นตัวสร้างความสะดวกสบายซึ่งเริ่มต้นกลุ่มของส่วนประกอบที่เกี่ยวข้อง
- ส่วนประกอบ (ซึ่งอาจเรียกว่าพฤติกรรมเอฟเฟกต์คุณสมบัติหรือลักษณะ) เป็นแนวคิดหลักใน Octopuskit ที่มีคุณสมบัติเช่นเดียวกับตรรกะ* ซึ่งประกอบขึ้นเป็นองค์ประกอบภาพหรือนามธรรมของเกม ส่วนประกอบเรียกใช้รหัสเมื่อเพิ่มลงในเอนทิตีเมื่อมีการอัปเดตเฟรมและ/หรือเมื่อถูกลบออกจากเอนทิตี ส่วนประกอบอาจสอบถามเอนทิตีของพวกเขาสำหรับส่วนประกอบอื่น ๆ และส่งผลกระทบต่อพฤติกรรมของกันและกันเพื่อสร้างการพึ่งพาแบบไดนามิกในระหว่างการรันไทม์ เครื่องยนต์มาพร้อมกับไลบรารีส่วนประกอบที่ปรับแต่งได้สำหรับกราฟิกการเล่นเกมฟิสิกส์ ฯลฯ
⛓ ระบบ เป็นเพียงคอลเลกชันของส่วนประกอบ ของคลาสเฉพาะ พวกเขาไม่ได้ทำการตรรกะใด ๆ*แต่พวกเขาถูกจัดเรียงโดย ฉาก ในอาร์เรย์เพื่อดำเนินการส่วนประกอบจากเอนทิตีทั้งหมดตามลำดับที่กำหนดทุกเฟรมดังนั้นส่วนประกอบที่พึ่งพาส่วนประกอบอื่น ๆ จะได้รับการปรับปรุงหลังจากการพึ่งพาของพวกเขา
* คำจำกัดความเหล่านี้อาจแตกต่างจากเครื่องยนต์อื่น ๆ เช่นความสามัคคีซึ่งตรรกะทั้งหมดอยู่ในระบบ
- องค์ประกอบ ส่วนต่อประสานผู้ใช้ เช่นปุ่มรายการและ huds ได้รับการออกแบบใน Swiftui สิ่งนี้ช่วยให้ภาพเคลื่อนไหวของเหลวข้อความที่คมชัดรูปร่างเวกเตอร์ตัวอย่างสดการอัปเดตข้อมูลอัตโนมัติที่ขับเคลื่อนด้วยข้อมูลอัตโนมัติและไอคอนคุณภาพสูงกว่า 1,500 ไอคอนจากสัญลักษณ์ SF ของ Apple
ดูเอกสารประกอบสถาปัตยกรรมสำหรับรายละเอียดของลำดับชั้นของวัตถุ
เวิร์กโฟลว์หลักของคุณจะเขียนคลาสส่วนประกอบสำหรับแต่ละ "ส่วน" ของกราฟิกและการเล่นเกมจากนั้นรวมเข้าด้วยกันเพื่อสร้างเอนทิตีที่ปรากฏบนหน้าจอหรือหน่วยงานนามธรรมที่จัดการข้อมูลเกี่ยวกับ "แบ็กเอนด์"
เช่นพูดว่า parallaxbackgroundentity ที่มี cloudscomponent , hillscomponent และ treescomponent หรือ gamesessionEntity ที่มี worldmapcomponent และ multiplayersynccomponent
ประสิทธิภาพ: ถึงแม้ว่าการวัดประสิทธิภาพที่กว้างขวางยังไม่ได้ทำ แต่ OK สามารถแสดงสไป รต์ได้มากกว่า 5,000 ตัวบน iPhone XS ที่ 60 เฟรมต่อวินาที สไปรต์แต่ละตัวแสดงโดยเอนทิตีที่มีหลายองค์ประกอบที่ได้รับการปรับปรุงทุกเฟรมและตอบสนองต่อการสัมผัสอินพุต
เหมาะสำหรับ Swift : Swift, Swift, Swift! เฟรมเวิร์กจะต้องปฏิบัติตามแนวทางที่กำหนดไว้สำหรับการออกแบบ Swift API ทุกอย่างจะต้องสมเหตุสมผลภายใน Swift และ Flow อย่างราบรื่นด้วยสำนวนที่รวดเร็วที่สุดเท่าที่จะทำได้
วิตามิน 2D : ในขณะนี้ OK เป็นกรอบสำหรับเกม 2D แต่มันไม่ได้ป้องกันคุณจากการใช้เทคโนโลยีเช่น SceneKit หรือมุมมองโลหะระดับต่ำและอาจใช้สำหรับแอพที่ไม่ใช่เกม
ไหล่ของ Ettins : เครื่องยนต์ใช้ประโยชน์จาก Spritekit, GamePlaykit, Swiftui และเทคโนโลยีอื่น ๆ ที่ Apple จัดทำขึ้น ไม่ควรพยายาม "ต่อสู้" พวกเขาแทนที่พวกเขาหรือซ่อนพวกเขาไว้เบื้องหลังนามธรรมมากเกินไป
OK ส่วนใหญ่จะถูกนำไปใช้ผ่านคลาสย่อยที่กำหนดเองและส่วนขยายของคลาส SpriteKit และ GamePlaykit โดยไม่ต้อง "ปิดบัง" พวกเขาหรือปิดกั้นคุณจากการโต้ตอบกับคลาสพื้นฐาน สิ่งนี้ช่วยให้คุณสามารถนำเฟรมเวิร์กนี้มาใช้เพิ่มขึ้นและช่วยให้คุณรวมเกมของคุณเข้ากับเครื่องมือ XCode IDE เช่นตัวแก้ไขฉากที่เป็นไปได้
การมีเพศสัมพันธ์ที่แน่นหนากับ Apple APIs ยังช่วยให้มั่นใจได้ว่าเกมของคุณจะพิสูจน์ได้ในอนาคต เมื่อใดก็ตามที่ Apple ปรับปรุงเฟรมเวิร์กเหล่านี้ Octopuskit และเกมของคุณควรได้รับประโยชน์บางอย่าง "ฟรี" ตัวอย่างเช่นเมื่อมีการแนะนำโลหะ SpriteKit ได้รับการปรับปรุงให้ใช้โลหะโดยอัตโนมัติแทน OpenGL ภายใต้ประทุนทำให้เกมที่มีอยู่มากมายเพิ่มประสิทธิภาพ (WWDC 2016, เซสชั่น 610)
รหัสมาก่อน : OK เป็นเครื่องยนต์ "programmatical" เป็นหลัก เกือบทุกอย่างทำในรหัส นอกจากนี้ยังช่วยในการควบคุมแหล่งที่มา ตัวแก้ไขฉาก Xcode ถูกผลักไสให้อยู่ในสถานะ "พลเมืองชั้นสอง" เนื่องจากความไม่สมบูรณ์และข้อบกพร่อง (ณ เดือนพฤษภาคม 2018, Xcode 9.4) แต่ได้รับการสนับสนุนทุกที่ที่สะดวก ดูจุดต่อไป
คุณสามารถออกแบบเลย์เอาต์/เลย์เอาต์ระดับสูงในตัวแก้ไขฉากโดยใช้โหนดตัวยึดตำแหน่งที่มีชื่อ (ตัวระบุ) จากนั้นคุณอาจสร้างเอนทิตีจากโหนดเหล่านั้นและเพิ่มส่วนประกอบลงในรหัส
ขณะนี้ด้วย Swiftui การเขียนโปรแกรมสำหรับแพลตฟอร์ม Apple กำลังมุ่งเน้นไปที่รหัสแทนที่จะเป็นตัวแก้ไขภาพ
ความสามารถในการปรับแต่งและความยืดหยุ่น : เครื่องยนต์มุ่งมั่นที่จะยืดหยุ่นและให้อิสระในการจัดโครงสร้างเกมของคุณในรูปแบบต่างๆ เนื่องจากคุณสามารถเข้าถึงซอร์สโค้ดของเอ็นจิ้นได้อย่างเต็มที่คุณสามารถแก้ไขหรือขยายสิ่งใดให้เหมาะกับความต้องการที่แน่นอนของแต่ละโครงการ
คุณสามารถใช้วิธีการใด ๆ ต่อไปนี้ในการสร้างฉากของคุณตามลำดับการสนับสนุนเครื่องยนต์:
- ดำเนินการสร้างและวางตำแหน่งของโหนดส่วนใหญ่อยู่ในรหัส ใช้ XCode Scene Editor ไม่บ่อยนักเพื่อออกแบบและดูตัวอย่างองค์ประกอบบางอย่างเช่นเอนทิตีที่มีตำแหน่งเฉพาะ ฯลฯ ไม่ใช่ฉากทั้งหมดและใช้
SKReferenceNodeเพื่อโหลดในรหัส
- ใช้ตัวแก้ไขฉาก Xcode เป็นจุดเริ่มต้นของคุณเพื่อสร้างฉากเทมเพลตที่อาจโหลดเป็นอินสแตนซ์
SKReferenceNodeระดับบนสุดของOKSceneวิธีการนี้ช่วยให้การออกแบบภาพและการดูตัวอย่าง "WYSIWYG"
- สร้างฉากเกือบทั้งหมดในตัวแก้ไขฉาก Xcode เพิ่มส่วนประกอบที่รองรับการกระทำร่างกายฟิสิกส์กราฟการนำทางและพื้นผิว ฯลฯ ใน IDE
ตั้งค่าคลาสที่กำหนดเองของฉากเป็นOKSceneหรือคลาสย่อยของมัน โหลดฉากโดยเรียกOKViewController.loadAndPresentScene(fileNamed:withTransition:)เช่นระหว่างdidEnter.from(_:)เหตุการณ์ของOKGameState
- คุณไม่ จำเป็น ต้องใช้สถาปัตยกรรมและรูปแบบใด ๆ ที่แนะนำที่นี่ คุณไม่จำเป็นต้องใช้สถานะของเกมและวัตถุเกมของคุณไม่จำเป็นต้องสืบทอดจากคลาส OK ใด ๆ คุณสามารถใช้สถาปัตยกรรมของคุณเองและใช้ OK สำหรับวิธีการของผู้ช่วยสองสามวิธี ฯลฯ รักษาเฉพาะสิ่งที่คุณต้องการจากเฟรมเวิร์กนี้และไม่รวมส่วนที่เหลือจากการรวบรวม
ตัวตนของตนเอง : คุณไม่จำเป็นต้องดาวน์โหลดหรือติดตามห้องสมุดบุคคลที่สามอื่น ๆ หากโครงการของคุณไม่ต้องการพวกเขา ทุกสิ่งที่ OK ใช้อยู่ภายใน OK หรือ Apple Frameworks ดังนั้นจึงสามารถใช้งานได้อย่างเต็มที่นอกกรอบ
อ่านคู่มือ quickstart และการใช้งาน คุณจะต้องใช้ Xcode 12, iOS 14 และ MacOS Big Sur (แม้ว่า OK อาจใช้งานได้กับรุ่นเก่าด้วยการปรับเปลี่ยนด้วยตนเองบางอย่าง)
ระดับทักษะ: ระดับกลาง : แม้ว่าตกลงจะไม่ได้นำเสนอในรูปแบบที่ออกแบบมาสำหรับผู้เริ่มต้นสัมบูรณ์ส่วนใหญ่เป็นเพราะฉันขี้เกียจเกินไปที่จะเขียนเอกสารจากขั้นตอนที่ศูนย์ แต่ก็ไม่ใช่ "ขั้นสูง" หากคุณได้อ่านหนังสือภาษาที่รวดเร็วและพยายามสร้างเกม SpriteKit ใน XCode คุณพร้อมที่จะใช้ OK!
คุณควรอ่านเกี่ยวกับรูปแบบ "องค์ประกอบเหนือมรดก" และ "เอนทิตี - องค์ประกอบ - ระบบ" หากคุณยังไม่คุ้นเคยกับแนวคิดเหล่านั้นแม้ว่าการใช้งานของ OK อาจแตกต่างจากที่คุณคาดหวัง
ดูบทเรียนของ Apple สำหรับ Swiftui
สำหรับภาพรวมโดยละเอียดของสถาปัตยกรรมของเครื่องยนต์ดูสถาปัตยกรรม
ติดอยู่? ดูเคล็ดลับและการแก้ไขปัญหา
สงสัยว่ามีบางสิ่งที่จงใจทำอย่างที่เป็นอยู่หรือทำไม? การเขียนโค้ดการประชุมและการตัดสินใจออกแบบอาจมีคำอธิบาย
ต้องการติดตามสิ่งที่กำลังจะมาถึงหรือช่วยในการพัฒนาคุณสมบัติที่ขาดหายไป? ดูสิ่งที่ต้องทำและแผนงาน
ผู้สนับสนุนและผู้สนับสนุน❤︎
โครงการนี้อาจเรียกว่า Octopuskit, "OK" หรือ "OKIO" (สำหรับ "Octopuskit โดยการบุกรุก Octopus") แต่ "Iook" ฟังดูแปลก ๆ
การตั้งชื่อเป็นการผสมผสานของแรงบันดาลใจจาก บริษัท ต่างๆเช่น Rogue Amoeba,. io Domain และอะนิเมะ Shinryaku! Ika Musume
พื้นที่ก่อนหน้านี้ ]) ในส่วนตัวอย่างมีไว้เพื่อความชัดเจน -
ใบอนุญาต: Apache 2.0
รวม Shaders จาก Shaderkit © Paul Hudson ที่ได้รับใบอนุญาตภายใต้ใบอนุญาต MIT (ดูส่วนหัวในไฟล์ที่เกี่ยวข้อง)
บอก ฉันทีว่าทุกอย่างยอดเยี่ยมหรือน่ากลัวแค่ไหน: Discord, Twitter หรือ?
ฉันไม่ค่อยตรวจสอบสิ่งเหล่านี้ดังนั้นวิธีที่ดีที่สุดในการถามคำถามอาจผ่านการเปิดปัญหาในที่เก็บ GitHub
สนับสนุน วิถีชีวิตที่เสื่อมโทรมของฉันเพื่อที่ฉันจะได้มุ่งเน้นไปที่การทำสิ่งที่ไม่สามารถขายได้: Patreon ของฉัน
โครงการนี้ไม่ได้เป็นพันธมิตรกับ Apple
Octopuskit © 2023 บุก Octopus • Apache License 2.0