مساحة اعلانية

آخر المواضيع

بناء لعبة اليرقات باستخدام :Cocos2D كشف التصادم


الخطوة 1: الصواريخ / برعم التصادم
 اصطدام الصاروخ مع براعم هو أشبه ما يكون بلاعب الاصطدام مع البراعم. نحن ببساطة نتحقق من حدود كل صاروخ في اللعب ضد حدود كل برعم في اللعب وتحديد ما إذا كان حدث أي تصادم. عندما يتم ضرب برعم، نقوم بإنقاص حياته، تعديل التعتيم، وإزالته إذا حياته وصلت إلى الحد 0.
 افتح Missile.m، قم بعمل  import ل  Sprout.، وقم بإضافة الكود التالي في الجزء السفلي من ال update method

CGRect missileRect = [self getBounds]; [self.gameLayer.sprouts enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {    Sprout *sprout = (Sprout *)obj;    CGRect sproutRect = [sprout getBounds];     if(CGRectIntersectsRect(missileRect, sproutRect)) {        self.dirty = YES;        sprout.lives--;                 }    }];

حيث أن كل تحديثات الصواريخ، عددها، والتحقق لمعرفة ما إذا كان محيطهم يتقاطع. إذا كان هناك تصادم، يتم وسم الصاروخ ب "القذر" وإنقاص حياة برعم وفقا لذلك. لقد كتبت بالفعل الكود لتعديل تعتيم البراعم على أساس مدة حياتها، لذلك إذا قمت بتشغيل اللعبة في هذه المرحلة، يجب أن تشاهد التغيير على البراعم عندما تتعرض للضرب ولكن الأهم من ذلك أننا بحاجة إلى إزالة البراعم التي وصل مؤشر الحياة لديها إلى 0.
ويمكن القيام بذلك داخل الـ Update Method: الـ Method الموجوة فى Game Layer.m .
قم بفتح GameLayer.m وقم بإضافة الكود  التالي على الزر الخاص بال update

// 1__block Sprout *deadSprout = nil;[self.sprouts enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {    Sprout *sprout = (Sprout *)obj;    if(sprout.lives == 0) {        deadSprout = sprout;        *stop = YES;    }}]; // 2if(deadSprout) {    [self.spritesBatchNode removeChild:deadSprout.sprite cleanup:YES];    [self.sprouts removeObject:deadSprout];}

1- نحن نعد كل البراعم بحثاً عن مقتل أحدهم. لتبسيط الأمور، يتم مسح برعم واحد فقط في كل تكرار أو في كل دورة.
2- في حالة وجود برعم ميت، نقوم بإزالته من الـ batch node وكذلك بإزالة برعم من مجموعة البراعم.
الآن، قم بتشغيل اللعبة وسترى أن البرعم يتلاشى عندما يضرب ويختفي في نهاية المطاف.
الخطوة الثانية:تصادم اليرقات.
نحن الآن بحاجة إلى إضافة كشف التصادم بين الصاروخ واليرقة. هذا التفاعل هو ما يجعل هذا التطبيق الخاص بك لعبة صحيحة. عند حدوث الضربة أو التصادم، ينبغي على اليرقة أن تنقسم في الجزء المضروب وكل "يرقة" جديدة يجب أن تنتقل في اتجاهات منفصلة. ويتم تحويل الجزء الذي أصيب إلى برعم.
ابدأ من خلال فتح Missile.m، استيراد Caterpillar.h وSegment.h، وقم بإضافة الكود التالي في أخر ال update method
__block Caterpillar *hitCaterpillar = nil;__block Segment *hitSegment = nil;// 1[self.gameLayer.caterpillars enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {    Caterpillar *caterpillar = (Caterpillar *)obj;    [caterpillar.segments enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {        Segment *segment = (Segment *)obj;        CGRect segmentRect = [segment getBounds];        // 2            if(CGRectIntersectsRect(missileRect, segmentRect)) {            self.dirty = YES;            hitCaterpillar = [caterpillar retain];            hitSegment = [segment retain];                        *stop = YES;        }    }];}]; // 3if(hitCaterpillar && hitSegment) {    [self.gameLayer splitCaterpillar:hitCaterpillar atSegment:hitSegment];    [hitSegment release];    [hitCaterpillar release];}
1. تعداد كل من اليرقات في اللعب وتعداد كل من القطاعات التي تعمل فيها.2. التحقق من وجود تصادم بالفعل وتسجيل أي جزء من اليرقة تم ضربه فعلياً.3. إذا كان لدينا تصادم، يمكننا تقسيم اليرقة في الجزء الحالي. وسوف نقوم بإنشاء الـ methodالخاصة بهذه الجزئية فيما بعد.
الآن لدينا الصاروخ اصطدم مع اليرقة، هناك ما يجب القيام به.
 الأول, هو أن أكتب منطقة تقسيم اليرقة على شريحة معينة. وسيتم ذلك في
GameLayer.m.أولا، قم بفتح الملف GameLayer.h ثم تعريف الـclasses  التالية:

@class Caterpillar;@class Segment;

ثم قم بتعريف ال method  التالية:
- (void)splitCaterpillar:(Caterpillar *) caterpillar atSegment:(Segment *)segment;
قبل أن نبدأ التنفيذ، نحن بحاجة إلى إضافة ملفين للمشروع. قم بتحميل NSArray+Reverse ، فك الضغط، واسحب كلا الملفين إلى مشروعك.  انها مجرد فئة على NSMutableArray تعطينا طريقة معكوسة.
 الآن افتح الملفGameLayer.m ، وقم بعمل import أو استيراد لـ Segment.h  NSArray+Reverse.h, وقم ببناء الـ method  التالية:
- (void)splitCaterpillar:(Caterpillar *)caterpillar atSegment:(Segment *)segment {// 1if([caterpillar.segments count] == 1) {    [self.spritesBatchNode removeChild:segment.sprite cleanup:NO];    [self.caterpillars removeObject:caterpillar];    [self createSproutAtPostion:segment.position];    return;} // 2[self.spritesBatchNode removeChild:segment.sprite cleanup:NO]; // 3[self createSproutAtPostion:segment.position]; // 4NSInteger indexOfSegement = [caterpillar.segments indexOfObject:segment];NSMutableArray *headSegments = [NSMutableArray array];NSMutableArray *tailsSegments = [NSMutableArray array]; // 5[caterpillar.segments enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {            if(idx < indexOfSegement) {    [headSegments addObject:obj];    } else if(idx > indexOfSegement) {    [tailsSegments addObject:obj];    }}]; // 6if([tailsSegments count] > 0) {     // 7    [tailsSegments reverse];     // 8    Caterpillar *newCaterpillar = [[[Caterpillar alloc] initWithGameLayer:self segments:tailsSegments level:self.level] autorelease];    newCaterpillar.position = [[tailsSegments objectAtIndex:0] position];     // 9    if(caterpillar.currentState == CSRight ||       caterpillar.previousState == CSRight) {    // Was heading right    if(caterpillar.currentState == CSDownLeft ||       caterpillar.currentState == CSDownRight) {        // Is heading down        newCaterpillar.previousState = CSUpRight;    } else {        // Is heading up        newCaterpillar.previousState = CSDownRight;    }    newCaterpillar.currentState = CSLeft;    } else {    // Was heading left    if(caterpillar.currentState == CSDownLeft ||       caterpillar.currentState == CSDownRight) {        // Is heading down        newCaterpillar.previousState = CSUpRight;    } else {        // Is heading up        newCaterpillar.previousState = CSDownRight;    }    newCaterpillar.currentState = CSRight;    }     [self.caterpillars addObject:newCaterpillar];} // 10if([headSegments count] > 0) {    caterpillar.segments = headSegments;} else {    [self.caterpillars removeObject:caterpillar];}}
1- إذا ضربنا قطعة واحدة من اليرقة (فقط الرأس)، نقوم بإزالة هذه اليرقة من المباراة وتحويلها إلى برعم.
2- إزالة الجزء الذي ضرب من ال batch node.
3- تحويل الجزء الذي ضرب إلى برعم (سيتم بناء الطريقة الخاصة بذلك).
4- نحن بحاجة إلى تقسيم اليرقة إلى مصفوفتين، الرأس والذيل.
5- تحديد مكان سقوط القطاعات الأخرى (الرأس أو الذيل) وإضافتها إلى المصفوفات المناسبة.
6- معرفة ما اذا كان هناك أي شرائح ذيل.
7- عكس مصفوفة شرائح الذيل. هذه هي فئة على NSMutableArray الذي تم ذكره أعلاه. نحن بحاجة إلى عكس القطاعات من أجل تحريك  اليرقة في الإتجاه المعاكس.
8- إنشاء يرقة جديدة باستخدام جزء الذيل. وسنقوم ببناء هذه الـ  method
9- هذا هو أساس هذه ال method. نحن هنا نحدد الاتجاه الحالي (اليمين أو اليسار) والاتجاه العام الحالي (صعودا أو هبوطا) لليرقة التي تعرضت لضربة وذلك لإرسال يرقة جديدة في الاتجاه المعاكس.
10- إذا كان لا يزال هناك رأس، نحن فقط نضيف اليرقة التي تعرضت لضربة للقطاعات الرأس المتبقية.

نجاح باهر، ولم يأخذ منا الكثير من الوقت. هل لا تزال معي؟ هناك زوج من الطرق استخدمناه هنا وفي الكود السابق الذي لا يزال بحاجة إلى تنفيذ.

الطريقة الأولى للتنفيذ هى createSproutAtPosition :. قم بإضافة تعريف الأسلوب التالي إلى واجهتك الخاصة  في الجزء العلوي من GameLayer.m:
- (void)createSproutAtPostion:(CGPoint)position;
والآن قم ببناء هذه ال method
- (void)createSproutAtPostion:(CGPoint)position {        // 1    int x = (position.x - kGameAreaStartX) / kGridCellSize;    int y = (kGameAreaStartY - kGridCellSize + kGameAreaHeight + kGridCellSize/2 - position.y) / kGridCellSize;     // 2    Sprout *sprout = [[Sprout alloc] initWithGameLayer:self];    sprout.position = position;    [self.sprouts addObject:sprout];    _locations[x][y] = YES;}

1- 
هذا يترجم موقعنا على إحداثيات الشاشة إلى إحداثيات الشبكة باستخدام المهارات الجبرية التي درسناها في الصف الثامن, ونحن نستمدها من كود تحديد المواقع المكتوب في part 2
2- وهنا أيضاً يتم إنشاء برعم جديد وإضافته إلى اللعبة
وآخر طريقة نحتاج لبنائها هي initWithGameLayer:segments:level:  في الـ caterpillar class وهذه الطريقة سوف تكون مسؤولة عن بناء يرقة جديدة.قم بفتح  Caterpillar.h وأضف تعريف الطريقة التالية:
- (id)initWithGameLayer:(GameLayer *)layer segments:(NSMutableArray *)segments  level:(NSInteger)level;

والآن, افتح Caterpillar.m وأضف الكود التالى:
- (id)initWithGameLayer:(GameLayer *)layer segments:(NSMutableArray *)segments  level:(NSInteger)level {if(self = [super initWithGameLayer:layer]) {    self.segments = segments;    self.level = level;    self.currentState = CSRight;    self.previousState = CSDownLeft;     // set the position of the rest of the segments    __block int x = 0;    __block Segment *parentSegment = [self.segments objectAtIndex:0];    parentSegment.parent = nil;     [self.segments enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {    Segment *segment = (Segment *)obj;                 if(x++ > 0) {         if(![segment isEqual:parentSegment]) {        segment.parent = parentSegment;        }         parentSegment = segment;    }                 }]; }return self;}

هذه الطريقة مطابقة تقريبا للـطريقة السابقة initWithGameLayer, , الفرق الوحيد هو بدلا من تخصيص مصفوفة من الشرائح، فإنه يضع مجموعة شرائح للقطاعات الواردة التي تم تمريرها الى الـ method.الآن امضي قدما في تشغيل اللعبة، في هذه المرحلة يجب أن تكون قادراً على قتل اليرقة في اللعبة تماماً.
الخطوة الثالثة:لاعب تصادم اليرقة.الشيء الأخير الذي نحتاجه لإكمال الكشف عن التصادم هو تنفيذ الإصطدام بين اليرقة واللاعب. في حال اصطدام أي جزء من اليرقة باللاعب، نقلل من عدد الأرواح للاعب كما أن اللاعب يصبح محصناً أي لا يمكن صدمه لفترة وجيزة، بحيث أن اليرقة تمر من خلاله ولا تصدمه.
ابدأ من خلال فتح GameConfig.h وإضافة الخيار التالي:
#define kPlayerInvincibleTime 15
الآن, قم بفتح Caterpillar.m و import Player.h ثم أضف الكود التالى فى أسفل طريقـــة update: قبل ضبط موضع الكاتر بيلر مباشرة:

static int playerInvincibleCount = kPlayerInvincibleTime;static BOOL playerHit; CGRect playerRect = [self.gameLayer.player getBounds]; // 1[self.segments enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {    Segment *segment = (Segment *)obj;    CGRect segmentRect = [segment getBounds];     if(CGRectIntersectsRect(segmentRect, playerRect) && playerInvincibleCount == kPlayerInvincibleTime) {        *stop = YES;        playerHit = YES;        // 2    self.gameLayer.player.lives--;        [[NSNotificationCenter defaultCenter] postNotificationName:kNotificationPlayerLives object:nil];    } }]; // 3if(playerHit) {    if(playerInvincibleCount > 0) {        playerInvincibleCount--;    } else {        playerHit = NO;        playerInvincibleCount = kPlayerInvincibleTime;    }}
1- تعداد كل من القطاعات لتحديد ما إذا كانت تتصادم مع اللاعب.2- إذا أصيب لاعب، يجب إنقاص حياته وعمل تنبيه بذلك. وهذا يجب أن ينعكس  تلقائيا, بحيث ينعكس في واجهة المستخدم استنادآ إلى الكود البرمجي المكتوب في جزء 3.3- إذا أصيب لاعب، وتحقق مما إذا كانت لا تزال في الفترة التي لا يمكن أن يصدم فيها. إذا لم يكن كذلك، يجب إعادة تعيين العداد (لا يُصدم) بحيث تصبح معرضة للصدم مرة أخرى.
الآن، قم بتشغيل اللعبة واسمح لليرقة بضرب اللاعب. يجب أن تنقص عدد الحياة المسموحة للاعب من أعلى الشاشة.

الخلاصة.
كشف التصادم ليست بالمهمة السهلة ونحن فقط ناقشنا الأمور السطحية، وإن أحببت التعمق أكثر في الموضوع ألق نظرة على استخدام Box2D with Cocos2D .

الكــاتــب

    • مشاركة

ليست هناك تعليقات:

جميع الحقوق محفوظة لــ الشبح للمعلوميات 2019 ©