http://www.cocos2d-iphone.org/forum/topic/8424
애드몹을 사용 하시기 위해서는 위의 사이트에서 등록 하여 고유 넘버 키를 받으셔야 사용이가능 합니다.
참고 사이트 입니다.


=============================================================================
AdViewController.h
#import <UIKit/UIKit.h>
#import <iAd/iAd.h>
#import "AdMobDelegateProtocol.h"

@protocol AdViewControllerDelegate;

@interface AdViewController : UIViewController <ADBannerViewDelegate, AdMobDelegate>
{
 id <AdViewControllerDelegate> delegate;
 id adBannerView;

 AdMobView* adMobAd;
}

@property (nonatomic, assign) id <AdViewControllerDelegate> delegate;

- (id)initWithMasterView:(UIView*)masterView;
- (void)rotateBannerView:(UIDeviceOrientation)toDeviceOrientation;

@end

@protocol AdViewControllerDelegate

- (void)adController:(AdViewController*)controller didLoadiAd:(id)iadBanner;
- (void)adController:(AdViewController*)controller didFailedToRecieveiAd:(id)iadBanner;

- (void)adController:(AdViewController*)controller didLoadAdMobAd:(AdMobView*)adMobBanner;
- (void)adController:(AdViewController*)controller didFailedToRecieveAdMobAd:(AdMobView*)adMobBanner;

@end

AdViewController.m

#import "AdViewController.h"
#import "cocos2d.h"

#import "AdMobView.h"

@implementation AdViewController

@synthesize delegate;

- (UIDeviceOrientation)currentOrientation
{
 return [[CCDirector sharedDirector] deviceOrientation];
}

- (id) initWithMasterView:(UIView*) masterView
{
 if( nil != (self = [super init]) )
 {
  [self setView:masterView];

  //Initialize the class manually to make it compatible with iOS < 4.0
  Class classAdBannerView = NSClassFromString(@"ADBannerView");
  if (classAdBannerView != nil)
  {
   adBannerView = [[classAdBannerView alloc] initWithFrame:CGRectZero];
   [adBannerView setDelegate:self];
   [adBannerView setRequiredContentSizeIdentifiers: [NSSet setWithObjects:
                 ADBannerContentSizeIdentifier320x50,
                 ADBannerContentSizeIdentifier480x32, nil]];

   [self.view addSubview:adBannerView];

   [self rotateBannerView:[self currentOrientation]];

   [adBannerView setHidden:YES];

  }
  else
  {
   //Request an AdMob Ad
   adMobAd = [AdMobView requestAdOfSize:ADMOB_SIZE_320x48 withDelegate:self];
   [adMobAd retain];
  }
 }

 return self;
}

- (void)rotateBannerView:(UIDeviceOrientation)toDeviceOrientation
{
 if (adBannerView)
 {
  if (UIDeviceOrientationIsLandscape(toDeviceOrientation))
   [adBannerView setCurrentContentSizeIdentifier:ADBannerContentSizeIdentifier480x32];
  else
   [adBannerView setCurrentContentSizeIdentifier:ADBannerContentSizeIdentifier320x50];

  [(UIView*)adBannerView setTransform:CGAffineTransformIdentity];

  //Set the transformation for each orientation
  switch (toDeviceOrientation)
  {
   case UIDeviceOrientationPortrait:
   {
    [(UIView*)adBannerView setCenter:CGPointMake(160, 455)];
   }
    break;
   case UIDeviceOrientationPortraitUpsideDown:
   {
    [(UIView*)adBannerView setTransform:CGAffineTransformMakeRotation(CC_DEGREES_TO_RADIANS(180))];
    [adBannerView setCenter:CGPointMake(160, 25)];
   }
    break;
   case UIDeviceOrientationLandscapeLeft:
   {
    [(UIView*)adBannerView setTransform:CGAffineTransformMakeRotation(CC_DEGREES_TO_RADIANS(90))];
    [adBannerView setCenter:CGPointMake(16, 240)];
   }
    break;
   case UIDeviceOrientationLandscapeRight:
   {
    [(UIView*)adBannerView setTransform:CGAffineTransformMakeRotation(CC_DEGREES_TO_RADIANS(-90))];
    [adBannerView setCenter:CGPointMake(304, 240)];
   }
    break;
   default:
    break;
  }
 }

 if (adMobAd)
 {
  [adMobAd setTransform:CGAffineTransformIdentity];

  //Set the transformation for each orientation
  switch (toDeviceOrientation)
  {
   case UIDeviceOrientationPortrait:
   {
    [adMobAd setCenter:CGPointMake(160, 456)];
   }
    break;
   case UIDeviceOrientationPortraitUpsideDown:
   {
    [adMobAd setTransform:CGAffineTransformMakeRotation(CC_DEGREES_TO_RADIANS(180))];
    [adMobAd setCenter:CGPointMake(160, 24)];
   }
    break;
   case UIDeviceOrientationLandscapeLeft:
   {
    [adMobAd setTransform:CGAffineTransformMakeRotation(CC_DEGREES_TO_RADIANS(90))];
    [adMobAd setCenter:CGPointMake(24, 240)];
   }
    break;
   case UIDeviceOrientationLandscapeRight:
   {
    [adMobAd setTransform:CGAffineTransformMakeRotation(CC_DEGREES_TO_RADIANS(-90))];
    [adMobAd setCenter:CGPointMake(296, 240)];
   }
    break;
   default:
    break;
  }
 }
}

#pragma mark -
#pragma mark ADBannerViewDelegate

- (BOOL)allowActionToRun
{
 return YES;
}

- (void) stopActionsForAd
{
 //Pause background music here

 [adBannerView setHidden:YES];

 [[CCDirector sharedDirector] stopAnimation];
 [[CCDirector sharedDirector] pause];
}

- (void) startActionsForAd
{
 //Resume background music here

 [self rotateBannerView:[self currentOrientation]];
 [[UIApplication sharedApplication] setStatusBarOrientation:(UIInterfaceOrientation)[self currentOrientation]];
 [adBannerView setHidden:NO];

 [[CCDirector sharedDirector] stopAnimation];
 [[CCDirector sharedDirector] resume];
 [[CCDirector sharedDirector] startAnimation];
}

- (BOOL)bannerViewActionShouldBegin:(ADBannerView *)banner willLeaveApplication:(BOOL)willLeave
{
 BOOL shouldExecuteAction = [self allowActionToRun];
    if (!willLeave && shouldExecuteAction)
    {
  [self stopActionsForAd];
    }
    return shouldExecuteAction;
}

- (void)bannerViewDidLoadAd:(ADBannerView *)banner
{
 [adBannerView setHidden:NO];
 [delegate adController:self didLoadiAd:banner];
}

- (void)bannerView:(ADBannerView *)banner didFailToReceiveAdWithError:(NSError *)error
{
 [adBannerView setHidden:YES];
 [delegate adController:self didFailedToRecieveiAd:banner];
}

- (void)bannerViewActionDidFinish:(ADBannerView *)banner
{
 [self startActionsForAd];
}

#pragma mark -
#pragma mark AdMobDelegate methods

- (NSString *)publisherIdForAd:(AdMobView *)adView
{
 return @"your_admob_publisher_id";    //replace it with you publisher id
}

- (UIViewController *)currentViewControllerForAd:(AdMobView *)adView {
 return self;
}

- (UIColor *)adBackgroundColorForAd:(AdMobView *)adView
{
 return [UIColor colorWithRed:0 green:0 blue:0 alpha:1]; // this should be prefilled; if not, provide a UIColor
}

- (UIColor *)primaryTextColorForAd:(AdMobView *)adView
{
 return [UIColor colorWithRed:1 green:1 blue:1 alpha:1]; // this should be prefilled; if not, provide a UIColor
}

- (UIColor *)secondaryTextColorForAd:(AdMobView *)adView
{
 return [UIColor colorWithRed:1 green:1 blue:1 alpha:1]; // this should be prefilled; if not, provide a UIColor
}

- (NSArray *)testDevices
{
 return [NSArray arrayWithObjects: ADMOB_SIMULATOR_ID, nil];
}

- (void)didReceiveAd:(AdMobView *)adView
{
 CCLOG(@"AdMob: Did receive ad");

 [self rotateBannerView:[self currentOrientation]];
 [self.view addSubview:adMobAd];

 [delegate adController:self didLoadAdMobAd:adView];
}

// Sent when an ad request failed to load an ad
- (void)didFailToReceiveAd:(AdMobView *)adView
{
 CCLOG(@"AdMob: Did fail to receive ad");
 [adMobAd removeFromSuperview];
 [adMobAd release];
 adMobAd = nil;

 [delegate adController:self didFailedToRecieveAdMobAd:adView];
}

#pragma mark -
#pragma mark Memory Management

- (void) dealloc
{
 if (adMobAd)
 {
  [adMobAd setDelegate:nil];
  [adMobAd removeFromSuperview];
  [adMobAd release];
  adMobAd = nil;
 }

 if (adBannerView)
 {
  [adBannerView setDelegate:nil];
  [adBannerView removeFromSuperview];
  [adBannerView release];
  adBannerView = nil;
 }

    [super dealloc];
}

@end

The usage is very simple, #importAdViewController.h in you Layer's .h and add the delegate protocol AdViewControllerDelegate

#import "AdViewController.h"

@interface Menu : CCLayer <AdViewControllerDelegate>
{
 AdViewController *adController;
}

And in your layer's .m add this

- (void)onEnter
{
 [super onEnter];

 adController = [[AdViewController alloc] initWithMasterView:[[CCDirector sharedDirector] openGLView]];
 [adController setDelegate:self];

}

- (void)onExit
{
 //Completely remove the controller
 [adController setDelegate:nil];
 [adController release];
 adController = nil;

 [super onExit];
}

- (void)adController:(AdViewController*)controller didLoadiAd:(id)iadBanner;
{
 //Do something when the ad loads, like moving objects.
}

- (void)adController:(AdViewController*)controller didFailedToRecieveiAd:(id)iadBanner;
{
 //Do something when the ad fails to load, like moving objects.;
}

- (void)adController:(AdViewController*)controller didLoadAdMobAd:(AdMobView*)adMobBanner;
{
 //Do something when the ad loads, like moving objects.
}

- (void)adController:(AdViewController*)controller didFailedToRecieveAdMobAd:(AdMobView*)adMobBanner;
{
 //Do something when the ad fails to load, like moving objects.
}
<script src="http://gods2000.tistory.com/plugin/CallBack_bootstrapper?&src=https://s1.daumcdn.net/cfs.tistory/v/0/blog/plugins/CallBack/callback&id=29&callbackId=gods2000tistorycom292340&destDocId=callbacknestgods2000tistorycom292340&host=http://gods2000.tistory.com&float=left&random=631"></script> 출처 :http://gods2000.tistory.com/29
Posted by 오늘마감

작업을 하던중 코코스와 sio2 엔진을 통합하면 좀 편하겠다. 싶어서

통합해 보았습니다.
http://www.cocos2d-iphone.org/forum/topic/3620#post-26503 문서의

yarri 님 글을 참고 했는데 오래된 버전으로 작성되어 있어 차이점이 좀 있었습니다.

맥 초보분들도 이해하기 쉽게 따라하는 식으로 써볼게요.


기본 준비물

cocos2d 0.99.4 설치

sio2 1.4 버전 다운로드


1. cocos2d는 xcode템플릿을 지원하므로 'cocos2d application' 템플릿으로 프로젝트를 생성합니다. ( ex, cocos2d_lib )

 

 

 

 


 소스만 사용할 것이므로 xcode를 종료합니다.

 

2. sio2는 template이라는 폴더를 복사하는 방식으로 새프로젝트를 생성하고 있습니다. 기본 template을 사용해도 무방하지만 리소스를 랜더링 하고 있는 tutorial02를 복사본을 뜬후 이름을 변경합니다. (ex, sio2withcocos2d) 이때 src 폴더와 data 폴더도 같이 복사해줍니다.

 

 

 

 

 

 

3. sio2withcocos2d 폴더내의 template.xcodeproj 를 열고 프로젝트 이름을 본인에 맞게 변경합니다. (변경안해도 상관은 없겠죠)


4. cocos2d에서 필요한 파일들을 sio2withcocos2d 폴더로 복사 합니다. libs, Resources 폴더를 복사한후 Resources폴더 내에서 fps_images.png만 남기고 지웁니다.






출처 : http://blog.naver.com/PostView.nhn?blogId=kkuri1976a&logNo=30092850805
Posted by 오늘마감
[cocos2D] 2D Scrolling Game with Cocos2D TileMap with Zoom!

A common question I see on the cocos2d forums is ‘when I want to make my game scroll, do I move the camera or the layer?’ or some variant of that. I also got some more detailed questions about how to make a functioning 2D scroller, so I’m going to described how I got it to work.

First of all, the answer to the above question is you move the layer. If you follow the examples in the cocos2d download, you have a “GameScene” and a “GameLayer”. Well, everything that needs to be moved when your game scrolls should be added as a child to that GameLayer. If you are using a TileMap as a background, this includes that tilemap. The only thing that you don’t add as a child to the GameLayer is stuff that does not move with the scrolling view, such as your HUDLayer that has text that shows your characters health. Other than that, your character, the background, other characters, should all be added to the GameLayer.

You have to remember which objects are absolute (attached to your GameScene or other layers) versus those that are relative (a child of your GameLayer) when you set up your touch handling code. For my HUD that has buttons you can press at any time, say to pause the game, you want to add the touch handling object to your GameScene or HUDLayer class, since it doesn’t move. But if you want to be able to touch objects that scroll along with your view in the game itself, your touch handling code needs to be in an object that is a child of your GameLayer.

This might be a little confusing, so let’s see some code:

gameLayer = [GameLayer node]; [gameScene addChild:gameLayer z:zOrder_GameLayer];   hudLayer = [HUDLayer node]; [gameScene addChild:hudLayer z:zOrder_HudLayer];   tileMap = [BGTileMap node]; [gameLayer addChild:tileMap z:-1];   [gameScene addChild:[PauseGameButton node] z:zOrder_GameButtons]; [gameLayer addChild:[FireGunAtTouchPoint node]];

The pause game button is always on your screen, while the point at which your character fires the gun depends on how how far your view has been scrolled (by moving GameLayer).

Let’s see some of the code that actually moves this game layer:

- (void)setViewpointCenter:(CGPoint)point { CGPoint centerPoint = ccp(240, 160); viewPoint = ccpSub(centerPoint, point);   // dont scroll so far so we see anywhere outside the visible map which would show up as black bars if(point.x &lt; centerPoint.x) viewPoint.x = 0; if(point.y &lt; centerPoint.y) viewPoint.y = 0;   // while zoomed out, don't adjust the viewpoint if(!isZoomedOut) gameLayer.position = viewPoint; }

When do you call that method? Well, it depends on what you want, but generally these scrolling games follow around the movement of your ‘main’ character, right? So whatever character the you want to follow, add this to override the standard CocosNode setPosition method so you update your viewpoint whenever the character moves

- (void)setPosition:(CGPoint)point { [[StandardGameController sharedSingleton] setViewpointCenter:point]; [super setPosition:point]; }

Note that the StandardGameController is a construct of mine that I use to separate the game logic out from the display code. It doesn’t matter exactly how you do it, you just need a way to have your main character object call back to something that contains a reference to GameLayer so it can adjust the position of your GameLayer.

Now remember, for your background to scroll properly, you need to add your background tileMap as a child of your GameLayer that is being moved around.

That being said, I found that an important method was missing from the cocos2d tilemap that I need to use in order to detect collisions based on the types of tiles encountered. I created a subclass of TMXTiledMap and added in these methods:

- (CGPoint)coordinatesAtPosition:(CGPoint)point { return ccp((int)(point.x / self.tileSize.width), (int)(self.mapSize.height - (point.y / self.tileSize.height))); }   - (unsigned int)getGIDAtPosition:(CGPoint)point { return [layer tileGIDAt:[self coordinatesAtPosition:point]]; }

That way it’s easy to figure out what tile any individual object is colliding with. For example, in my main character object I can have code that runs in step: function with this:

BGTileMap* tileMap = [StandardGameController sharedSingleton].tileMap; CGPoint coordinate = [tileMap coordinatesAtPosition:self.position]; BBLog(@"Right now on tile %d",[tileMap.layer tileGIDAt:coordinate]);

Now I know what type of tile I am overlapping, and I can respond to the environment accordingly.

This is really all the code that you need to make a scrolling game view…I think some people overthink it and try adjusting the position of every object individually with some offset, but it’s not necessary since your objects can use relative positions with their parent.

I have one last bit of code to add, and this is something kind of fun. It’s not complete, but at least it’s a start. What this allows you to do is ‘zoom out’ so you can see your entire map with ALL the objects shrunk down, and then zoom back in to your character. The only tricky part is when you zoom back in, you have to slowly adjust your viewpoint in steps so the zoom in action is centered on your character, instead of jumping at the end.

#define ZOOM_BACK_IN_INTERVALS 10 #define ZOOM_OUT_RATE 0.3 // TODO need to refine this so for each step it uses the new viewpoint - (void)setZoom:(BOOL)zoomedIn { BBLog(@"Zooming in %d", zoomedIn);   // this scales it out so the whole height of the tilemap is in the screen float zoomScaleFactor = 320 / (tileMap.mapSize.height * tileMap.tileSize.height); if(zoomedIn) { [gameLayer runAction:[ScaleTo actionWithDuration:ZOOM_OUT_RATE scale:1.0]]; [gameLayer runAction:[MoveTo actionWithDuration:ZOOM_OUT_RATE position:viewPoint]]; [self schedule:@selector(setZoomedBackIn:) interval:ZOOM_OUT_RATE]; // need this for the transistion } else { [gameLayer runAction:[ScaleTo actionWithDuration:ZOOM_OUT_RATE scale:zoomScaleFactor]]; [gameLayer runAction:[MoveTo actionWithDuration:ZOOM_OUT_RATE position:ccp(0,0)]]; isZoomedOut = YES; } }   // need this small correction at the end to account of the player is moving and the viewpoint has changed to avoid jitter #define ZOOM_OUT_CORRECTION_RATE 0.3 - (void)setZoomedBackIn:(ccTime)dt { [self unschedule:@selector(setZoomedBackIn:)]; [gameLayer runAction:[MoveTo actionWithDuration:ZOOM_OUT_CORRECTION_RATE position:viewPoint]]; [self schedule:@selector(setZoomedBackInFinished:) interval:ZOOM_OUT_CORRECTION_RATE]; // need this for the transistion }   - (void)setZoomedBackInFinished:(ccTime)dt { [self unschedule:@selector(setZoomedBackInFinished:)]; isZoomedOut = NO; }

Now you see why my viewPoint variable was a class member…you’ll need it for these methods to work.

The reason this code isn’t complete is when it starts zooming in, it creates the actions to zoom in on the current viewpoint, but if the player is moving by the time the zoom animation is done, that viewpoint is changed and needs to ’snap’ to the new viewpoint. That is the reason for the setZoomedBackIn: method, which really shouldn’t have to move the gameLayer anymore. However, I haven’t yet written the code to continuously create smaller move actions to take into account a moving viewpoint as the animation continues, but doing so shouldn’t be that hard. If you want to see that bit when I finish, post in the comments and I’ll add it in.


http://johnehartzog.com/2009/10/2d-scrolling-game-with-cocos2d-tilemap-with-zoom/

Posted by 오늘마감
[cocos2D] Easy To Create Buttons with Cocos2D

Those of you who use cocos2d a lot might understand why I created this class as some point. Hopefully it may save some of you those nasty 5 line blobs that you normally need to create a simple button. Usage is simple, just do:

[self addChild:[Button buttonWithText:@"back" atPosition:ccp(80, 50) target:self selector:@selector(back:)]]; [self addChild:[Button buttonWithImage:@"openFeint.png" atPosition:ccp(400, 50) target:self selector:@selector(openOpenFeint:)]];

You’ll need to create your own button.png and button_p.png (the second one is the image shown when you are touching the button). Also you’ll need to choose your own font. Here is the code…

// // Button.h // StickWars - Siege // // Created by EricH on 8/3/09. //   @interface Button : Menu { } + (id)buttonWithText:(NSString*)text atPosition:(CGPoint)position target:(id)target selector:(SEL)selector; + (id)buttonWithImage:(NSString*)file atPosition:(CGPoint)position target:(id)target selector:(SEL)selector; @end   @interface ButtonItem : MenuItem { Sprite *back; Sprite *backPressed; } + (id)buttonWithText:(NSString*)text target:(id)target selector:(SEL)selector; + (id)buttonWithImage:(NSString*)file target:(id)target selector:(SEL)selector; - (id)initWithText:(NSString*)text target:(id)target selector:(SEL)selector; - (id)initWithImage:(NSString*)file target:(id)target selector:(SEL)selector; @end
// // Button.m // StickWars - Siege // // Created by EricH on 8/3/09. //   #import "Button.h"     @implementation Button + (id)buttonWithText:(NSString*)text atPosition:(CGPoint)position target:(id)target selector:(SEL)selector { Menu *menu = [Menu menuWithItems:[ButtonItem buttonWithText:text target:target selector:selector], nil]; menu.position = position; return menu; }   + (id)buttonWithImage:(NSString*)file atPosition:(CGPoint)position target:(id)target selector:(SEL)selector { Menu *menu = [Menu menuWithItems:[ButtonItem buttonWithImage:file target:target selector:selector], nil]; menu.position = position; return menu; } @end   @implementation ButtonItem + (id)buttonWithText:(NSString*)text target:(id)target selector:(SEL)selector { return [[[self alloc] initWithText:text target:target selector:selector] autorelease]; }   + (id)buttonWithImage:(NSString*)file target:(id)target selector:(SEL)selector { return [[[self alloc] initWithImage:file target:target selector:selector] autorelease]; }   - (id)initWithText:(NSString*)text target:(id)target selector:(SEL)selector { if(self = [super initWithTarget:target selector:selector]) { back = [[Sprite spriteWithFile:@"button.png"] retain]; back.anchorPoint = ccp(0,0); backPressed = [[Sprite spriteWithFile:@"button_p.png"] retain]; backPressed.anchorPoint = ccp(0,0); [self addChild:back];   self.contentSize = back.contentSize;   Label* textLabel = [Label labelWithString:text fontName:@"take_out_the_garbage" fontSize:22]; textLabel.position = ccp(self.contentSize.width / 2, self.contentSize.height / 2); textLabel.anchorPoint = ccp(0.5, 0.3); [self addChild:textLabel z:1]; } return self; }   - (id)initWithImage:(NSString*)file target:(id)target selector:(SEL)selector { if(self = [super initWithTarget:target selector:selector]) {   back = [[Sprite spriteWithFile:@"button.png"] retain]; back.anchorPoint = ccp(0,0); backPressed = [[Sprite spriteWithFile:@"button_p.png"] retain]; backPressed.anchorPoint = ccp(0,0); [self addChild:back];   self.contentSize = back.contentSize;   Sprite* image = [Sprite spriteWithFile:file]; [self addChild:image z:1]; image.position = ccp(self.contentSize.width / 2, self.contentSize.height / 2); } return self; }   -(void) selected { [self removeChild:back cleanup:NO]; [self addChild:backPressed]; [super selected]; }   -(void) unselected { [self removeChild:backPressed cleanup:NO]; [self addChild:back]; [super unselected]; }   // this prevents double taps - (void)activate { [super activate]; [self setIsEnabled:NO]; [self schedule:@selector(resetButton:) interval:0.5]; }   - (void)resetButton:(ccTime)dt { [self unschedule:@selector(resetButton:)]; [self setIsEnabled:YES]; }   - (void)dealloc { [back release]; [backPressed release]; [super dealloc]; }   @end

A common question I see on the cocos2d forums is ‘when I want to make my game scroll, do I move the camera or the layer?’ or some variant of that. I also got some more detailed questions about how to make a functioning 2D scroller, so I’m going to described how I got it to work.

First of all, the answer to the above question is you move the layer. If you follow the examples in the cocos2d download, you have a “GameScene” and a “GameLayer”. Well, everything that needs to be moved when your game scrolls should be added as a child to that GameLayer. If you are using a TileMap as a background, this includes that tilemap. The only thing that you don’t add as a child to the GameLayer is stuff that does not move with the scrolling view, such as your HUDLayer that has text that shows your characters health. Other than that, your character, the background, other characters, should all be added to the GameLayer.

You have to remember which objects are absolute (attached to your GameScene or other layers) versus those that are relative (a child of your GameLayer) when you set up your touch handling code. For my HUD that has buttons you can press at any time, say to pause the game, you want to add the touch handling object to your GameScene or HUDLayer class, since it doesn’t move. But if you want to be able to touch objects that scroll along with your view in the game itself, your touch handling code needs to be in an object that is a child of your GameLayer.

This might be a little confusing, so let’s see some code:

gameLayer = [GameLayer node]; [gameScene addChild:gameLayer z:zOrder_GameLayer];   hudLayer = [HUDLayer node]; [gameScene addChild:hudLayer z:zOrder_HudLayer];   tileMap = [BGTileMap node]; [gameLayer addChild:tileMap z:-1];   [gameScene addChild:[PauseGameButton node] z:zOrder_GameButtons]; [gameLayer addChild:[FireGunAtTouchPoint node]];

The pause game button is always on your screen, while the point at which your character fires the gun depends on how how far your view has been scrolled (by moving GameLayer).

Let’s see some of the code that actually moves this game layer:

- (void)setViewpointCenter:(CGPoint)point { CGPoint centerPoint = ccp(240, 160); viewPoint = ccpSub(centerPoint, point);   // dont scroll so far so we see anywhere outside the visible map which would show up as black bars if(point.x &lt; centerPoint.x) viewPoint.x = 0; if(point.y &lt; centerPoint.y) viewPoint.y = 0;   // while zoomed out, don't adjust the viewpoint if(!isZoomedOut) gameLayer.position = viewPoint; }

When do you call that method? Well, it depends on what you want, but generally these scrolling games follow around the movement of your ‘main’ character, right? So whatever character the you want to follow, add this to override the standard CocosNode setPosition method so you update your viewpoint whenever the character moves

- (void)setPosition:(CGPoint)point { [[StandardGameController sharedSingleton] setViewpointCenter:point]; [super setPosition:point]; }

Note that the StandardGameController is a construct of mine that I use to separate the game logic out from the display code. It doesn’t matter exactly how you do it, you just need a way to have your main character object call back to something that contains a reference to GameLayer so it can adjust the position of your GameLayer.

Now remember, for your background to scroll properly, you need to add your background tileMap as a child of your GameLayer that is being moved around.

That being said, I found that an important method was missing from the cocos2d tilemap that I need to use in order to detect collisions based on the types of tiles encountered. I created a subclass of TMXTiledMap and added in these methods:

- (CGPoint)coordinatesAtPosition:(CGPoint)point { return ccp((int)(point.x / self.tileSize.width), (int)(self.mapSize.height - (point.y / self.tileSize.height))); }   - (unsigned int)getGIDAtPosition:(CGPoint)point { return [layer tileGIDAt:[self coordinatesAtPosition:point]]; }

That way it’s easy to figure out what tile any individual object is colliding with. For example, in my main character object I can have code that runs in step: function with this:

BGTileMap* tileMap = [StandardGameController sharedSingleton].tileMap; CGPoint coordinate = [tileMap coordinatesAtPosition:self.position]; BBLog(@"Right now on tile %d",[tileMap.layer tileGIDAt:coordinate]);

Now I know what type of tile I am overlapping, and I can respond to the environment accordingly.

This is really all the code that you need to make a scrolling game view…I think some people overthink it and try adjusting the position of every object individually with some offset, but it’s not necessary since your objects can use relative positions with their parent.

I have one last bit of code to add, and this is something kind of fun. It’s not complete, but at least it’s a start. What this allows you to do is ‘zoom out’ so you can see your entire map with ALL the objects shrunk down, and then zoom back in to your character. The only tricky part is when you zoom back in, you have to slowly adjust your viewpoint in steps so the zoom in action is centered on your character, instead of jumping at the end.

#define ZOOM_BACK_IN_INTERVALS 10 #define ZOOM_OUT_RATE 0.3 // TODO need to refine this so for each step it uses the new viewpoint - (void)setZoom:(BOOL)zoomedIn { BBLog(@"Zooming in %d", zoomedIn);   // this scales it out so the whole height of the tilemap is in the screen float zoomScaleFactor = 320 / (tileMap.mapSize.height * tileMap.tileSize.height); if(zoomedIn) { [gameLayer runAction:[ScaleTo actionWithDuration:ZOOM_OUT_RATE scale:1.0]]; [gameLayer runAction:[MoveTo actionWithDuration:ZOOM_OUT_RATE position:viewPoint]]; [self schedule:@selector(setZoomedBackIn:) interval:ZOOM_OUT_RATE]; // need this for the transistion } else { [gameLayer runAction:[ScaleTo actionWithDuration:ZOOM_OUT_RATE scale:zoomScaleFactor]]; [gameLayer runAction:[MoveTo actionWithDuration:ZOOM_OUT_RATE position:ccp(0,0)]]; isZoomedOut = YES; } }   // need this small correction at the end to account of the player is moving and the viewpoint has changed to avoid jitter #define ZOOM_OUT_CORRECTION_RATE 0.3 - (void)setZoomedBackIn:(ccTime)dt { [self unschedule:@selector(setZoomedBackIn:)]; [gameLayer runAction:[MoveTo actionWithDuration:ZOOM_OUT_CORRECTION_RATE position:viewPoint]]; [self schedule:@selector(setZoomedBackInFinished:) interval:ZOOM_OUT_CORRECTION_RATE]; // need this for the transistion }   - (void)setZoomedBackInFinished:(ccTime)dt { [self unschedule:@selector(setZoomedBackInFinished:)]; isZoomedOut = NO; }

Now you see why my viewPoint variable was a class member…you’ll need it for these methods to work.

The reason this code isn’t complete is when it starts zooming in, it creates the actions to zoom in on the current viewpoint, but if the player is moving by the time the zoom animation is done, that viewpoint is changed and needs to ’snap’ to the new viewpoint. That is the reason for the setZoomedBackIn: method, which really shouldn’t have to move the gameLayer anymore. However, I haven’t yet written the code to continuously create smaller move actions to take into account a moving viewpoint as the animation continues, but doing so shouldn’t be that hard. If you want to see that bit when I finish, post in the comments and I’ll add it in.

Posted by 오늘마감
[cocos2D] Using Box2D Physics Engine with Cocos2D iPhone

Starting work on my new project, I’ve found Box2D to be a far superior physics engine than chipmunk. It is more mature, the API more flexible, and it seems to even perform faster. However, the cocos2d code for it was rather space, so here is a sort of helper file I had to create to make it work with my game.

Keep in mind this game is in progress and I’ve only been using this for a few days, so it may have issues that might pop up later on. It seems to be working very well for now though, with 40-50 objects on screen moving around with ~40 FPS.

Here is the header

// // Box2DEngine.h // // Created by EricH on 7/22/09. // Copyright 2009 __MyCompanyName__. All rights reserved. //   #import "Box2D.h"   // made this an extern constant to avoid obj c lookup overhead extern b2World *bb_world;   @interface Box2DEngine : CocosNode { }   + (Box2DEngine *)sharedSingleton; - (void)createWorld:(CGSize)size; - (void)deleteWorld; - (void)runSimulation; @end

The .mm file

// // Box2DEngine.mm // // Created by EricH on 7/22/09. // Copyright 2009 __MyCompanyName__. All rights reserved. //   #import "HookActor.h"     #import "Box2DEngine.h" #import "SuperBox2DActor.h"   b2World* bb_world;   const float32 timeStep = 1.0f / 60.0f; const int32 velocityIterations = 10; const int32 positionIterations = 10;   #define MAX_NUM_COLLISIONS 2048 // TODO make sure this buffer is the right size b2ContactResult contactResultCache[MAX_NUM_COLLISIONS]; int32 contactResultCount = 0;   class MyContactListener : public b2ContactListener { public: void Add(const b2ContactPoint* point) { }   void Persist(const b2ContactPoint* point) { }   void Remove(const b2ContactPoint* point) { }   void Result(const b2ContactResult* point) { // TODO we are making a deep copy of every contact point here // check the box2d contact masks to make sure we minimize unwanted contact results contactResultCache[contactResultCount++] = *point; } };   void handleCachedContactResults() { b2ContactResult contactResult; for(int i = 0; i < contactResultCount; i++) { #ifdef BBDEBUG if(contactResultCount >= MAX_NUM_COLLISIONS) { NSLog(@"RAN OUT OF BUFFER"); assert(NO); } #endif contactResult = contactResultCache[i]; SuperBox2DActor* actorOne = (SuperBox2DActor*)contactResult.shape1->GetBody()->GetUserData(); SuperBox2DActor* actorTwo = (SuperBox2DActor*)contactResult.shape2->GetBody()->GetUserData(); if(!actorOne.isDead && !actorTwo.isDead) { [actorOne collisionResultOne:&contactResult withActor:actorTwo]; [actorTwo collisionResultTwo:&contactResult withActor:actorOne]; } }   // clear the collision cache contactResultCount = 0; }   void removeDeadActors() { b2Body* node = bb_world->GetBodyList(); while (node) { b2Body* b = node; node = node->GetNext();   SuperBox2DActor* actor = (SuperBox2DActor*)b->GetUserData(); if (actor.isDead) {   // remove from physics engine bb_world->DestroyBody(b);   // remove from game engine (cocos2d) [[StandardGameController sharedSingleton] removeGameActor:actor]; } } }     @implementation Box2DEngine + (Box2DEngine*)sharedSingleton { static Box2DEngine* sharedSingleton; if (!sharedSingleton) sharedSingleton = [[Box2DEngine alloc] init];   return sharedSingleton; }   - (void)createWorld:(CGSize)size { b2AABB worldAABB; worldAABB.lowerBound.Set(0, 0); worldAABB.upperBound.Set(size.width * BOX2D_SCALE_FACTOR_INVERSE, size.height * BOX2D_SCALE_FACTOR_INVERSE); // TODO this shouldnt be inverse?   b2Vec2 gravity(0.0f, -30.0f); bool doSleep = true;   bb_world = new b2World(worldAABB, gravity, doSleep); bb_world->SetContactListener(new MyContactListener()); }   - (void)deleteWorld { [self unschedule:@selector(step:)]; delete bb_world; bb_world = NULL; }   - (void)runSimulation { [self schedule:@selector(step:)]; }   - (void)step:(ccTime)dt {   // step the world bb_world->Step(dt, velocityIterations, positionIterations); // TODO do i use timestep or dt here?   //BBLog(@"Num of contact results is %d",contactResultCount); // do stuff with collisions handleCachedContactResults();   // remove all actors that are marked as dead removeDeadActors();   // update cocosnode positions for (b2Body* b = bb_world->GetBodyList(); b; b = b->GetNext()) { if (b->GetUserData() != NULL) { SuperBox2DActor *actor = (SuperBox2DActor*)b->GetUserData(); b2Vec2 position = b->GetPosition(); actor.position = b2toCGPoint(position); actor.rotation = -1 * CC_RADIANS_TO_DEGREES(b->GetAngle()); //NSLog(@"obj %@ %4.2f %4.2f\n",actor, position.x, position.y); } }   }   @end

Update: This code is obsolete now. You can just do

Label *messageLabel = [Label labelWithString:message dimensions:CGSizeMake(380, 120) alignment:UITextAlignmentCenter fontName:@"your_custom_font" fontSize:26];

by using the new FontManager class. For example, run this once in your app delegate when your program first loads

[[FontManager sharedManager] loadFont:@"your_custom_font"];

It can take a long NSString and create multiple labels without breaking up a word. I’ll eventually use this for my help screen, replacing the current 6 different 480×320 png images that I load for each one  .

The code is simple, but hopefully it might save somebody the time it took me to write it. I had to look up some very basic elements of ObjC here, so if there is a much easier way to do this, please let me know but don’t make too much fun of me.

You can easily switch out the BitmapFontAtlas for just a normal Label and it would work just fine.

(void) setTipString:(NSString*)str {   NSInteger lineChars = 0; BOOL isSpace = NO; NSInteger index = 0; NSInteger numLines = 0;   NSMutableString *line = [NSMutableString stringWithCapacity:LINE_LENGTH];   while (index <= [str length]) { if(index == [str length]) { BitmapFontAtlas *tip = [[BitmapFontAtlas bitmapFontAtlasWithString:[NSString stringWithString:line] fntFile:@"text.fnt" alignment:UITextAlignmentLeft] retain]; [tip setPosition: cpv(30,210 - 20 * numLines)]; [self addChild:tip]; return; }     NSString *tmp = [str substringWithRange:NSMakeRange(index, 1)]; [line appendString:tmp];   if([tmp isEqual:@" "]) isSpace = YES; else isSpace = NO;   if(lineChars >= LINE_LENGTH && isSpace) { BitmapFontAtlas *tip = [[BitmapFontAtlas bitmapFontAtlasWithString:[NSString stringWithString:line] fntFile:@"text.fnt" alignment:UITextAlignmentLeft] retain]; [tip setPosition: cpv(30,210 - 20 * numLines)]; [self addChild:tip]; lineChars = -1; [line setString:@""]; numLines++; } lineChars++; index++; } }
Posted by 오늘마감
2D Scrolling Game with Cocos2D TileMap with Zoom!

A common question I see on the cocos2d forums is ‘when I want to make my game scroll, do I move the camera or the layer?’ or some variant of that. I also got some more detailed questions about how to make a functioning 2D scroller, so I’m going to described how I got it to work.

First of all, the answer to the above question is you move the layer. If you follow the examples in the cocos2d download, you have a “GameScene” and a “GameLayer”. Well, everything that needs to be moved when your game scrolls should be added as a child to that GameLayer. If you are using a TileMap as a background, this includes that tilemap. The only thing that you don’t add as a child to the GameLayer is stuff that does not move with the scrolling view, such as your HUDLayer that has text that shows your characters health. Other than that, your character, the background, other characters, should all be added to the GameLayer.

You have to remember which objects are absolute (attached to your GameScene or other layers) versus those that are relative (a child of your GameLayer) when you set up your touch handling code. For my HUD that has buttons you can press at any time, say to pause the game, you want to add the touch handling object to your GameScene or HUDLayer class, since it doesn’t move. But if you want to be able to touch objects that scroll along with your view in the game itself, your touch handling code needs to be in an object that is a child of your GameLayer.

This might be a little confusing, so let’s see some code:

gameLayer = [GameLayer node]; [gameScene addChild:gameLayer z:zOrder_GameLayer];   hudLayer = [HUDLayer node]; [gameScene addChild:hudLayer z:zOrder_HudLayer];   tileMap = [BGTileMap node]; [gameLayer addChild:tileMap z:-1];   [gameScene addChild:[PauseGameButton node] z:zOrder_GameButtons]; [gameLayer addChild:[FireGunAtTouchPoint node]];

The pause game button is always on your screen, while the point at which your character fires the gun depends on how how far your view has been scrolled (by moving GameLayer).

Let’s see some of the code that actually moves this game layer:

- (void)setViewpointCenter:(CGPoint)point { CGPoint centerPoint = ccp(240, 160); viewPoint = ccpSub(centerPoint, point);   // dont scroll so far so we see anywhere outside the visible map which would show up as black bars if(point.x &lt; centerPoint.x) viewPoint.x = 0; if(point.y &lt; centerPoint.y) viewPoint.y = 0;   // while zoomed out, don't adjust the viewpoint if(!isZoomedOut) gameLayer.position = viewPoint; }

When do you call that method? Well, it depends on what you want, but generally these scrolling games follow around the movement of your ‘main’ character, right? So whatever character the you want to follow, add this to override the standard CocosNode setPosition method so you update your viewpoint whenever the character moves

- (void)setPosition:(CGPoint)point { [[StandardGameController sharedSingleton] setViewpointCenter:point]; [super setPosition:point]; }

Note that the StandardGameController is a construct of mine that I use to separate the game logic out from the display code. It doesn’t matter exactly how you do it, you just need a way to have your main character object call back to something that contains a reference to GameLayer so it can adjust the position of your GameLayer.

Now remember, for your background to scroll properly, you need to add your background tileMap as a child of your GameLayer that is being moved around.

That being said, I found that an important method was missing from the cocos2d tilemap that I need to use in order to detect collisions based on the types of tiles encountered. I created a subclass of TMXTiledMap and added in these methods:

- (CGPoint)coordinatesAtPosition:(CGPoint)point { return ccp((int)(point.x / self.tileSize.width), (int)(self.mapSize.height - (point.y / self.tileSize.height))); }   - (unsigned int)getGIDAtPosition:(CGPoint)point { return [layer tileGIDAt:[self coordinatesAtPosition:point]]; }

That way it’s easy to figure out what tile any individual object is colliding with. For example, in my main character object I can have code that runs in step: function with this:

BGTileMap* tileMap = [StandardGameController sharedSingleton].tileMap; CGPoint coordinate = [tileMap coordinatesAtPosition:self.position]; BBLog(@"Right now on tile %d",[tileMap.layer tileGIDAt:coordinate]);

Now I know what type of tile I am overlapping, and I can respond to the environment accordingly.

This is really all the code that you need to make a scrolling game view…I think some people overthink it and try adjusting the position of every object individually with some offset, but it’s not necessary since your objects can use relative positions with their parent.

I have one last bit of code to add, and this is something kind of fun. It’s not complete, but at least it’s a start. What this allows you to do is ‘zoom out’ so you can see your entire map with ALL the objects shrunk down, and then zoom back in to your character. The only tricky part is when you zoom back in, you have to slowly adjust your viewpoint in steps so the zoom in action is centered on your character, instead of jumping at the end.

#define ZOOM_BACK_IN_INTERVALS 10 #define ZOOM_OUT_RATE 0.3 // TODO need to refine this so for each step it uses the new viewpoint - (void)setZoom:(BOOL)zoomedIn { BBLog(@"Zooming in %d", zoomedIn);   // this scales it out so the whole height of the tilemap is in the screen float zoomScaleFactor = 320 / (tileMap.mapSize.height * tileMap.tileSize.height); if(zoomedIn) { [gameLayer runAction:[ScaleTo actionWithDuration:ZOOM_OUT_RATE scale:1.0]]; [gameLayer runAction:[MoveTo actionWithDuration:ZOOM_OUT_RATE position:viewPoint]]; [self schedule:@selector(setZoomedBackIn:) interval:ZOOM_OUT_RATE]; // need this for the transistion } else { [gameLayer runAction:[ScaleTo actionWithDuration:ZOOM_OUT_RATE scale:zoomScaleFactor]]; [gameLayer runAction:[MoveTo actionWithDuration:ZOOM_OUT_RATE position:ccp(0,0)]]; isZoomedOut = YES; } }   // need this small correction at the end to account of the player is moving and the viewpoint has changed to avoid jitter #define ZOOM_OUT_CORRECTION_RATE 0.3 - (void)setZoomedBackIn:(ccTime)dt { [self unschedule:@selector(setZoomedBackIn:)]; [gameLayer runAction:[MoveTo actionWithDuration:ZOOM_OUT_CORRECTION_RATE position:viewPoint]]; [self schedule:@selector(setZoomedBackInFinished:) interval:ZOOM_OUT_CORRECTION_RATE]; // need this for the transistion }   - (void)setZoomedBackInFinished:(ccTime)dt { [self unschedule:@selector(setZoomedBackInFinished:)]; isZoomedOut = NO; }

Now you see why my viewPoint variable was a class member…you’ll need it for these methods to work.

The reason this code isn’t complete is when it starts zooming in, it creates the actions to zoom in on the current viewpoint, but if the player is moving by the time the zoom animation is done, that viewpoint is changed and needs to ’snap’ to the new viewpoint. That is the reason for the setZoomedBackIn: method, which really shouldn’t have to move the gameLayer anymore. However, I haven’t yet written the code to continuously create smaller move actions to take into account a moving viewpoint as the animation continues, but doing so shouldn’t be that hard. If you want to see that bit when I finish, post in the comments and I’ll add it in.

http://johnehartzog.com/2009/10/2d-scrolling-game-with-cocos2d-tilemap-with-zoom/

Posted by 오늘마감
Easy To Create Buttons with Cocos2D

Those of you who use cocos2d a lot might understand why I created this class as some point. Hopefully it may save some of you those nasty 5 line blobs that you normally need to create a simple button. Usage is simple, just do:

[self addChild:[Button buttonWithText:@"back" atPosition:ccp(80, 50) target:self selector:@selector(back:)]]; [self addChild:[Button buttonWithImage:@"openFeint.png" atPosition:ccp(400, 50) target:self selector:@selector(openOpenFeint:)]];

You’ll need to create your own button.png and button_p.png (the second one is the image shown when you are touching the button). Also you’ll need to choose your own font. Here is the code…

// // Button.h // StickWars - Siege // // Created by EricH on 8/3/09. //   @interface Button : Menu { } + (id)buttonWithText:(NSString*)text atPosition:(CGPoint)position target:(id)target selector:(SEL)selector; + (id)buttonWithImage:(NSString*)file atPosition:(CGPoint)position target:(id)target selector:(SEL)selector; @end   @interface ButtonItem : MenuItem { Sprite *back; Sprite *backPressed; } + (id)buttonWithText:(NSString*)text target:(id)target selector:(SEL)selector; + (id)buttonWithImage:(NSString*)file target:(id)target selector:(SEL)selector; - (id)initWithText:(NSString*)text target:(id)target selector:(SEL)selector; - (id)initWithImage:(NSString*)file target:(id)target selector:(SEL)selector; @end
// // Button.m // StickWars - Siege // // Created by EricH on 8/3/09. //   #import "Button.h"     @implementation Button + (id)buttonWithText:(NSString*)text atPosition:(CGPoint)position target:(id)target selector:(SEL)selector { Menu *menu = [Menu menuWithItems:[ButtonItem buttonWithText:text target:target selector:selector], nil]; menu.position = position; return menu; }   + (id)buttonWithImage:(NSString*)file atPosition:(CGPoint)position target:(id)target selector:(SEL)selector { Menu *menu = [Menu menuWithItems:[ButtonItem buttonWithImage:file target:target selector:selector], nil]; menu.position = position; return menu; } @end   @implementation ButtonItem + (id)buttonWithText:(NSString*)text target:(id)target selector:(SEL)selector { return [[[self alloc] initWithText:text target:target selector:selector] autorelease]; }   + (id)buttonWithImage:(NSString*)file target:(id)target selector:(SEL)selector { return [[[self alloc] initWithImage:file target:target selector:selector] autorelease]; }   - (id)initWithText:(NSString*)text target:(id)target selector:(SEL)selector { if(self = [super initWithTarget:target selector:selector]) { back = [[Sprite spriteWithFile:@"button.png"] retain]; back.anchorPoint = ccp(0,0); backPressed = [[Sprite spriteWithFile:@"button_p.png"] retain]; backPressed.anchorPoint = ccp(0,0); [self addChild:back];   self.contentSize = back.contentSize;   Label* textLabel = [Label labelWithString:text fontName:@"take_out_the_garbage" fontSize:22]; textLabel.position = ccp(self.contentSize.width / 2, self.contentSize.height / 2); textLabel.anchorPoint = ccp(0.5, 0.3); [self addChild:textLabel z:1]; } return self; }   - (id)initWithImage:(NSString*)file target:(id)target selector:(SEL)selector { if(self = [super initWithTarget:target selector:selector]) {   back = [[Sprite spriteWithFile:@"button.png"] retain]; back.anchorPoint = ccp(0,0); backPressed = [[Sprite spriteWithFile:@"button_p.png"] retain]; backPressed.anchorPoint = ccp(0,0); [self addChild:back];   self.contentSize = back.contentSize;   Sprite* image = [Sprite spriteWithFile:file]; [self addChild:image z:1]; image.position = ccp(self.contentSize.width / 2, self.contentSize.height / 2); } return self; }   -(void) selected { [self removeChild:back cleanup:NO]; [self addChild:backPressed]; [super selected]; }   -(void) unselected { [self removeChild:backPressed cleanup:NO]; [self addChild:back]; [super unselected]; }   // this prevents double taps - (void)activate { [super activate]; [self setIsEnabled:NO]; [self schedule:@selector(resetButton:) interval:0.5]; }   - (void)resetButton:(ccTime)dt { [self unschedule:@selector(resetButton:)]; [self setIsEnabled:YES]; }   - (void)dealloc { [back release]; [backPressed release]; [super dealloc]; }   @end

A common question I see on the cocos2d forums is ‘when I want to make my game scroll, do I move the camera or the layer?’ or some variant of that. I also got some more detailed questions about how to make a functioning 2D scroller, so I’m going to described how I got it to work.

First of all, the answer to the above question is you move the layer. If you follow the examples in the cocos2d download, you have a “GameScene” and a “GameLayer”. Well, everything that needs to be moved when your game scrolls should be added as a child to that GameLayer. If you are using a TileMap as a background, this includes that tilemap. The only thing that you don’t add as a child to the GameLayer is stuff that does not move with the scrolling view, such as your HUDLayer that has text that shows your characters health. Other than that, your character, the background, other characters, should all be added to the GameLayer.

You have to remember which objects are absolute (attached to your GameScene or other layers) versus those that are relative (a child of your GameLayer) when you set up your touch handling code. For my HUD that has buttons you can press at any time, say to pause the game, you want to add the touch handling object to your GameScene or HUDLayer class, since it doesn’t move. But if you want to be able to touch objects that scroll along with your view in the game itself, your touch handling code needs to be in an object that is a child of your GameLayer.

This might be a little confusing, so let’s see some code:

gameLayer = [GameLayer node]; [gameScene addChild:gameLayer z:zOrder_GameLayer];   hudLayer = [HUDLayer node]; [gameScene addChild:hudLayer z:zOrder_HudLayer];   tileMap = [BGTileMap node]; [gameLayer addChild:tileMap z:-1];   [gameScene addChild:[PauseGameButton node] z:zOrder_GameButtons]; [gameLayer addChild:[FireGunAtTouchPoint node]];

The pause game button is always on your screen, while the point at which your character fires the gun depends on how how far your view has been scrolled (by moving GameLayer).

Let’s see some of the code that actually moves this game layer:

- (void)setViewpointCenter:(CGPoint)point { CGPoint centerPoint = ccp(240, 160); viewPoint = ccpSub(centerPoint, point);   // dont scroll so far so we see anywhere outside the visible map which would show up as black bars if(point.x &lt; centerPoint.x) viewPoint.x = 0; if(point.y &lt; centerPoint.y) viewPoint.y = 0;   // while zoomed out, don't adjust the viewpoint if(!isZoomedOut) gameLayer.position = viewPoint; }

When do you call that method? Well, it depends on what you want, but generally these scrolling games follow around the movement of your ‘main’ character, right? So whatever character the you want to follow, add this to override the standard CocosNode setPosition method so you update your viewpoint whenever the character moves

- (void)setPosition:(CGPoint)point { [[StandardGameController sharedSingleton] setViewpointCenter:point]; [super setPosition:point]; }

Note that the StandardGameController is a construct of mine that I use to separate the game logic out from the display code. It doesn’t matter exactly how you do it, you just need a way to have your main character object call back to something that contains a reference to GameLayer so it can adjust the position of your GameLayer.

Now remember, for your background to scroll properly, you need to add your background tileMap as a child of your GameLayer that is being moved around.

That being said, I found that an important method was missing from the cocos2d tilemap that I need to use in order to detect collisions based on the types of tiles encountered. I created a subclass of TMXTiledMap and added in these methods:

- (CGPoint)coordinatesAtPosition:(CGPoint)point { return ccp((int)(point.x / self.tileSize.width), (int)(self.mapSize.height - (point.y / self.tileSize.height))); }   - (unsigned int)getGIDAtPosition:(CGPoint)point { return [layer tileGIDAt:[self coordinatesAtPosition:point]]; }

That way it’s easy to figure out what tile any individual object is colliding with. For example, in my main character object I can have code that runs in step: function with this:

BGTileMap* tileMap = [StandardGameController sharedSingleton].tileMap; CGPoint coordinate = [tileMap coordinatesAtPosition:self.position]; BBLog(@"Right now on tile %d",[tileMap.layer tileGIDAt:coordinate]);

Now I know what type of tile I am overlapping, and I can respond to the environment accordingly.

This is really all the code that you need to make a scrolling game view…I think some people overthink it and try adjusting the position of every object individually with some offset, but it’s not necessary since your objects can use relative positions with their parent.

I have one last bit of code to add, and this is something kind of fun. It’s not complete, but at least it’s a start. What this allows you to do is ‘zoom out’ so you can see your entire map with ALL the objects shrunk down, and then zoom back in to your character. The only tricky part is when you zoom back in, you have to slowly adjust your viewpoint in steps so the zoom in action is centered on your character, instead of jumping at the end.

#define ZOOM_BACK_IN_INTERVALS 10 #define ZOOM_OUT_RATE 0.3 // TODO need to refine this so for each step it uses the new viewpoint - (void)setZoom:(BOOL)zoomedIn { BBLog(@"Zooming in %d", zoomedIn);   // this scales it out so the whole height of the tilemap is in the screen float zoomScaleFactor = 320 / (tileMap.mapSize.height * tileMap.tileSize.height); if(zoomedIn) { [gameLayer runAction:[ScaleTo actionWithDuration:ZOOM_OUT_RATE scale:1.0]]; [gameLayer runAction:[MoveTo actionWithDuration:ZOOM_OUT_RATE position:viewPoint]]; [self schedule:@selector(setZoomedBackIn:) interval:ZOOM_OUT_RATE]; // need this for the transistion } else { [gameLayer runAction:[ScaleTo actionWithDuration:ZOOM_OUT_RATE scale:zoomScaleFactor]]; [gameLayer runAction:[MoveTo actionWithDuration:ZOOM_OUT_RATE position:ccp(0,0)]]; isZoomedOut = YES; } }   // need this small correction at the end to account of the player is moving and the viewpoint has changed to avoid jitter #define ZOOM_OUT_CORRECTION_RATE 0.3 - (void)setZoomedBackIn:(ccTime)dt { [self unschedule:@selector(setZoomedBackIn:)]; [gameLayer runAction:[MoveTo actionWithDuration:ZOOM_OUT_CORRECTION_RATE position:viewPoint]]; [self schedule:@selector(setZoomedBackInFinished:) interval:ZOOM_OUT_CORRECTION_RATE]; // need this for the transistion }   - (void)setZoomedBackInFinished:(ccTime)dt { [self unschedule:@selector(setZoomedBackInFinished:)]; isZoomedOut = NO; }

Now you see why my viewPoint variable was a class member…you’ll need it for these methods to work.

The reason this code isn’t complete is when it starts zooming in, it creates the actions to zoom in on the current viewpoint, but if the player is moving by the time the zoom animation is done, that viewpoint is changed and needs to ’snap’ to the new viewpoint. That is the reason for the setZoomedBackIn: method, which really shouldn’t have to move the gameLayer anymore. However, I haven’t yet written the code to continuously create smaller move actions to take into account a moving viewpoint as the animation continues, but doing so shouldn’t be that hard. If you want to see that bit when I finish, post in the comments and I’ll add it in.

Posted by 오늘마감
Using Box2D Physics Engine with Cocos2D iPhone

Starting work on my new project, I’ve found Box2D to be a far superior physics engine than chipmunk. It is more mature, the API more flexible, and it seems to even perform faster. However, the cocos2d code for it was rather space, so here is a sort of helper file I had to create to make it work with my game.

Keep in mind this game is in progress and I’ve only been using this for a few days, so it may have issues that might pop up later on. It seems to be working very well for now though, with 40-50 objects on screen moving around with ~40 FPS.

Here is the header

// // Box2DEngine.h // // Created by EricH on 7/22/09. // Copyright 2009 __MyCompanyName__. All rights reserved. //   #import "Box2D.h"   // made this an extern constant to avoid obj c lookup overhead extern b2World *bb_world;   @interface Box2DEngine : CocosNode { }   + (Box2DEngine *)sharedSingleton; - (void)createWorld:(CGSize)size; - (void)deleteWorld; - (void)runSimulation; @end

The .mm file

// // Box2DEngine.mm // // Created by EricH on 7/22/09. // Copyright 2009 __MyCompanyName__. All rights reserved. //   #import "HookActor.h"     #import "Box2DEngine.h" #import "SuperBox2DActor.h"   b2World* bb_world;   const float32 timeStep = 1.0f / 60.0f; const int32 velocityIterations = 10; const int32 positionIterations = 10;   #define MAX_NUM_COLLISIONS 2048 // TODO make sure this buffer is the right size b2ContactResult contactResultCache[MAX_NUM_COLLISIONS]; int32 contactResultCount = 0;   class MyContactListener : public b2ContactListener { public: void Add(const b2ContactPoint* point) { }   void Persist(const b2ContactPoint* point) { }   void Remove(const b2ContactPoint* point) { }   void Result(const b2ContactResult* point) { // TODO we are making a deep copy of every contact point here // check the box2d contact masks to make sure we minimize unwanted contact results contactResultCache[contactResultCount++] = *point; } };   void handleCachedContactResults() { b2ContactResult contactResult; for(int i = 0; i < contactResultCount; i++) { #ifdef BBDEBUG if(contactResultCount >= MAX_NUM_COLLISIONS) { NSLog(@"RAN OUT OF BUFFER"); assert(NO); } #endif contactResult = contactResultCache[i]; SuperBox2DActor* actorOne = (SuperBox2DActor*)contactResult.shape1->GetBody()->GetUserData(); SuperBox2DActor* actorTwo = (SuperBox2DActor*)contactResult.shape2->GetBody()->GetUserData(); if(!actorOne.isDead && !actorTwo.isDead) { [actorOne collisionResultOne:&contactResult withActor:actorTwo]; [actorTwo collisionResultTwo:&contactResult withActor:actorOne]; } }   // clear the collision cache contactResultCount = 0; }   void removeDeadActors() { b2Body* node = bb_world->GetBodyList(); while (node) { b2Body* b = node; node = node->GetNext();   SuperBox2DActor* actor = (SuperBox2DActor*)b->GetUserData(); if (actor.isDead) {   // remove from physics engine bb_world->DestroyBody(b);   // remove from game engine (cocos2d) [[StandardGameController sharedSingleton] removeGameActor:actor]; } } }     @implementation Box2DEngine + (Box2DEngine*)sharedSingleton { static Box2DEngine* sharedSingleton; if (!sharedSingleton) sharedSingleton = [[Box2DEngine alloc] init];   return sharedSingleton; }   - (void)createWorld:(CGSize)size { b2AABB worldAABB; worldAABB.lowerBound.Set(0, 0); worldAABB.upperBound.Set(size.width * BOX2D_SCALE_FACTOR_INVERSE, size.height * BOX2D_SCALE_FACTOR_INVERSE); // TODO this shouldnt be inverse?   b2Vec2 gravity(0.0f, -30.0f); bool doSleep = true;   bb_world = new b2World(worldAABB, gravity, doSleep); bb_world->SetContactListener(new MyContactListener()); }   - (void)deleteWorld { [self unschedule:@selector(step:)]; delete bb_world; bb_world = NULL; }   - (void)runSimulation { [self schedule:@selector(step:)]; }   - (void)step:(ccTime)dt {   // step the world bb_world->Step(dt, velocityIterations, positionIterations); // TODO do i use timestep or dt here?   //BBLog(@"Num of contact results is %d",contactResultCount); // do stuff with collisions handleCachedContactResults();   // remove all actors that are marked as dead removeDeadActors();   // update cocosnode positions for (b2Body* b = bb_world->GetBodyList(); b; b = b->GetNext()) { if (b->GetUserData() != NULL) { SuperBox2DActor *actor = (SuperBox2DActor*)b->GetUserData(); b2Vec2 position = b->GetPosition(); actor.position = b2toCGPoint(position); actor.rotation = -1 * CC_RADIANS_TO_DEGREES(b->GetAngle()); //NSLog(@"obj %@ %4.2f %4.2f\n",actor, position.x, position.y); } }   }   @end

Update: This code is obsolete now. You can just do

Label *messageLabel = [Label labelWithString:message dimensions:CGSizeMake(380, 120) alignment:UITextAlignmentCenter fontName:@"your_custom_font" fontSize:26];

by using the new FontManager class. For example, run this once in your app delegate when your program first loads

[[FontManager sharedManager] loadFont:@"your_custom_font"];

It can take a long NSString and create multiple labels without breaking up a word. I’ll eventually use this for my help screen, replacing the current 6 different 480×320 png images that I load for each one  .

The code is simple, but hopefully it might save somebody the time it took me to write it. I had to look up some very basic elements of ObjC here, so if there is a much easier way to do this, please let me know but don’t make too much fun of me.

You can easily switch out the BitmapFontAtlas for just a normal Label and it would work just fine.

(void) setTipString:(NSString*)str {   NSInteger lineChars = 0; BOOL isSpace = NO; NSInteger index = 0; NSInteger numLines = 0;   NSMutableString *line = [NSMutableString stringWithCapacity:LINE_LENGTH];   while (index <= [str length]) { if(index == [str length]) { BitmapFontAtlas *tip = [[BitmapFontAtlas bitmapFontAtlasWithString:[NSString stringWithString:line] fntFile:@"text.fnt" alignment:UITextAlignmentLeft] retain]; [tip setPosition: cpv(30,210 - 20 * numLines)]; [self addChild:tip]; return; }     NSString *tmp = [str substringWithRange:NSMakeRange(index, 1)]; [line appendString:tmp];   if([tmp isEqual:@" "]) isSpace = YES; else isSpace = NO;   if(lineChars >= LINE_LENGTH && isSpace) { BitmapFontAtlas *tip = [[BitmapFontAtlas bitmapFontAtlasWithString:[NSString stringWithString:line] fntFile:@"text.fnt" alignment:UITextAlignmentLeft] retain]; [tip setPosition: cpv(30,210 - 20 * numLines)]; [self addChild:tip]; lineChars = -1; [line setString:@""]; numLines++; } lineChars++; index++; } }

Posted by 오늘마감
cocos2d 설치와 프로젝트 템플릿 활용
Cocos2D 라이브러리를 사용하는 방법은 여러가지가 있지만,
주요하게는 두가지 방법이 있는거 같습니다.

방법 1. static library를 빌드, 라이브러리에서 헤더파일만 복사
방법 2. dependent project로 cocos2d 프로젝트를 포함

[방법 1]
방법 1번의 경우, SDK를 여러버전을 사용하거나 하는 경우 다시 빌드해서
복사하는 등의 불편함이 있겠더군요. 그리고 cocos2d의 헤더파일들만
다시 복사하는 것도 복잡하더군요.. external source들 때문에...

그리고 Cocos2D 프로제트 템플릿이 필요해서 이리저리 찾아봤는데...
어떤 것들은, Cocos2D 소스가 통째로 들어가 있고.. 난리가 아니더군요.. ㅡ,ㅡ

[방법 2]
그래서 찾다보니, tjweir 라는 분께서 이미 잘 만들어놓으셨더라구요.. ^^;
요약하면 다음과 같습니다.


1. cocos2d 프로제트는 적절한 곳에 복사해 놓습니다.
저의 경우 ~/SDKs/cocos2d-0.8b 여기에 있고요..
(라이브러리 따로 빌드해 놓을 필요없어요.. ^^)

2. Xcode의 global environment (Cmd+,) 의 Source Tree
항목에서 COCOS2D_SRC 라는 변수를 만들고 여기에
Cocos2D의 소스가 있는 경로를 지정합니다.

3. git 클라이언트로 템플릿 소스를 받아서 저장 해놓고
프로젝트 템플릿 경로에 갖다 놓습니다.
git clone git://github.com/tjweir/cocos2d-application.git

4. 이 템플릿을 이용해서 프로젝트를 만드시고, 빌드하시면 됩니다. ^^;

참조: http://github.com/tjweir/cocos2d-application/tree/master

혹시 더 좋은 방법이 있나요? ^^;


출처 : http://blog.naver.com/PostView.nhn?blogId=gonagi&logNo=150052654676
Posted by 오늘마감
초초초보자를 위한 cocos2d 관련사이트
저처럼 아무것도 모르시는 초초초초초초초초~ 초보자를 위해서 조금이나마 도움이 되시라고 적어봅니다.

http://monoclestudios.com/cocos2d_whitepaper.html

위의 사이트는 cocos2d를 한번도 사용해 보지 않으셨다면 한번 따라해보시길 권해드립니다.

영문으로 되어있지만 캡쳐화면과 같이 있어서 어렵지않을듯 합니다.
( 블로그에 번역해 놓으신분이 계시내여. 아래 주소 참조
   http://blog.naver.com/jedikim72/10042076138
)

http://lukehatcher.com/2009/04/coloring-sprites-with-cocos2d-iphone/

맨처음 적었던 사이트의 파트너쉽 사이트로 링크가 걸려있는곳 입니다.

Coloring Sprite 에 대해서 적어놓은거던데 맨처음 사이트꺼 SimpleGame 따라해보고 추가로 해보기 괜찮은듯 해서 적어봅니다.

http://permadi.com/blog/?p=275

위의 사이트는 cocos2d 를 이용해서 볼모양의 그림이 점프하는 애니메이션을 보여줍니다.

소스코드를 따라해보시거나 사이트에 있는 샘플파일을 받아서 실행해 보시기 바랍니다.

http://kwigbo.com/wp/

ABC123 등 coscos2d 로 만든 간단한게임 소스를 공개해 놓았습니다.
( 단 소스가 압축이 안되서 올려져 있어서 불편할지도 모르겠습니다만 도움이 되실분들도 있을것 같아서... )

마지막으로

http://www.cocos2d.org/doc/programming_guide/

cocos2d 사이트에서 제공하는 프로그래밍 가이드 사이트 입니다.

은근히 모르시는분들이 있는것 같아서 적어봤습니다.

공부하다가 도움이될만한 사이트가 있으면 이문서에 추가적으로 업데이트 하도록 하겠습니다.
 


출처 : http://blog.naver.com/PostView.nhn?blogId=gonagi&logNo=150047655458
Posted by 오늘마감