هذه هي الحلقة
الخامسة من سلسلة دروس الـ Cocos2D
لإستنساخ لعبة الحشرة إلى iOS
(أي-او-إس).
قبل أن تبدء في هذا الدرس تأكد من أنك قد أكملت الأجزاء السابقة.فى المرة السابقة تناقشنا فى موضوع AI of the caterpillar وتعلمنا كيف نحرك caterpillar خلال حقل الانبات وحدود المستوى.
فى درس اليوم سنقفز فى كل أنحاء اللعبة ونتناقش حول حركة اللاعب و وإطلاق الصواريخ.
قبل أن تبدء في هذا الدرس تأكد من أنك قد أكملت الأجزاء السابقة.فى المرة السابقة تناقشنا فى موضوع AI of the caterpillar وتعلمنا كيف نحرك caterpillar خلال حقل الانبات وحدود المستوى.
فى درس اليوم سنقفز فى كل أنحاء اللعبة ونتناقش حول حركة اللاعب و وإطلاق الصواريخ.
الخطوة الأولى: التحكم باللاعب.
التحكم باللاعب
بسيط وسهل إلى حد ما, أول شيء يتعين علينا القيام به هو أن نخبر طبقة لعبتنا لتطبيق اللمسات من أجل التفاعل معها. أضف الكود التالى الى GameLayer.m: بطريقة init الخاصة بك:
[[CCTouchDispatcher sharedDispatcher] addTargetedDelegate:self priority:0 swallowsTouches:YES];
كما رأيتم فى الدرس
الأول, هذا الكود ببساطة سوف يسمح لـ game layer بأن يكون مندوب اللمس لإستلام الإشعارات من اللمسات, الآن هناك كودان نحتاج إلى تنفيذهما.
أضف النظامين (الكودين) إلى GameLayer.m
أضف النظامين (الكودين) إلى GameLayer.m
// 1- (BOOL)ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event { return YES;} // 2- (void)ccTouchMoved:(UITouch *)touch withEvent:(UIEvent *)event { // 3 CGPoint touchLocation = [self convertTouchToNodeSpace:touch]; CGPoint oldTouchLocation = [touch previousLocationInView:touch.view]; oldTouchLocation = [[CCDirector sharedDirector] convertToGL:oldTouchLocation]; oldTouchLocation = [self convertToNodeSpace:oldTouchLocation]; // 4 int xChange = touchLocation.x - oldTouchLocation.x; int yChange = touchLocation.y - oldTouchLocation.y; int newX = self.player.position.x + xChange; int newY = self.player.position.y + yChange; // 5 if(newX < kGameAreaStartX + kGameAreaWidth - kGridCellSize && newX > kGameAreaStartX && newY > kGameAreaStartY + kGridCellSize / 2 && newY < kGameAreaStartY + (kGridCellSize * 3)) { __block BOOL collide = NO; CGPoint oldPosition = self.player.position; // 6 self.player.position = ccp(newX,newY); // 7 [self.sprouts enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { Sprout *sprout = (Sprout *)obj; CGRect sproutRect = [sprout getBounds]; CGRect playerRect = [self.player getBounds]; if(CGRectIntersectsRect(sproutRect, playerRect)) { collide = YES; *stop = YES; } }]; // 8 if(collide) { self.player.position = oldPosition; } }}
1- فى البداية نحتاج إلى تنفيذ ccTouchesBegan حتى نسمح للمتصل بمعرفة أننا نستجيب للمسات. إذا قمت بحذف هذه ستتحطم لعبتنا.2- بعد ذلك طريقة ccTouchesMoved التى يتم استدعائها عندما يمرر اللاعب إصبعه على الهاتف.3- الحصول على مرجع أو إشارة عن إحداثى مكان اللمسة الحالية وإحداثى مكان اللمسة السابقة.4- الحصول على التغير من إحداثى الموقع القديم والجديد, سوف نستخدم هذا التغير لتحديد مدى تحرك اللاعب.5-هنا لدينا سلسلة من الإختبارات للتأكد من أن اللاعب يبقى داخل "منطقة اللاعب" أو المربع المحيط الظاهري الذي أنشأناه لهم. و الكود السابق فى الواقع هو الذى يحرك اللاعب.6- تحديث مكان اللاعب.7- نحن هنا بصدد التحقق لمعرفة ما إذا كان لاعب يصطدم مع أي من البراعم. براعم تشكل عقبات للاعب، ونحن نريد تقييد حركة اللاعب إذا كانوا في طريقه.8- وأخيرا اذا كان هناك تصادم يُحول اللاعب إلى أفضل وضع جيد كان به
الان إذا قمت بتشغيل اللعبة يجب أن تكون قادرا على أن تسحب فى أى مكان فى المنطقة الخاصة باللعبة وأن تحرك اللاعب فى منطقة ضيقة
.الخطوة الثانية: الكائن الصاروخىالكائن الصاروخى هو
مايسمح لللاعب وعناصر اللعبة الأخرى بالتفاعل, اللاعب سيطلق تيار مستمر من
الصواريخ بسرعة وعلى فترات زمنية متفاوتة على حسب مستواه.
قبل البدء, نحتاج إلى إنشاء بعض الثوابت التى
سنحتاج اليها فيما بعد.
افتح GameConfig. وقم بإضافة الأسطر التالية:
افتح GameConfig. وقم بإضافة الأسطر التالية:
#define kMissileSpeed 1.0#define kMissileMaxSpeed 10.0#define kMissilesTotal 20#define kMissileFrequency .6 //seconds#define kMinMissileFrequency .2
سأقوم بتوضيح كلا منها لأنها تاتى مع الكود التالى, الآن أنشئ كائن جديد للعبة اسمه الصاروخ, أضف الكود
التالى إلى Missile.h:
#import "cocos2d.h"#import "GameObject.h" @interface Missile : GameObject@property (nonatomic, assign) BOOL dirty;- (void)update:(ccTime)dt;@end
سيتم استخدام خاصية
dirty للدلالة على أن الصاروخ لم يعد باللعبة يمكن أن يكون هذا بسبب الخروج من الشاشة أو
الاصطدام بكائن آخر فى اللعبة, منذ أن تتحرك الصواريخ باستمرار ستحتاج إلى تحديث لطريقة تحريكهم.
الآن قم بفتح Missile.m وقم بنسخ الكود التالى:
#import "Missile.h"#import "GameLayer.h"#import "GameConfig.h" @implementation Missile @synthesize dirty = _dirty; // 1- (id)initWithGameLayer:(GameLayer *)layer { if(self == [super initWithGameLayer:layer]) { self.sprite = [CCSprite spriteWithSpriteFrameName:@"missile.png"]; } return self;} - (void)update:(ccTime)dt { // 2 int inc = kMissileSpeed * (self.gameLayer.level + 1.5); // 3 if(inc > kMissileMaxSpeed) { inc = kMissileMaxSpeed; } // 4 int y = self.position.y + inc; self.position = ccp(self.position.x,y); // 5 if(self.position.y > kGameAreaStartY + kGameAreaHeight) { self.dirty = YES; }} @end
- طريقة الـ init الخاصة بنا تبدو مألوفة للغاية, وهى مسئولة فقط لإنشاء روح
الصاروخ.
- هذه هى السرعة التى سيتحرك بها الصاروخ, وهويبدأ بالقيمة الأساسية, ويُسرع استنادا إلى المستوى الحالى.
- عند مرحلة ما قد تخرج سرعة
الصاروخ عن السيطرة, نحن نمنع ذلك بإضافة أقصى سرعة.
- هذان السطران هما فى الواقع
من يحركان الصاروخ للأمام, نحن نحسب قيمة جديدة للصاروخ وتحديث الموقع.
- أخيرا, اذا اصطدم الصاروخ
بالجزء العلوى نحول خاصية _dirty الى
true سنقوم بجمع القمامة
من الصواريخ القذرة داخل GameLayer .
الخطوة الثالثة: إطلاق الصواريخالان نحن نمتلك بعض الصواريخ لإطلاقها, نحتاج إلى إطلاقهم من اللاعب بصفة عامة عندما تمتلك كمية كبيرة من الأجسام مثل الصواريخ, أنت تريد إعادة استخدام أكبر عدد ممكن دون تخصيص صواريخ جديدة أثناء تشغيل الحلقة الرئيسية, لحل هذه القضية سننشىء مصفوفتين, مصفوفة ستملك كل الصواريخ الحالية داخل اللعبة وقد تم إطلاقهم بواسطة اللاعب, والثانية ستملك الصواريخ الباقية للإطلاق.
فى نهاية طريقة التحديث سوف ننظف كل خاصية dirty من الصواريخ وننقلهم من مصفوفة "in play" داخل اللعب إلى المصفوفة الاخرى "pool"
أضف الخصائص
التالية إلى ملف GameLayer.m :
@property (nonatomic, retain) NSMutableArray *missilesWaiting;@property (nonatomic, retain) NSMutableArray *missilesFiring;
الان, افتح GameLayer.m وقم باستيراد
ملف Missile.h
وأضف السطور التالية إلى طريقة init
الخاصة بك:
// 1_missilesWaiting = [[NSMutableArray alloc] initWithCapacity:kMissilesTotal];_missilesFiring = [[NSMutableArray alloc] initWithCapacity:kMissilesTotal];// 2for(int x = 0; x < kMissilesTotal; x++) { Missile *missile = [[Missile alloc] initWithGameLayer:self]; [self.missilesWaiting addObject:missile]; [missile release];}
- تهيئة كلا من المصفوفتين.
- حلقة kMissilesTotal تنشىء كائنات صواريخ عديدة مرة واحدة يتم إنشاؤهم وتنظيفهم إلى مصفوفة.
- بعد ذلك, القفز إلى طريقة التحديث بإضافة الكود التالى :
// 1static float missleFireCount = 0; - (void)update:(ccTime)dt { // ...Caterpillar code... // 2 float frequency = kMinMissileFrequency; if(kMissileFrequency / (self.level * 1.25) > kMinMissileFrequency) { frequency = kMissileFrequency / self.level; } // 3 if(missleFireCount < frequency) { missleFireCount += dt; } else { missleFireCount = 0; // 4 if([self.missilesWaiting count] > 0) { Missile *missile = [self.missilesWaiting objectAtIndex:0]; [self.missilesFiring addObject:missile]; [self.missilesWaiting removeObjectAtIndex:0]; missile.position = self.player.position; [self.spritesBatchNode addChild:missile.sprite]; } } // 5 __block Missile *dirty = nil; [self.missilesFiring enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { Missile *missile = (Missile *)obj; [missile update:dt]; if(missile.dirty) { dirty = missile; *stop = YES; } }]; // 6 if(dirty) { dirty.dirty = NO; [self.missilesWaiting addObject:dirty]; [self.missilesFiring removeObject:dirty]; [self.spritesBatchNode removeChild:dirty.sprite cleanup:NO]; }}
1- نحتاج إلى إنشاء عداد ثابت
للمساعدة فى تسهيل التردد الذى ينطلق منه الصواريخ.2- حساب تردد إطلاق الصواريخ كما يزداد المستوى
يزداد التردد أيضا.3- نحن نحتاج فقط إلى إطلاق صاروخ جديد إذا كان التردد أكبر من أو مساويا للتردد المحدد لكل مستوى.4- سحب الصاروخ من مصفوفة الإنتظار (إذا كان بها)
وإضافتها لمصفوفة الإطلاق, فى هذه المرحلة أيضا أضفنا روح الصاروخ لعقدة
الدفع التى يمكن استخلاصها.5- التحقق من تعداد كافة الصواريخ من وجود واحد قذر, إذا وجدنا واحد تذكر أى واحد يمكننا تحريكه مجددا إلى مصفوفة
الانتظار.6- إذا كان هناك صاروخ قذر نحركه من مصفوفة الإنتظار إلى
مصفوفة الإطلاق وحذف روحه من عقدة الدفع.
هذه هى كل الاكواد
اللازمة لتحريك الصوارريخ, تقدم للأمام وقم بتشغيل اللعبة عند هذه النقطة شاهد
الصواريخ منطلقة من اللاعب وأنت تتحرك حولها صورة.
الخلاصة.الان نحن سمحنا
للاعب وبعض الصواريخ بالتحرك, الان بدأت تشعر أنها حقا لعبة, كما أننا سوف نستكشف بعض التصادمات بين اللاعب و البراعم فى الجزء القادم من السلسلة. سندخل إلى أعمق من ذلك فى كشف الإصطدام بين الصواريخ والبراعم والحشرة وبين اللاعب والحشرة.
استمتعوا بالبرمجة.
ليست هناك تعليقات: