加入你的角色
如果你認為只有地圖,上面什麼都沒有,這實在是太孤單了!那你的想法跟我一樣,所以現在來增加角色吧!
完成的code放在最下面,大家也可以直接去看。
開始
放一個角色到地圖上,首先就是要指定你要讓角色出現在地圖上的哪個方塊裡面。
打開TileMap,然後打開剛做好的地圖,點選上方功能列的圖層,點選加入對象層,然後會在右方圖層中出現一個新的層,你可以改名稱為Objects。
點選操作視窗上方的插入對象,然後在你希望角色出現的方塊上面點一下,按右鍵,選擇對象屬性,進去之後在名稱的位置輸入SpawnPoint,這樣就好了。
存檔,然後接下來要介紹藍色部分的code了!
首先是在interface裡面新加入的變數,_player,用來記錄你的角色,可以尋找他的位置等等。
CCSprite *_player;
以及特性:
@property (nonatomic, retain) CCSprite *player;
當然就要實作:
@synthesize player = _player;
在dealloc裡面增加:
self.player = nil;
然後在init方法裡面,我們多了以下的code:
self.isTouchEnabled = YES;
開啟碰觸。
CCTMXObjectGroup *objects = [_tileMap objectGroupNamed:@"Objects"];
導入物件層。
NSAssert(objects != nil, @"'Objects' object group not found");
當物件層是空的時候,提出警告。
NSMutableDictionary *spawnPoint = [objects objectNamed:@"SpawnPoint"];
導入指定的位置。
NSAssert(spawnPoint != nil, @"SpawnPoint object not found");
當找不到這個位置的時候提出警告。
int x = [[spawnPoint valueForKey:@"x"] intValue];
int y = [[spawnPoint valueForKey:@"y"] intValue];
把該位置的座標輸出。
self.player = [CCSprite spriteWithFile:@"Player.png"];
_player.position = ccp(x, y);
把角色圖片定位在這個位置上。
[self addChild:_player];
把角色加入Layer裡。
[self setViewpointCenter:_player.position];
設定畫面的中心。
如果塗綠色會很刺眼,請留言跟我說。
保持player在螢幕的中心
當player移動時我們會希望鏡頭一直跟著,那這要怎麼辦到呢?就是加入以下方法:
-(void)setViewpointCenter:(CGPoint) position {
CGSize winSize = [[CCDirector sharedDirector] winSize];int x = MAX(position.x, winSize.width /2);int y = MAX(position.y, winSize.height /2);
x = MIN(x, (_tileMap.mapSize.width * _tileMap.tileSize.width) - winSize.width /2);
y = MIN(y, (_tileMap.mapSize.height * _tileMap.tileSize.height) - winSize.height/2);
CGPoint actualPosition = ccp(x, y);
CGPoint centerOfView = ccp(winSize.width/2, winSize.height/2);
CGPoint viewPoint = ccpSub(centerOfView, actualPosition);
self.position = viewPoint;
}
CGSize winSize = [[CCDirector sharedDirector] winSize];int x = MAX(position.x, winSize.width /2);int y = MAX(position.y, winSize.height /2);
x = MIN(x, (_tileMap.mapSize.width * _tileMap.tileSize.width) - winSize.width /2);
y = MIN(y, (_tileMap.mapSize.height * _tileMap.tileSize.height) - winSize.height/2);
CGPoint actualPosition = ccp(x, y);
CGPoint centerOfView = ccp(winSize.width/2, winSize.height/2);
CGPoint viewPoint = ccpSub(centerOfView, actualPosition);
self.position = viewPoint;
}
首先,這先取得了螢幕的大小。然後看看position的x座標是否比螢幕的一半來的大?看哪一個比較大,就取哪一個做為x值。也用一樣的方法得到一個y值。這樣可以讓x和y的值有一個最小下界。
然後比較這個x值和整個地圖的寬度(_tileMap.mapSize.width * _tileMap.tileSize.width)減去畫面的一半,然後把最小的作為新的x值輸出。注意到後者是固定值,這表示說,只要x沒有到太右邊,也就是太接近右邊地圖的邊界的話,就以這個x值為主,反之,x的極限就是地圖寬度減去螢幕一半寬了。
新的y值亦同,於是可以得到一個實際的位置。再來,定出螢幕的中心,取得螢幕中心到實際位置的向量(這邊我要再確認一下,感覺我弄反了),然後把地圖往這個向量的方向和大小移動,就可以定位在中心了。請大家一定要把這個方法學起來啊。
觸碰的方法
如果有接觸到cocos2D的touch方法,那就會發現,怎麼會有touch和touches的分別?當你使用touches時,依照一般的寫法,通常是沒問題的,就是將touches的點找出來,然後轉換成全域座標,再拿這座標去用。但是touch就不能這樣做了。如果你用一樣的想法去coding,你會遇到編譯上的問題。
原文裡面,他使用touch的方法,就是完整的解決方案。
首先,加入以下方法:
-(void) registerWithTouchDispatcher {
[[CCTouchDispatcher sharedDispatcher] addTargetedDelegate:self priority:0 swallowsTouches:YES];
}
然後再去寫ccTouchBegan的部分:
-(BOOL) ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event {
return YES;
}
-(void) ccTouchEnded:(UITouch *)touch withEvent:(UIEvent *)event {
CGPoint touchLocation = [touch locationInView:[touch view]];
touchLocation = [[CCDirector sharedDirector] convertToGL:touchLocation];
touchLocation = [self convertToNodeSpace:touchLocation];
CGPoint playerPos = _player.position;
CGPoint diff = ccpSub(touchLocation, playerPos);
if (abs(diff.x)>abs(diff.y)) {
if (diff.x > 0) {
playerPos.x += _tileMap.tileSize.width;
}else {
playerPos.x -= _tileMap.tileSize.width;
}
}else {
if (diff.y>0) {
playerPos.y += _tileMap.tileSize.height;
}else {
playerPos.y -= _tileMap.tileSize.height;
}
}
if (playerPos.x <= (_tileMap.mapSize.width * _tileMap.tileSize.width) &&
playerPos.y <= (_tileMap.mapSize.height * _tileMap.tileSize.height) &&
playerPos.y>=0 && playerPos.x >=0) {
[self setPlayerPosition:playerPos];
}
[self setViewpointCenter:_player.position];
}
只要配上registerWithTouchDispatcher,就可以安心地使用了。
再來說明一下began和end兩部分的方法。
began只是回傳Yes,表示觸碰了。
end是要去設定player的位置以及將player至於螢幕的中心。首先,取得player現在的位置,然後取得觸碰點和player現在位置的向量,使用if迴圈判斷該向量的x方向是否為正,若為正,就設定player的位置往右一格,反之,往左一格。如果該向量y方向的值為正,就設定player的位置往上一格,反之,往下一格。簡單說,一次動一格,簡單吧?
然後再用一個if迴圈,判斷如果player座標x部分小於等於地圖的寬度、y部分小於等於地圖的高度並且x和y都大於零,簡單說,就是player的座標還在地圖內,那麼就把player的位置用這個座標去設定,反之,就不設了,保持在原位。最後一行是讓player留在螢幕中心。
編譯看看吧!你應該會看到player,並且可以移動他。
成品
#import "cocos2d.h"
// HelloWorldLayer
@interface HelloWorldLayer : CCLayer
{
CCTMXTiledMap *_tileMap;
CCTMXLayer *_background;
CCSprite *_player;
}
@property (nonatomic, retain) CCTMXTiledMap *tileMap;
@property (nonatomic, retain) CCTMXLayer *background;
@property (nonatomic, retain) CCSprite *player = _player;
+(CCScene *) scene;
@end
以下是實作檔裡面的code:
#import "HelloWorldLayer.h"
// HelloWorldLayer implementation
@implementation HelloWorldLayer
@synthesize tileMap = _tileMap;
@synthesize background = _background;
@synthesize player = _player;
@synthesize player;
+(CCScene *) scene
{
CCScene *scene = [CCScene node];
HelloWorldLayer *layer = [HelloWorldLayer node];
[scene addChild: layer];
return scene;
}
-(void) setViewpointCenter:(CGPoint) position {
CGSize winSize = [CCDirector sharedDirector].winSize;
int x = MAX(position.x, winSize.width/2);
int y = MAX(position.y, winSize.height/2);
x = MIN(x, (_tileMap.mapSize.width * _tileMap.tileSize.width) - winSize.width/2);
y = MIN(y, (_tileMap.mapSize.height * _tileMap.tileSize.height) - winSize.height/2);
CGPoint actualPosition = ccp(x, y);
CGPoint centerOfView = ccp(winSize.width/2, winSize.height/2);
CGPoint viewPoint = ccpSub(centerOfView, actualPosition);
self.position = viewPoint;
}
// on "init" you need to initialize your instance
-(id) init
{
if( (self=[super init])) {
self.isTouchEnabled = YES;
self.tileMap = [CCTMXTiledMap tiledMapWithTMXFile:@"TileMap.tmx"];
self.background = [_tileMap layerNamed:@"Background"];
CCTMXObjectGroup *objects = [_tileMap objectGroupNamed:@"Objects"];
NSAssert(objects != nil, @"'Objects' object group not found");
NSMutableDictionary *spawnPoint = [objects objectNamed:@"SpawnPoint"];
NSAssert(spawnPoint != nil, @"SpawnPoint object not found");
int x = [[spawnPoint valueForKey:@"x"] intValue];
int y = [[spawnPoint valueForKey:@"y"] intValue];
_player = [CCSprite spriteWithFile:@"Player.png"];
_player.position = ccp(x, y);
[self addChild:_player];
[self setViewpointCenter:_player.position];
[self addChild:_tileMap z:-1];
}
return self;
}
-(void) registerWithTouchDispatcher {
[[CCTouchDispatcher sharedDispatcher] addTargetedDelegate:self priority:0 swallowsTouches:YES];
}
-(BOOL) ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event {
return YES;
}
-(void) setPlayerPosition:(CGPoint)position {
_player.position = position;
}
-(void) ccTouchEnded:(UITouch *)touch withEvent:(UIEvent *)event {
CGPoint touchLocation = [touch locationInView:[touch view]];
touchLocation = [[CCDirector sharedDirector] convertToGL:touchLocation];
touchLocation = [self convertToNodeSpace:touchLocation];
CGPoint playerPos = _player.position;
CGPoint diff = ccpSub(touchLocation, playerPos);
if (abs(diff.x)>abs(diff.y)) {
if (diff.x > 0) {
playerPos.x += _tileMap.tileSize.width;
}else {
playerPos.x -= _tileMap.tileSize.width;
}
}else {
if (diff.y>0) {
playerPos.y += _tileMap.tileSize.height;
}else {
playerPos.y -= _tileMap.tileSize.height;
}
}
if (playerPos.x <= (_tileMap.mapSize.width * _tileMap.tileSize.width) &&
playerPos.y <= (_tileMap.mapSize.height * _tileMap.tileSize.height) &&
playerPos.y>=0 && playerPos.x >=0) {
[self setPlayerPosition:playerPos];
}
[self setViewpointCenter:_player.position];
}
// on "dealloc" you need to release all your retained objects
- (void) dealloc
{
self.tileMap = nil;
self.background = nil;
self.player = nil;
[super dealloc];
}
@end
留言
張貼留言