
محرك لعبة ثنائية الأبعاد يعتمد على ECS وكُتب في سويفت بنسبة 100 ٪ لنظام التشغيل iOS و MacOS و TVOS و VisionOS.
حذر
؟ لم يعد هذا المشروع قد تم تحديثه من قبل المشرف الوحيد.
؟ لقد انتقلت إلى جودو. تحقق من Comedot ← إطار عمل المكونات الخاص بي للألعاب ثنائية الأبعاد في Godot!
مهم
❕ Octopuskit يتطلب Octopuscore. تم تقسيم وظائف غير اللعبة إلى مستودع منفصل للاستخدام في التطبيقات العامة. للاطلاع على آخر نسخة مستقلة ، انظر 4.0.0-beta-5
إذا كنت قد حاولت صنع لعبة في Swift أثناء التمسك بواجهة برمجة التطبيقات الرسمية ، فقد يكون هذا لك! يلف Octopuskit ويمتد أطر Apple:
• GameplayKit للهندسة المعمارية للهيكل المرن لكيان من العناصر لتأليف سلوك اللعبة ديناميكيًا.
• SpriteKit للرسومات ثنائية الأبعاد والفيزياء وتظليلات GPU.
• Swiftui لتصميم السوائل بسرعة ، HUDs قابلة للتطوير مع بناء جملة التصريحي.
• المعادن لضمان أفضل أداء محلي تحت الغطاء.
• تتيح لك المكونات المستقلة عن نظام التشغيل التعامل مع إدخال الماوس/اللمس أو لوحة المفاتيح/لوحة الألعاب بنفس الرمز ، وتجميعها أصليًا لـ iOS + MacOS دون الحاجة إلى CATALYST.

يعتبر Octopuskit عملًا مستمرًا مستمرًا وما زلت أتعلم كما أذهب ، لذلك قد يتغير بسرعة دون الحفاظ على التوافق للخلف أو تحديث الوثائق.
هذا المشروع هو نتيجة محاولاتي لجعل الألعاب في Pure Swift. لقد وقعت في حب اللغة ، لكنني لم أتمكن من العثور على أي محركات دعمتها أو كانت لدي نوع من الهندسة المعمارية التي وجدتها بديهية ، لذلك بدأت في صنع بلدي.
ردود الفعل مرحبًا! - Shinryakutako
حريصة على الغوص؟ أضف Octopuskit كاعتماد على مدير الحزمة السريع لمشروع 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" واحد يتولى القائمة الرئيسية ، والتوقف ، والقطعة ، إلخ.
قد يكون للدول والمشاهد ووجهات النظر Swiftui علاقات كثيرة قد تتغير أثناء وقت التشغيل.
؟ الكيانات هي ببساطة مجموعات من المكونات . أنها لا تحتوي على منطق ، باستثناء المُنشئين الذين يهيئون مجموعات من المكونات ذات الصلة.
؟ المكونات (التي يمكن أن تسمى أيضًا السلوكيات أو التأثيرات أو الميزات أو السمات) هي المفهوم الأساسي في Octopuskit ، التي تحتوي على الخصائص وكذلك المنطق* الذي يشكل كل عنصر بصري أو مجردة للعبة. يقوم المكون بتشغيل الكود الخاص به عند إضافته إلى كيان ، عند تحديث إطار ، و/أو عند إزالته من كيان. قد تستفسر المكونات كيانها عن المكونات الأخرى وتؤثر على سلوك بعضها البعض لتشكيل تبعيات ديناميكية أثناء وقت التشغيل. يأتي المحرك مع مكتبة من المكونات القابلة للتخصيص للرسومات واللعب والفيزياء وما إلى ذلك.
⛓ الأنظمة هي ببساطة مجموعات من مكونات فئة معينة. إنهم لا يؤدون أي منطق*، لكنهم مرتبة بواسطة مشهد في صفيف لتنفيذ مكونات من جميع الكيانات بترتيب حتمي في كل إطار ، بحيث يتم تحديث المكونات التي تعتمد على المكونات الأخرى بعد تبعياتها.
* قد تختلف هذه التعريفات عن المحركات الأخرى ، مثل الوحدة ، حيث يوجد كل المنطق داخل الأنظمة.
؟ تم تصميم عناصر واجهة المستخدم مثل الأزرار والقوائم و HUDs في Swiftui . يتيح ذلك الرسوم المتحركة السوائل والنص الحاد وأشكال المتجهات والمعاينات المباشرة والتحديثات التلقائية التي تعتمد على البيانات وأكثر من 1500 أيقونات عالية الجودة من رموز SF من Apple.
راجع وثائق الهندسة المعمارية للحصول على انهيار مفصل للتسلسل الهرمي للكائن.
سيقوم سير العمل الأساسي بك بكتابة فصول مكون لكل "جزء" من الرسومات واللعب ، ثم الجمع بينها لإنشاء كيانات تظهر على الشاشة ، أو الكيانات المجردة التي تتعامل مع البيانات على "الخلفية".
على سبيل المثال ، قل parallaxbackentity التي تحتوي على مكون من الغيوم ، مكون من HillsComponent و TreesComponent ، أو ألعاب تحتوي على مكون عالمي ومكون متعدد اللاعبين .
الأداء: على الرغم من أن المعايير الواسعة لم يتم القيام بها بعد ، إلا أن OK يمكن أن تعرض أكثر من 5000 من العفاريت على جهاز iPhone XS في 60 إطارًا في الثانية ؛ كل العفريت يمثله كيان مع تحديث مكونات متعددة كل إطار ، والاستجابة لمدخلات اللمس.
مصممة لسرعة : سريعة ، سريعة ، سريعة! يجب أن يتبع الإطار الإرشادات المعمول بها لتصميم SWIFT API. كل شيء يجب أن يكون منطقيًا داخل سريع ويتدفق بسلاسة مع التعابير السريعة قدر الإمكان.
فيتامين 2D : في الوقت الحالي ، يعد OK في المقام الأول إطارًا للألعاب ثنائية الأبعاد ، لكنه لا يمنعك من استخدام تقنيات مثل المشاهدات المعدنية ذات المستوى المنخفض أو منخفضة المستوى ، وقد يتم استخدامه للتطبيقات غير المباشرة.
أكتاف Ettins : يقوم المحرك بتعزيز SpriteKit و GameplayKit و Swiftui وغيرها من التقنيات التي توفرها Apple. لا ينبغي أن تحاول "محاربتهم" ، أو استبدالها ، أو إخفاءها وراء الكثير من التجريدات.
يتم تنفيذ OK في الغالب من خلال فئات فرعية مخصصة وملحقات من فصول spritekit و gameplaykit ، دون "حجبها" أو منعك من التفاعل مع الفئات الأساسية. يتيح لك ذلك تبني هذا الإطار بشكل تدريجي ، ويتيح لك دمج لعبتك مع أدوات Xcode IDE مثل محرر المشهد حيثما أمكن ذلك.
يضمن الاقتران الضيق مع Apple APIs أيضًا أن تكون لعبتك مقاومة في المستقبل ؛ عندما تحسن Apple هذه الأطر ، يجب أن تحصل Octopuskit وألعابك أيضًا على بعض الفوائد "مجانًا". على سبيل المثال ، عندما تم تقديم Metal ، تم تحديث SpriteKit لاستخدام المعادن تلقائيًا بدلاً من OpenGL تحت الغطاء ، مما يمنح العديد من الألعاب الحالية زيادة في الأداء. (WWDC 2016 ، الجلسة 610)
يأتي الرمز أولاً : OK هو في المقام الأول محرك "برمجي" ؛ يتم كل شيء تقريبًا في الكود. هذا يساعد أيضا مع التحكم في المصدر. تم ترحيل محرر مشهد Xcode إلى حالة "المواطن من الدرجة الثانية" بسبب عدم اكتماله وخلله (اعتبارًا من مايو 2018 ، Xcode 9.4) ، لكنه مدعوم أينما كان مناسبًا. انظر النقطة التالية.
يمكنك تصميم تخطيطات/مستويات عالية المستوى في محرر المشهد ، باستخدام العقد النائبة مع أسماء (معرفات). يمكنك بعد ذلك إنشاء كيانات من تلك العقد وإضافة مكونات إليها في التعليمات البرمجية.
الآن مع Swiftui ، تتجه البرمجة لمنصات Apple نحو التركيز على الكود بدلاً من المحررين البصريين على أي حال.
التخصيص والمرونة : يسعى المحرك إلى أن يكون مرنًا ويمنحك الحرية في تنظيم لعبتك بطرق مختلفة. نظرًا لأن لديك وصولًا كاملاً إلى التعليمات البرمجية المصدر للمحرك ، يمكنك تعديل أو تمديد أي شيء لتناسب الاحتياجات الدقيقة لكل مشروع.
يمكنك استخدام أي من الأساليب التالية لبناء مشاهدك ، حسب ترتيب دعم المحرك:
- أداء إنشاء العقد ووضعها في الغالب في الكود. استخدم محرر مشهد Xcode بشكل غير متكرر ، لتصميم ومعاينة بعض العناصر الفردية مثل الكيانات ذات المواقف المحددة وما إلى ذلك ، وليس المشاهد بأكملها ، واستخدم
SKReferenceNodeلتحميلها في التعليمات البرمجية.
- استخدم محرر مشهد Xcode كنقطة انطلاق ، لإنشاء مشاهد قالب يمكن تحميلها
OKSceneSKReferenceNodeذات المستوى الأعلى. يسمح هذا النهج بتعديل التصميم المرئي "WysiWyg".
- قم بإنشاء مشهد بالكامل تقريبًا في محرر مشهد Xcode ، وإضافة أي مكونات مدعومة ، والإجراءات ، وأجسام الفيزياء ، والرسوم البيانية للتنقل والقوام وما إلى ذلك في IDE.
اضبط الفئة المخصصة للمشهد على أنهOKSceneأو فئة فرعية منه. قم بتحميل المشهد عن طريق الاتصالOKViewController.loadAndPresentScene(fileNamed:withTransition:)، على سبيل المثال خلالdidEnter.from(_:)حدثOKGameState.
- ليس عليك استخدام أي من البنية والأنماط المقترحة هنا ؛ ليس عليك استخدام حالات اللعبة ، ولا يتعين على كائنات اللعبة حتى أن ترث من أي فئات موافق. يمكنك استخدام الهندسة المعمارية الخاصة بك ، واستخدام موافق فقط لعدد قليل من أساليب المساعد وما إلى ذلك ، مع الحفاظ على ما تحتاجه فقط من هذا الإطار واستبعاد الباقي من التجميع.
الاستفتاء الذاتي : يجب ألا تحتاج إلى تنزيل أو مواكبة أي مكتبات أخرى من الطرف الثالث إذا كان مشروعك لا يتطلبها ؛ كل ما يستخدمه موافق هو ضمن أطر عمل OK أو Apple ، لذلك يصبح قابلاً للاستخدام بالكامل خارج الصندوق.
اقرأ دليل QuickStart and Usage. ستحتاج إلى Xcode 12 و iOS 14 و MacOS Big Sur (على الرغم من أن موافق قد يعمل على الإصدارات القديمة مع بعض التعديلات اليدوية.)
مستوى المهارة: وسيط : على الرغم من عدم تقديم OK في شكل مصمم للمبتدئين المطلقين ، في الغالب لأنني كسول جدًا في كتابة وثائق من الخطوة صفر ، إلا أنها ليست "متطورة" لأشياء المستوى أيضًا ؛ إذا كنت قد قرأت كتاب اللغة السريعة وحاولت إنشاء لعبة spriteKit في Xcode ، فأنت مستعد لاستخدام موافق!
يجب عليك أيضًا أن تقرأ عن أنماط "التكوين على الميراث" و "الكيان والمكون - نظام" إذا لم تكن على دراية بهذه المفاهيم ، على الرغم من أن تنفيذ OK لهذه قد يكون مختلفًا عما تتوقعه.
انظر أيضًا دروس Apple لـ Swiftui.
للحصول على نظرة عامة مفصلة على بنية المحرك ، انظر العمارة.
عالق؟ انظر النصائح واستكشاف الأخطاء وإصلاحها.
أتساءل عما إذا كان هناك شيء ما تم ذلك عن عمد كما هو ، أو لماذا؟ قد يكون لاتفاقيات الترميز وقرارات التصميم شرح.
هل تريد الاحتفاظ بعلامات التبويب على ما سيحدث أو يساعد في تطوير الميزات المفقودة؟ انظر Todo & Roadmap.
المساهمون والمؤيدون ❤︎
يمكن الإشارة إلى هذا المشروع باسم Octopuskit أو "OK" أو "Okio" (لـ "Octopuskit عن طريق غزو الأخطبوط") ولكن يبدو "iook" غريبًا.
التسمية هي مزيج من الإلهام من شركات مثل Rogue Amoeba ، ومجال .io ، و shinryaku الأنيمي! إيكا موسوم .
المساحة قبل الأخير ]) في قسم الأمثلة هي للوضوح. سائدا
الترخيص: Apache 2.0
يتضمن تظليل من Shaderkit © Paul Hudson ، المرخص له بموجب ترخيص MIT (انظر الرؤوس في الملفات ذات الصلة).
أخبرني كم هو رائع أو فظيع: Discord ، Twitter or ؟ctopus؟it@؟nvading؟ctopus.ⓘⓞ
نادراً ما أتحقق من ذلك ، لذا فإن أفضل طريقة لطرح سؤال قد تكون من خلال فتح مشكلة في مستودع GitHub.
دعم نمط حياتي المنحطي حتى أتمكن من التركيز على صنع أشياء غير قابلة للتغيير: Patreon الخاص بي
لا ينتم هذا المشروع بأي شكل من الأشكال مع Apple.
Octopuskit © 2023 غزو الأخطبوط • ترخيص Apache 2.0