スヌパヌマリオブラザヌズクロヌンゲヌムの䜜成パヌト1

画像 私たちの倚くにずっお、スヌパヌマリオブラザヌズはゲヌムプレむを本圓に魅了した最初のゲヌムでした。

任倩堂の盎感的なSMBコントロヌルず優れたレベルの蚭蚈により、配管工ずそのパヌトナヌの仮想䞖界で䜕時間も過ごすこずができたした。



Jacob Gundersenによるこの玠晎らしいチュヌトリアルでは、独自のプラットフォヌマヌを䜜成したす。 しかし、メむンキャラクタヌはコアラになるので、ゲヌムを「スヌパヌコアリオブラザヌズ」ず呌びたす。

たた、メカニズムを単玔化するために、敵の移動を忘れおいたす。 代わりに、床に埋め蟌たれたスタッド付きブロックを䜿甚したす。 これにより、プラットフォヌマヌの䞭心である物理゚ンゞンに完党に集䞭できるようになりたす。



泚意 カットの䞋では、信じられないほどの量の翻蚳されたテキスト、写真、コヌド翻蚳されおいないコヌド、および独自の物理゚ンゞンを䜜成するためのガむド



このチュヌトリアルでは、事前にCocos2Dプログラミングの基本に粟通しおいるこずを前提ずしおいたす。 それ以倖の堎合は、最初にRayのWebサむトでいく぀かの最初のレッスンを理解するこずを匷くお勧めしたす。



始めたしょう



開始するには、このチュヌトリアルのスタヌタヌプロゞェクトをダりンロヌドしおください。 解凍し、Xcodeで開き、実行したす。 同様の䜕かが゚ミュレヌタ画面に衚瀺されるはずです。



画像



そうです-ただ退屈な空癜の画面 ]チュヌトリアルを進めるに぀れお、完党に埋めおいきたす。

必芁なすべおの画像ず音声は、スタヌタヌプロゞェクトに既に远加されおいたす。 プロゞェクトの内容を芋おいきたしょう。





物理゚ンゞンの基本



プラットフォヌマヌは物理゚ンゞンに基づいお動䜜したす。このチュヌトリアルでは、独自の物理゚ンゞンを䜜成したす。

同じBox2DやChipminkを䜿甚しないで独自の゚ンゞンを䜜成する必芁がある理由は2぀ありたす。



  1. 詳现蚭定。 zenプラットフォヌマヌを完党に理解するには、゚ンゞンを完党にカスタマむズする方法を孊ぶ必芁がありたす。
  2. シンプル。 Box2DずChipmunkにはカスタマむズ可胜な機胜がたくさんありたすが、それは抂しお私たちにずっおは圹に立ちたせん。 はい、リ゜ヌスがありたす。 そしお、私たち自身の゚ンゞンは、蚱す限り正確に食べたす。


物理゚ンゞンは、2぀の䞻なタスクを実行したす。

画像

  1. 動きをシミュレヌトしたす。 物理゚ンゞンの最初のタスクは、重力、運動、ゞャンプ、摩擊の盞反する力をシミュレヌトするこずです。
  2. 衝突を怜出したす。 2番目のタスクは、プレむダヌずそのレベルの他のオブゞェクトずの衝突を刀断するこずです。


たずえば、ゞャンプ䞭、䞊向きの力がコアラに䜜甚したす。 しばらくするず、重力がゞャンプの力を䞊回り、叀兞的な速床の攟物線状の倉化が埗られたす。

衝突怜出の助けを借りお、重力の圱響䞋で床を通り抜けるたびにコアラを停止し、コアラがい぀スパむクを螏んだかを刀断したすay。

実際にどのように機胜するかを芋おみたしょう。



物理゚ンゞンの䜜成



䜜成する物理゚ンゞンでは、Koalaには動きを蚘述する独自の倉数がありたす速床、加速床、䜍眮。 これらの倉数を䜿甚しお、プログラムの各ステップで次のアルゎリズムを䜿甚したす。



  1. ゞャンプたたはモヌションアクションが遞択されおいたすか
  2. もしそうなら、コアラのゞャンプたたは動きの匷さを䜿甚しおください。
  3. たた、重力をコアラに適甚したす。
  4. 結果のコアラ速床を蚈算したす。
  5. 受信した速床をKoalaに適甚し、その䜍眮を曎新したす。
  6. Koalasず他のオブゞェクトずの衝突を確認したす。
  7. 衝突が発生した堎合は、衝突が発生しなくなるたで障害物からコアラを移動したす。 たたは貧しいコアレを損傷したす。
画像

プログラムのすべおのステップでこれらのステップを実行したす。 私たちのゲヌムでは、重力によっおコアラが床からどんどん沈んでいきたすが、衝突が怜出されるたびに床の䞊のポむントに戻りたす。 この機胜を䜿甚しお、コアラが土地に觊れおいるかどうかを刀断するこずもできたす。 そうでない堎合は、コアラがゞャンプ状態にあるか、障害物からゞャンプした盎埌にプレヌダヌがゞャンプするのを防ぐこずができたす。

ポむント1〜5はKoalaオブゞェクト内で発生したす。 必芁な情報はすべおこのオブゞェクト内に保存する必芁があり、Koaleが倉数自䜓を曎新できるようにするこずは非垞に論理的です。

ただし、6番目の点、぀たり衝突の定矩に぀いおは、壁、床、敵、その他の危険など、レベルのすべおの機胜を考慮する必芁がありたす。 衝突怜出は、GameLevelLayerを䜿甚しおプログラムのすべおのステップで実行されたす-これは、ほずんどの物理タスクを実行するCCLayerのサブクラスであるこずを思い出しおください。

コアラが自分の手で䜍眮を曎新できるようにするず、最終的にコアラは壁や床に觊れたす。 そしお、GameLevelLayerはコアルを埩掻させたす。 そしお䜕床も䜕床も-それはコアラが圌女が振動しおいるように芋えるようになりたす。 朝のコヌヒヌが倚すぎる、コアリオ

そのため、コアレがその状態を曎新するこずを蚱可したせん。 代わりに、Koalaが曎新する新しい倉数desiredPositionをKoaleに远加したす。 GameLevelLayerは、KoalaをdesiredPositionに移動できるかどうかを確認したす。 その堎合、GameLevelLayerはKoalaの状態を曎新したす。

すべおが明確ですか コヌドでどのように芋えるか芋おみたしょう



TMXTiledMapをダりンロヌドする



Tile Mapsのようなマップがどのように機胜するかに぀いおはご存じだず思いたす。 そうでない堎合は、 このチュヌトリアルでそれらに぀いお読むこずをお勧めしたす。

レベルを芋おみたしょう。 タむルマップ゚ディタヌを起動しこれをただ行っおいない堎合はダりンロヌドしたす、プロゞェクトフォルダヌからlevel1.tmxを開きたす。 以䞋が衚瀺されたす。



画像



サむドバヌを芋るず、3぀の異なるレむダヌがあるこずがわかりたす。





コヌディングの時間です GameLevelLayer.mを開き、 #importの埌@implementation



前に次を远加したす。



 @interface GameLevelLayer() { CCTMXTiledMap *map; } @end
      
      





headクラスのメッシュマップを操䜜するために、CCTMXTiledMapクラスのロヌカル倉数マップを远加したした。

次に、レむダヌの初期化䞭にレむダヌにメッシュマップを配眮したす。 initメ゜ッドに次を远加したす。



 CCLayerColor *blueSky = [[CCLayerColor alloc] initWithColor:ccc4(100, 100, 250, 255)]; [self addChild:blueSky]; map = [[CCTMXTiledMap alloc] initWithTMXFile:@"level1.tmx"]; [self addChild:map];
      
      





最初に、青い空の色に背景CCLayerColorを远加したした。 次の2行のコヌドは、マップ倉数CCTMXTiledMapを読み蟌んでレむダヌに远加するだけです。



次に、 PlayerLevelLayer.mでPlayer.hをむンポヌトしたす。



 #import "Player.h"
      
      





匕き続きGameLevelLayer.mで 、 @ interface



セクションに次のロヌカル倉数を远加したす。



 Player * player;
      
      





次に、 initメ゜ッドに次のコヌドを䜿甚しお、Koalaをレベルに远加したす 。



 player = [[Player alloc] initWithFile:@"koalio_stand.png"]; player.position = ccp(100, 50); [map addChild:player z:15];
      
      





このコヌドはKoalaスプラむトオブゞェクトをロヌドし、その䜍眮を蚭定しおマップオブゞェクトに远加したす。

あなたは、なぜ単にコアラオブゞェクトをレむダに盎接远加するのではなく、マップに远加するのでしょうか すべおがシンプルです。 どのレむダヌをコアラの前に配眮し、どのレむダヌをコアラの埌ろに配眮するかを盎接制埡したす。 したがっお、コアルをメむンレむダヌではなく、カヌドの子にしたす。 Koalaを前面に配眮するため、Zオヌダヌに15を指定したす。たた、マップをスクロヌルしおも、コアラはメむンレむダヌではなく、マップに察しお同じ䜍眮にありたす。

よし、やっおみよう プロゞェクトを実行するず、次が衚瀺されるはずです。



画像



ゲヌムのように芋えたすが、コアリオは重力を無芖したす 物理゚ンゞンを䜿甚しお、倩から地球ぞず降ろしたす]



コアリオの重力状況

画像

物理孊のシミュレヌションを䜜成するには、受け取った情報から始めお、コアラの状態を考慮し、コアラに力を加える分岐ロゞックの耇雑なセットを䜜成したす。 しかし、この䞖界はすぐに耇雑になりすぎたす-それはそれほど難しい仕事ではないので、本圓の物理孊です。 珟実の䞖界では、重力は垞にオブゞェクトを匕き䞋げたす。 そのため、䞀定の重力を加えお、プログラムのすべおのステップでコアラに適甚したす。

他の力も、単にオンずオフを切り替えるだけではありたせん。 珟実の䞖界では、別の力が最初の力を䞊回るか等しくなるたで、力はオブゞェクトに䜜甚したす。

たずえば、跳躍力は重力をオフにしたせん。 重力が再びコアラを地面に抌し付けるたで、しばらく重力の力を超えたす。

これが物理孊のモデル化方法です。 コアラに重力をかけるかどうかを決めるだけではありたせん。 重力は垞に存圚したす。



神を挔じる

画像

゚ンゞンのロゞックは、力がオブゞェクトに䜜甚する堎合、他の力が最初の力を超えるたで動き続けるこずを意味したす。 Coalioが棚から飛び降りるずき、圌はパスで障害物に遭遇するたで䞀定の加速で䞋に移動し続けたす。 Coalioを動かしおも、圌の動きの力を䜿うのをやめるたで、圌は動きを止めたせん。 Coalioが停止するたで摩擊が䜜甚したす。

物理゚ンゞンを䜜成するず、このような単玔なゲヌムロゞックが、氷床や厖からの萜䞋などの耇雑な物理的問題の解決にどのように圹立぀かがわかりたす。 この動䜜モデルにより、ゲヌムを動的に倉曎できたす。

たた、このような銬による動きは、オブゞェクトの状態を垞に確認する必芁がないため、実装を容易にしたす。オブゞェクトは、珟実䞖界の物理法則に埓うだけです。

時々、神を挔じる必芁がありたす ]



地球の法則CGPointsおよびForces



次の抂念を瀺したしょう。





物理シミュレヌションでは、オブゞェクトに適甚される力はオブゞェクトを特定の速床に加速し、オブゞェクトはパス内で別の力に遭遇するたでその速床で移動したす。 速床は、新しいアクティブなフォヌスが珟れるず、フレヌムごずに倉化する倀です。

CGPoint構造を䜿甚しお、速床、力/加速床、䜍眮の3぀のこずを瀺したす。 CGPoint構造を䜿甚する理由は2぀ありたす。



  1. それらは2Dです。 速床、パワヌ/加速床、および䜍眮はすべお、2Dゲヌムの2D倀です。 重力は䞀方向にのみ䜜甚するず蚀うこずができたすが、ゲヌムのある時点で重力の方向を緊急に倉曎する必芁がある堎合はどうでしょうか スヌパヌマリオギャラクシヌを考えおください
  2. これは䟿利です。 CGPointを䜿甚するず、Cocos2Dに組み蟌たれおいるさたざたな機胜を䜿甚できたす。 特に、ccpAdd加算、ccpSub枛算、ccpMultfloat型の倉数による乗算を䜿甚したす。 これにより、コヌドの読み取りずデバッグがはるかに簡単になりたす


コアラのオブゞェクトの速床は可倉であり、重力、運動、ゞャンプ、摩擊などのさたざたな力の出珟によっお倉化したす。

ゲヌムの各ステップで、すべおの力を加算し、結果の倀をコアラの珟圚の速床に加算したす。 その結果、新しい珟圚の速床を受け取りたす。 フレヌムレヌトを䜿甚しお削枛したす。 その埌、コアラを移動したす。

泚意䞊蚘のいずれかが誀解を招く堎合、玠晎らしい人物であるダニ゚ル・シフマンは、ベクタヌに関する優れたチュヌトリアルを䜜成したした。これは、䜿甚する構造物に察する力の䜜甚を完党に説明しおいたす。

重力から始めたしょう。 力を䜿甚する実行ルヌプを䜜成したす。 if条件ブロックを閉じる盎前に、 GameLevelLayer.mファむルのinitメ゜ッドに次のコヌドを远加したす。



 [self schedule:@selector(update:)];
      
      





次に、新しいメ゜ッドをクラスに远加したす。



 - (void)update:(ccTime)dt { [player update:dt]; }
      
      





次に、 Player.hを開き、次のように倉曎したす。



 #import <Foundation/Foundation.h> #import "cocos2d.h" @interface Player : CCSprite @property (nonatomic, assign) CGPoint velocity; - (void)update:(ccTime)dt; @end
      
      





次のコヌドをPlayer.mに远加したす。



私をクリック
 #import "Player.h" @implementation Player @synthesize velocity = _velocity; // 1 - (id)initWithFile:(NSString *)filename { if (self = [super initWithFile:filename]) { self.velocity = ccp(0.0, 0.0); } return self; } - (void)update:(ccTime)dt { // 2 CGPoint gravity = ccp(0.0, -450.0); // 3 CGPoint gravityStep = ccpMult(gravity, dt); // 4 self.velocity = ccpAdd(self.velocity, gravityStep); CGPoint stepVelocity = ccpMult(self.velocity, dt); // 5 self.position = ccpAdd(self.position, stepVelocity); } @end
      
      





䞊蚘のコヌドをステップごずに芋おいきたしょう



  1. ここで、オブゞェクトを初期化し、速床倉数をれロに蚭定する新しいinitメ゜ッドを远加したした。
  2. ここで、重力ベクトルの倀を指定したした。 1秒ごずに、Koalaの速床を450ピクセルず぀加速したす。
  3. ここでは、重力ベクトルの倀を枛らしおフレヌムレヌトを満たすためにccpMultを䜿甚したした。 ccpMultは、フロヌトずCGPointを受け取り、CGPointを返したす。
  4. ここでは、珟圚のステップの重力を蚈算するずすぐに、珟圚の速床に重力を远加したす。
  5. 最埌に、1ステップの速床を蚈算したら、ccpAddを䜿甚しおコアラの䜍眮を曎新したす。


おめでずうございたす 最初の物理゚ンゞンを䜜成する正しい道を歩んでいたす プロゞェクトを実行しお結果を確認しおください



画像



Oooo-Coalioが床に萜ちたす それを修正したしょう。



倜のキック-衝突怜出



衝突怜出は、物理゚ンゞンの基盀です。 画像フレヌムの単玔な䜿甚から耇雑な3Dオブゞェクトの衝突たで、さたざたなタむプの衝突怜出がありたす。 幞いなこずに、プラットフォヌマヌは耇雑な構造を必芁ずしたせん。

オブゞェクトずのコアラの衝突を怜出するには、コアラを盎接囲むセルにTMXTileMapを䜿甚したす。 さらに、iOSに組み蟌たれたいく぀かの関数を䜿甚しお、Koalaのスプラむトがセルのスプラむトず亀差するかどうかを確認したす。

CGRectIntersectsRectおよびCGRectIntersection関数は、これらのチェックを非垞に簡単にしたす。 CGRectIntersectsRectは2぀の長方圢が亀差するかどうかをチェックし、CGRectIntersectionは亀差する長方圢を返したす。

たず、Koalaのスコヌプを定矩する必芁がありたす。 ロヌドされた各スプラむトにはフレヌムがありたす。フレヌムはテクスチャのサむズであり、boundingBoxず呌ばれるパラメヌタヌを䜿甚しおアクセスできたす。

すでにboundingBoxにあるフレヌムを定矩するのはなぜですか 通垞、テクスチャの呚囲には透明な゚ッゞがありたすが、衝突を刀断する際に考慮したせん。

時には、スプラむトの実際の画像透明ではないの呚囲の数ピクセルを考慮する必芁さえありたせん。 マリオが壁にぶ぀かったずき、圌はそれに少し觊れたすか、それずも圌の錻はブロックにわずかに埋たっおいたすか

やっおみたしょう。 Player.hに远加したす 。



 -(CGRect)collisionBoundingBox;
      
      





Player.mに远加したす 。



 - (CGRect)collisionBoundingBox { return CGRectInset(self.boundingBox, 2, 0); }
      
      





CGRectInsetは、2番目ず3番目の匕数のピクセル数でCGRectを圧瞮したす。 この堎合、衝突フレヌムの幅は6ピクセル小さくなりたす-䞡偎に3ピクセル。



重量挙げ



重量物を持ち䞊げる時間です。 「ねえ、あなたは今私を倪っおいるず思いたしたか」コアリオは蚀いたす。

衝突を怜出するには、GameLevelLayerにいく぀かのメ゜ッドが必芁です。 特に





䞊蚘の方法を簡玠化する2぀のヘルパヌ関数を䜜成したす。





次のコヌドをGameLevelLayer.mに远加したす。



 - (CGPoint)tileCoordForPosition:(CGPoint)position { float x = floor(position.x / map.tileSize.width); float levelHeightInPixels = map.mapSize.height * map.tileSize.height; float y = floor((levelHeightInPixels - position.y) / map.tileSize.height); return ccp(x, y); } - (CGRect)tileRectFromTileCoords:(CGPoint)tileCoords { float levelHeightInPixels = map.mapSize.height * map.tileSize.height; CGPoint origin = ccp(tileCoords.x * map.tileSize.width, levelHeightInPixels - ((tileCoords.y + 1) * map.tileSize.height)); return CGRectMake(origin.x, origin.y, map.tileSize.width, map.tileSize.height); }
      
      





最初のメ゜ッドは、メ゜ッドに枡すピクセル単䜍の座暙にあるセルの座暙を返したす。 セルの䜍眮を取埗するには、セルサむズで座暙を陀算したす。

Cocos2D / OpenGLシステムの座暙は巊䞋隅から始たり、システム座暙は巊䞊隅から始たるため、高さの座暙を反転する必芁がありたす。 暙準-それはクヌルではありたせんか

2番目の方法は反察のこずを行いたす。 セル座暙にセルサむズを乗算し、そのセルのCGRectを返したす。 繰り返したすが、高さを拡匵する必芁がありたす。

なぜ高さのy座暙に1を远加する必芁があるのですか セルの座暙はれロから始たるため、20個のセルの実際の座暙は19です。高さに1を远加しない堎合、ポむントは19 * tileHeightになりたす。



私は现胞に囲たれおいたす



それでは、コアラを囲むセルを決定する方法に移りたしょう。 このメ゜ッドでは、配列を䜜成し、それを返したす。 この配列には、セルのGID、セル座暙、およびこのセルのCGRect情報が含たれたす。

この配列を優先床順に敎理し、衝突を刀断したす。 たずえば、斜めの衝突を定矩する前に、䞊、巊、右、䞋から衝突を刀断したいずしたす。 たた、コアラず䞋のセルの衝突を怜出するず、地面に觊れるためのフラグを蚭定したす。

このメ゜ッドをGameLevelLayer.mに远加したす 。



私をクリック
 - (NSArray *)getSurroundingTilesAtPosition:(CGPoint)position forLayer:(CCTMXLayer *)layer { CGPoint plPos = [self tileCoordForPosition:position]; //1 NSMutableArray *gids = [NSMutableArray array]; //2 for (int i = 0; i < 9; i++) { //3 int c = i % 3; int r = (int)(i / 3); CGPoint tilePos = ccp(plPos.x + (c - 1), plPos.y + (r - 1)); int tgid = [layer tileGIDAt:tilePos]; //4 CGRect tileRect = [self tileRectFromTileCoords:tilePos]; //5 NSDictionary *tileDict = [NSDictionary dictionaryWithObjectsAndKeys: [NSNumber numberWithInt:tgid], @"gid", [NSNumber numberWithFloat:tileRect.origin.x], @"x", [NSNumber numberWithFloat:tileRect.origin.y], @"y", [NSValue valueWithCGPoint:tilePos],@"tilePos", nil]; [gids addObject:tileDict]; } [gids removeObjectAtIndex:4]; [gids insertObject:[gids objectAtIndex:2] atIndex:6]; [gids removeObjectAtIndex:2]; [gids exchangeObjectAtIndex:4 withObjectAtIndex:6]; [gids exchangeObjectAtIndex:0 withObjectAtIndex:4]; //6 for (NSDictionary *d in gids) { NSLog(@"%@", d); } //7 return (NSArray *)gids; }
      
      





Pff-コヌド党䜓。 心配しないで、詳现に説明したす。

しかし、その前に、マップ䞊に3぀のレむダヌがあるこずに泚意しおください。

異なるレむダヌが存圚するため、各レむダヌの衝突を別々に定矩できたす。





もちろん、さたざたなブロックずのさたざたな衝突を刀断するにはさたざたな方法がありたすが、マップ䞊のレむダヌなど、非垞に効果的なものがありたす。

さお、ステップごずにコヌドを芋おいきたしょう。



1.たず、入力するセルの座暙コアラの座暙を取埗したす。

2.次に、セルに関する情報を返す新しい配列を䜜成したす。

3.次に、サむクルを9回開始したす。コアラが既に配眮されおいるセルを含む、9぀の可胜な移動セルがあるためです。 次の数行は、9぀のセルの䜍眮を定矩し、それらをtilePos倉数から保存したす。



泚コアラが既に配眮されおいるセルずの衝突を刀断する必芁がないため、8぀のセルに関する情報のみが必芁です。

このケヌスを垞にキャッチしお、コアラをセルの1぀に移動する必芁がありたす。 Coalioが゜リッドセル内にある堎合、Coalioスプラむトの半分以䞊が䞭に入っおいたす。 圌はそれほど速く動くべきではありたせん-少なくずもこのゲヌムでは

これらの8぀のセルを操䜜しやすくするには、最初にCoalioセルを远加し、最埌に削陀したす。


4. 4番目のセクションでは、tileGIDAtを呌び出したす。 このメ゜ッドは、特定の座暙にあるセルのGIDを返したす。 受信した座暙にセルがない堎合、メ゜ッドはれロを返したす。 次に、倀「cell not found」にれロを䜿甚したす。

5.次に、ヘルパヌメ゜ッドを䜿甚しお、Cocos2D座暙デヌタのセルのCGRectを蚈算したす。 受信した情報をNSDictionaryに保存したす。 このメ゜ッドは、受信したNSDictionaryから配列を返したす。

6. 6番目のセクションでは、配列からKoalaセルを削陀し、セルを優先床順に䞊べ替えたす。

画像

倚くの堎合、コアラの䞋のセルずの衝突の堎合、セルずの衝突も斜めに定矩したす。 右の図をご芧ください。 赀で瀺されたコアラの䞋のセルずの衝突を怜出するこずにより、青で匷調衚瀺されたブロック2ずの衝突も怜出したす。

衝突怜出アルゎリズムはいく぀かの仮定を䜿甚したす。 これらの仮定は、察角セルではなく隣接セルに圓おはたりたす。 そのため、可胜な限り察角セルを䜿甚したアクションを避けるようにしたす。

そしお、これは䞊べ替え前埌の配列内のセルの順序を明確に瀺した写真です。 䞊、䞋、右、巊のセルが最初に凊理されるこずに気付くかもしれたせん。 セルの順序がわかれば、コアラがい぀地面に觊れたのか、雲の䞭を飛んだのかを刀断しやすくなりたす。

画像



7.セクション7のサむクルにより、セルをリアルタむムで監芖できたす。 ですから、すべおが蚈画通りに進んでいるこずを確実に知るこずができたす。



次のゲヌムの発売の準備がほが敎いたした ただし、ただいく぀かの小さなこずをする必芁がありたす。 壁レむダヌを倉数ずしおGameLevelLayerクラスに远加しお、䜿甚できるようにする必芁がありたす。



GameLevelLayer.m内で、次の倉曎を行いたす。



 //   @interface CCTMXLayer *walls; //    init,  ,      walls = [map layerNamed:@"walls"]; //    update [self getSurroundingTilesAtPosition:player.position forLayer:walls];
      
      





発射 しかし、残念ながら、ゲヌムはクラッシュしたす。 コン゜ヌルに次のように衚瀺されたす。



画像



たず、セルの䜍眮ずGID倀に関する情報を取埗したすただし、䞊郚に空の地圢があるため、ほずんどはれロです。

最終的に、゚ラヌ「TMXLayer無効な䜍眮」ですべおがクラッシュしたす。 これは、マップの端の倖偎の䜍眮がtileGIDatメ゜ッドに枡されるずきに発生したす。

少し埌でこの゚ラヌを回避したすが、最初に、既存の衝突の定矩を倉曎したす。



コアラの特暩を取り戻したす



その瞬間たで、コアラ自䜓がその䜍眮を曎新しおいたした。 しかし今、私たちは圌女からこの特暩を取っおいたす。



画像



コアラが独立しおその䜍眮を曎新するず、最終的には狂ったようにゞャンプし始めたす しかし、私たちはこれを望んでいたせん。

そのため、Koalaでは、GameLevelLayerず察話する远加の倉数desiredPositionが必芁です。

Koalaクラスは、その次の䜍眮を独立しお蚈算する必芁がありたす。 ただし、GameLevelLayerは、劥圓性を確認した埌にのみ、コアラを目的の䜍眮に移動する必芁がありたす。 同じこずが衝突怜出サむクルにも圓おはたりたす。すべおのセルの衝突がチェックされる前に、実際のスプラむトを曎新するこずは望たしくありたせん。

いく぀かの倉曎が必芁です。 たず、以䞋をPlayer.hに远加したす



 @property (nonatomic, assign) CGPoint desiredPosition;
      
      





Player.mに远加されたものを合成したす 。



 @synthesize desiredPosition = _desiredPosition;
      
      





次に、 Player.mのcollisionBoundingBoxメ゜ッドを次のように倉曎したす。



 - (CGRect)collisionBoundingBox { CGRect collisionBox = CGRectInset(self.boundingBox, 3, 0); CGPoint diff = ccpSub(self.desiredPosition, self.position); CGRect returnBoundingBox = CGRectOffset(collisionBox, diff.x, diff.y); return returnBoundingBox; }
      
      





このコヌドは、GameLevelLayerが衝突を刀断するために䜿甚する望たしい䜍眮に基づいおフレヌムを蚈算したす。

泚コリゞョンフレヌムの蚈算にはさたざたな方法がありたす。 CCNodeクラスに既にあるものず同様のコヌドを曞くこずができたすが、珟圚のメ゜ッドは、いく぀かの非自明性にもかかわらず、はるかに単玔です。

次に、珟圚の䜍眮ではなくdesiredPositionを曎新するように、updateメ゜ッドに次の倉曎を加えたす。



 //  'self.position = ccpAdd(self.position, stepVelocity);' : self.desiredPosition = ccpAdd(self.position, stepVelocity);
      
      





衝突を始めたしょう



真剣な成果の時が来たした。 それをすべおたずめる぀もりです。 GameLevelLayer.mに次のメ゜ッドを远加したす。



私をクリック
 - (void)checkForAndResolveCollisions:(Player *)p { NSArray *tiles = [self getSurroundingTilesAtPosition:p.position forLayer:walls ]; //1 for (NSDictionary *dic in tiles) { CGRect pRect = [p collisionBoundingBox]; //2 int gid = [[dic objectForKey:@"gid"] intValue]; //3 if (gid) { CGRect tileRect = CGRectMake([[dic objectForKey:@"x"] floatValue], [[dic objectForKey:@"y"] floatValue], map.tileSize.width, map.tileSize.height); //4 if (CGRectIntersectsRect(pRect, tileRect)) { CGRect intersection = CGRectIntersection(pRect, tileRect); //5 int tileIndx = [tiles indexOfObject:dic]; //6 if (tileIndx == 0) { //    p.desiredPosition = ccp(p.desiredPosition.x, p.desiredPosition.y + intersection.size.height); } else if (tileIndx == 1) { //    p.desiredPosition = ccp(p.desiredPosition.x, p.desiredPosition.y - intersection.size.height); } else if (tileIndx == 2) { //    p.desiredPosition = ccp(p.desiredPosition.x + intersection.size.width, p.desiredPosition.y); } else if (tileIndx == 3) { //    p.desiredPosition = ccp(p.desiredPosition.x - intersection.size.width, p.desiredPosition.y); } else { if (intersection.size.width > intersection.size.height) { //7 // ,     float intersectionHeight; if (tileIndx > 5) { intersectionHeight = intersection.size.height; } else { intersectionHeight = -intersection.size.height; } p.desiredPosition = ccp(p.desiredPosition.x, p.desiredPosition.y + intersection.size.height ); } else { // ,     float resolutionWidth; if (tileIndx == 6 || tileIndx == 4) { resolutionWidth = intersection.size.width; } else { resolutionWidth = -intersection.size.width; } p.desiredPosition = ccp(p.desiredPosition.x , p.desiredPosition.y + resolutionWidth); } } } } } p.position = p.desiredPosition; //7 }
      
      





いいね曞いたばかりのコヌドを芋おみたしょう。



1.最初に、コアラを囲むセルのセットを取埗したす。次に、このセットの各セルを埪環したす。セルを通過するたびに、衝突をチェックしたす。衝突が発生した堎合、KoalaのdesiredPositionを倉曎したす。

2.ルヌプの各ルヌプ内で、最初に珟圚のKoalaフレヌムを取埗したす。衝突が怜出されるたびに、desiredPosition倉数はその倀を、衝突が発生しなくなるポむントに倉曎したす。

3.次のステップは、NSDictionaryに栌玍したGIDを取埗するこずです。これはれロの堎合がありたす。 GIDがれロの堎合、珟圚のルヌプは終了し、次のセルに進みたす。

4。セルが新しい䜍眮にある堎合、CGRectを取埗する必芁がありたす。衝突する堎合ずしない堎合がありたす。このプロセスを次のコヌド行で実行し、tileRect倉数に保存したす。CGRect Koalaずセルができたので、衝突をチェックできたす。

5.セルの衝突をチェックするには、CGRectIntersectsRectを実行したす。衝突が発生した堎合、CGRectIntersection関数を䜿甚しお、CGRect亀差点を蚘述するCGRectを取埗したす。



ゞレンマに぀いお詳しく芋おみたしょう...



かなり興味深いケヌスです。衝突を正しく識別する方法を理解する必芁がありたす。

コアラを動かす最良の方法は、衝突ずは反察の方向に動かすこずだず思うかもしれたせん。䞀郚の物理゚ンゞンはこの原理で実際に動䜜したすが、より良い方法で゜リュヌションを適甚したす。

考えおみたしょう重力はコアラを垞にその䞋のセルに匕き寄せおおり、これらの衝突は進行䞭です。あなたがコアラが前進するのを想像するなら、同時に、コアルはただ重力によっお匕き䞋げられおいたす。動きを反察方向に単玔に倉曎するこずでこの問題を解決する堎合、コアラは巊䞊に移動したすが、䜕か他のものが必芁です

コアラは、これらのセルの䞊にずどたるために十分な距離を移動する必芁がありたすが、同じペヌスで前進し続けたす。

画像

コアラが壁を転がり萜ちた堎合も同じ問題が発生したす。プレむダヌがコアラを壁に抌し付けるず、コアラの動きの望たしい軌道が斜め䞋向きに壁に向けられたす。方向を倉えるだけで、コアラを壁から䞊に移動させたす。コアラを壁の倖に残したいが、それでも同じペヌスで䞋がっおほしい

画像

したがっお、衝突を垂盎に、い぀氎平に凊理するかを決定し、䞡方のアクションを盞互に排他的に凊理する必芁がありたす。䞀郚の物理゚ンゞンは、最初に最初のむベントを垞に凊理し、次に2番目のむベントを凊理したす。しかし、コアラのセルの䜍眮に基づいおより良い決定をしたいず考えおいたす。したがっお、たずえば、セルがコアラの真䞋にある堎合、コリゞョン識別子がコアラを䞊に戻すようにしたす。

しかし、セルがコアラの䜍眮に察しお斜めになっおいる堎合はどうでしょうかこの堎合、CGRect亀差点を䜿甚しお、コアラをどのように移動するかを理解したす。この長方圢の幅が高さよりも倧きい堎合、Koalaを垂盎に戻す必芁がありたす。高さが幅よりも倧きい堎合、コアラは氎平方向に移動する必芁がありたす。

画像

Koalaの速床ずフレヌムレヌトが特定のフレヌムワヌク内にある限り、このプロセスは正しく機胜したす。少し埌で、コアラが萜䞋しすぎおセルをすり抜けるケヌスを回避する方法を孊びたす。

Koalaの移動方法垂盎たたは氎平を決定したら、亀差点のCGRectサむズを䜿甚しお、Koalaを移動する量を決定したす。それぞれ幅たたは高さを芋お、この倧きさをコアラの倉䜍距離ずしお䜿甚したす。

特定の順序でセルをチェックするのはなぜですか垞に隣接するセルを最初に凊理し、次に斜めのセルを凊理する必芁がありたす。結局、Koalaの真䞋のセルの衝突をチェックしたい堎合、倉䜍ベクトルは垂盎に向けられたす。

画像

ただし、コアラがセルにわずかに觊れるず、CGRectの衝突が䞊方に広がる可胜性がありたす。

右偎の写真を芋おください。コリゞョン四角圢はコリゞョン党䜓のごく䞀郚であるため、青色の領域が拡倧されたす。ただし、コアラの盎䞋のセルに関する問題をすでに解決しおいる堎合は、コアラの右䞋のセルずの衝突を怜出する必芁がなくなりたす。したがっお、新たな問題を回避したす。



コヌドに戻りたしょう



巚倧なメ゜ッドcheckForAndResolveCollisionsに戻りたしょう ...



6. 6番目のセクションでは、珟圚のセルのむンデックスを取埗できたす。セルのむンデックスを䜿甚しお、セルの䜍眮を取埗したす。隣接するセルを個別に操䜜しお、コアラをシフトし、衝突の長さたたは高さを枛算たたは加算したす。ずおも簡単です。ただし、察角セルになるずすぐに、前のセクションで説明したアルゎリズムを適甚したす。

7. 7番目のセクションでは、衝突領域が広いか现長いかを刀断したすか幅が広い堎合-垂盎に䜜業したす。セルむンデックスが5より倧きい堎合、コアラを䞊に移動したす。領域が䞊方向に匕き䌞ばされおいる堎合、氎平方向に䜜業したす。セルむンデックスの順序に぀いおも、同様の原則に基づいお行動したす。最埌に、受け取ったポゞションをコアレに割り圓おたす。



この方法は、衝突怜出システムの頭脳です。



実際に利甚可胜な知識をすべお掻甚したしょう方法に倉曎し、曎新をただでGameLevelLayer 



 //  "[self getSurroundingTilesAtPosition:player.position forLayer:walls];" : [self checkForAndResolveCollisions:player];
      
      





getSurroundingTilesAtPositionforLayerブロックを削陀たたはコメントアりトするこずもできたす。



  /* for (NSDictionary *d in gids) { NSLog(@"%@", d); } //8 */
      
      





発射結果に驚いた



画像



ポヌルはコアリオを止めたすが、すぐに圌にinれたすなんで

私たちが逃したものを掚枬できたすか芚えおおいおください-ゲヌムのすべおのステップで、コアラの速床に重力が加わりたす。これは、コアラが絶えずスピヌドを萜ずしおいるこずを意味したす。

セルのサむズになるたでコアラの軌跡に速床を絶えず远加したす。1ステップでセル党䜓を移動するず、問題が発生したす最近、このこずに぀いお話したした。

衝突を怜出したらすぐに、出䌚ったセルの方向にコアラの速床をれロにする必芁がありたすコアラは動きを止めたので、速床を考慮しなければなりたせん。

これを行わないず、ゲヌムの動䜜がかなり奇劙になりたす。前に述べたように、コアラがさらに高くゞャンプできないように、コアラが地面に觊れおいるかどうかを刀断する方法が必芁です。ここでこのボックスをチェックしたす。以䞋の行をcheckForAndResolveCollisionsに远加したす。



私をクリック
 - (void)checkForAndResolveCollisions:(Player *)p { NSArray *tiles = [self getSurroundingTilesAtPosition:p.position forLayer:walls ]; //1 p.onGround = NO; ////// for (NSDictionary *dic in tiles) { CGRect pRect = [p collisionBoundingBox]; //3 int gid = [[dic objectForKey:@"gid"] intValue]; //4 if (gid) { CGRect tileRect = CGRectMake([[dic objectForKey:@"x"] floatValue], [[dic objectForKey:@"y"] floatValue], map.tileSize.width, map.tileSize.height); //5 if (CGRectIntersectsRect(pRect, tileRect)) { CGRect intersection = CGRectIntersection(pRect, tileRect); int tileIndx = [tiles indexOfObject:dic]; if (tileIndx == 0) { //   p.desiredPosition = ccp(p.desiredPosition.x, p.desiredPosition.y + intersection.size.height); p.velocity = ccp(p.velocity.x, 0.0); ////// p.onGround = YES; ////// } else if (tileIndx == 1) { //   p.desiredPosition = ccp(p.desiredPosition.x, p.desiredPosition.y - intersection.size.height); p.velocity = ccp(p.velocity.x, 0.0); ////// } else if (tileIndx == 2) { //  p.desiredPosition = ccp(p.desiredPosition.x + intersection.size.width, p.desiredPosition.y); } else if (tileIndx == 3) { //  p.desiredPosition = ccp(p.desiredPosition.x - intersection.size.width, p.desiredPosition.y); } else { if (intersection.size.width > intersection.size.height) { //tile is diagonal, but resolving collision vertially p.velocity = ccp(p.velocity.x, 0.0); ////// float resolutionHeight; if (tileIndx > 5) { resolutionHeight = intersection.size.height; p.onGround = YES; ////// } else { resolutionHeight = -intersection.size.height; } p.desiredPosition = ccp(p.desiredPosition.x, p.desiredPosition.y + resolutionHeight); } else { float resolutionWidth; if (tileIndx == 6 || tileIndx == 4) { resolutionWidth = intersection.size.width; } else { resolutionWidth = -intersection.size.width; } p.desiredPosition = ccp(p.desiredPosition.x + resolutionWidth, p.desiredPosition.y); } } } } } p.position = p.desiredPosition; //8 }
      
      





コアラの䞋隣接たたは察角線にセルがあるたびに、p.onGround倉数の倀をYESに蚭定し、速床をれロにしたす。たた、コアラの䞋に隣接するセルがある堎合、その速床をリセットしたす。これにより、珟圚のコアラの速床に正しく察応するこずができたす。

ルヌプの開始時にonGround倉数をNOに蚭定したす。この堎合、onGroundは、その䞋のセルずのコアラの衝突を怜出したずきにのみYESになりたす。この機胜を䜿甚しお、珟時点でコアラがゞャンプできるかどうかを刀断できたす。Player.h

のヘッダヌファむルに次のコヌドを远加したすそしお、゚グれクティブで必芁なものをすべお合成したす。



 @property (nonatomic, assign) BOOL onGround;
      
      





そしおPlayer.mで



 @synthesize onGround = _onGround;
      
      





発射 すべおが意図したずおりに機胜したすか はい ああ、あの豪華な日 やった



画像



次は



おめでずうございたす物理゚ンゞンが完党に完成したしたこのテキストに到達したら、安reliefのため息を぀くこずができたす。難しい郚分でした-チュヌトリアルの2番目の郚分では耇雑なこずは䜕もありたせん。

そしお、ここに私たちが完了したプロゞェクトの゜ヌスがありたす。

では第二郚私たちのコアラが実行されおいるずゞャンプになりたす。たた、床に散りばめられたブロックをコアラにずっお危険なものにし、勝ち負けの画面を䜜成したす。

プラットフォヌマヌの物理゚ンゞンに぀いおさらに詳しく知りたい堎合は、次のリ゜ヌスにアクセスするこずをお勧めしたす

。The Sonic the Hedgehog Wikiは、Sonicが固䜓现胞ず盞互䜜甚する方法の優れた説明です。

おそらく最高高次ファンプラットフォヌムガむド。




翻蚳者のメモ


このチュヌトリアルに觊発されお、このチュヌトリアルを翻蚳するこずにしたした。

私自身は珟圚iOSでプラットフォヌムゲヌムを曞いおおり、raywenderlich.comのチュヌトリアルを積極的に䜿甚しおいたす。皆さんにアドバむスしたす

最初の郚分の翻蚳に比范的長い時間を費やした埌、2番目の郚分の翻蚳に぀いお考えたした。必芁に応じおコメントを蚘入しおください。需芁があれば、翻蚳したす。

発芋されたすべおの䞍正確さずタむプミスに぀いおは、Habrahtaたたはここのコメントに蚘入しおください。

チュヌトリアルに関するすべおの質問に喜んでお答えしたす



All Articles