Thứ Năm, 6 tháng 12, 2012

A Comparison of Push vs Pull Ajax


The advent of AJAX has made it possible to develop browser based web applications with high user interactivity and low user-perceived latency. Real-time dynamic web data such as news headlines, stock tickers, and auction updates need to be propagated to the users as soon as possible. However, AJAX still suffers from the limitations of the web’s request/response architecture which prevents servers from pushing real-time dynamic web data.
Engin Bozdag, Ali Mesbah and Arie van Deursen of the Delft University of Technology have discussed the following approcahes to achieve web-based real time event notification:
1. HTTP Pull: In this traditional approach , the client checks with the server for latest data at regular user definable intervals The pulling frequecncy needs to be high to ensure high data accuracy, but high pulling frequency may induce redundant checks leading to high network traffic. Low pulling frequency, on the other hand, may lead to missed updates. Ideally, the pulling interval should be equal to the rate at which the server state changes.
2. HTTP Streaming: This method consists of streaming server data in the response of a long-lived HTTP connection (Page Streaming) or an XMLHttpRequest connection (Service Streaming).
3. Reverse AJAX: Service Streaming, as applied to AJAX, is known as Reverse AJAX or COMET . It enables the server to send a message to the client when an event occurs, without the client having to explicitly request. The goal is to achieve a real-time update of the state changes. COMET uses the persistent connectionfeature in HTTP/1.1. With HTTP/1.1, unless specified otherwise, the TCP connection between the server and the browser is kept alive, until an explicit ‘close connection’ message is sent by one of the parties, or a timeout/network error occurs.
4. Long Polling: Also known as Asynchronous Polling, this method is a hybrid of pure server push and client pull. It is based on BAYEUX protocol. This protocol follows the topic based publish - subscribe scheme. After a subscription to a channel, the connection between the client and the server is kept open, for a defined amount of time. If no event occurs on the server side, a timeout occurs, and the server asks the client to reconnect asynchronously. If an event occurs, the server sends the data to the client, and the client reconnects.
In their experimental study, the authors compared Data Coherence, Server Performance, Network Performance and Data Misses of an AJAX application using a COMET push implementation (Dojo’s Cometd library), as opposed to a pure pull approcah.
The authors concluded that:
"...If we want high data coherence and high network performance, we should choose the push approach. However, push brings some scalability issues; the server application CPU usage is 7 times higher as in pull. According to our results, the server starts to saturate at 350-500 users. For larger number of users, load balancing and server clustering techniques are unavoidable.
With the pull approach, achieving total data coherence with high network performance is very difficult. If the pull interval is higher than the publish interval, some data miss will occur. If it is lower, network performance will suffer. Pull performs well only if the pull interval equals to publish interval. However, in order to achieve that, we need to know the exact publish interval beforehand. However, the publish interval is rarely static and predictable. This makes pull useful only in situations where the data is published frequently according to some pattern..."

KHÁI NIÊM CƠ BẢN VỀ RAM

TÊN GỌI 
Hiện nay nhiều người thường nhầm lẫn về cách gọi tên của các loại RAM. Nếu như RDRAM không có gì để nói thì với dòng SDRAM, việc nhầm lẫn ngày càng lớn. Khái niệm RAM (Random Access Memory) thì chắc hẳn ai cũng biết. DRAM hay SDRAM là khái niệm mở rộng hơn (Synchronous Dynamic Random Access Memory - RAM đồng bộ). Ban đầu và thậm chí hiện nay khi nói đến SDRAM người ta thường nghĩ ngay đến RAM loại cũ với tốc độ 100MHz hay 133MHz; tuy nhiên từ sau khi DDR SDRAM (Double Data Rate SDRAM) ra đời thì quan niệm này hoàn toàn sai. Tham khảo một vài bảng báo giá linh kiện, bạn sẽ thấy các công ty đã góp phần không nhỏ vào việc khiến người dùng hiểu sai vấn đề. SDRAM là tên gọi chung của một dòng bộ nhớ máy tính, nó được phân ra SDR (Single Data Rate) và DDR (Double Data Rate). Do đó nếu gọi một cách chính xác, chúng ta sẽ có hai loại RAM chính là SDR SDRAM và DDR SDRAM. Cấu trúc của hai loại RAM này tương đối giống nhau, nhưng DDR có khả năng truyền dữ liệu ở cả hai điểm lên và xuống của tín hiệu nên tốc độ nhanh gấp đôi. Trong thời gian gần đây xuất hiện chuẩn RAM mới dựa trên nền tảng DDR là DDR-II, DDR-II có tốc độ cao hơn nhờ cải tiến thiết kế. 

TỐC ĐỘ (SPEED) 
Đây có lẽ là khái niệm được người dùng quan tâm nhất, tuy nhiên có người thắc mắc về cách gọi tên, đối với DDR thì có hai cách gọi theo tốc độ MHz hoặc theo băng thông. Ví dụ, khi nói DDR333 tức là thanh RAM đó mặc định hoạt động ở tốc độ 333MHz nhưng cách gọi PC2700 thì lại nói về băng thông RAM, tức là khi chạy ở tốc độ 333MHz thì nó sẽ đạt băng thông là 2700MB/s (trên lý thuyết). Tương ứng như thế chúng ta sẽ có bảng sau: 
Thường ở Việt Nam thông dụng các loại RAM có bus 333 và 400, những loại có bus cao hơn thường xuất hiện ở những loại cao cấp như Kingston HyperX, Corsair , Mushkin LV nhưng nói chung khá hiếm. 

ĐỘ TRỄ (LATENCY) 
CAS Latency là khái niệm mà người dùng thắc mắc nhiều nhất. Trước đây, khi đi mua RAM, người mua thường chỉ quan tâm tới tốc độ hoạt động như 100MHz hay 133MHz nhưng gần đây, khái niệm CAS đang dần được người dùng để ý bởi nó đóng vai trò khá quan trọng vào tốc độ xử lý tổng thể của hệ thống; đặc biệt trong ép xung. Vậy CAS là gì? 

CAS là viết tắt của 'Column Address Strobe' (địa chỉ cột). Một thanh DRAM được coi như một ma trận của các ô nhớ (bạn có thể hình dung như một bảng tính excel với nhiều ô trống) và dĩ nhiên mỗi ô nhớ sẽ có toạ độ (ngang, dọc). Như vậy bạn có thể đoán ngay ra khái niệm RAS (Row Adress Strobe)là địa chỉ hàng nhưng do nguyên lý hoạt động của DRAM là truyền dữ liệu xuống chân nên RAS thường không quan trọng bằng CAS. 

Khái niệm độ trễ biểu thị quãng thời gian bạn phải chờ trước khi nhận được thứ mình cần. Theo từ điển Merriam-Webster thì latency có nghĩa là 'khoảng thời gian từ khi ra lệnh đến khi nhận được sự phản hồi'. Vậy CAS sẽ làm việc như thế nào? CAS Latency có ý nghĩa gì? 
Để hiểu khái niệm này, chúng ta sẽ cùng điểm nhanh qua cách thức bộ nhớ làm việc, đầu tiên chipset sẽ truy cập vào hàng ngang (ROW) của ma trận bộ nhớ thông qua việc đưa địa chỉ vào chân nhớ (chân RAM) rồi kích hoạt tín hiệu RAS. Chúng ta sẽ phải chờ khoảng vài xung nhịp hệ thống (RAS to CAS Delay) trước khi địa chỉ cột được đặt vào chân nhớ và tín hiệu CAS phát ra. Sau khi tín hiệu CAS phát đi, chúng ta tiếp tục phải chờ một khoảng thời gian nữa (đây chính là CAS Latency) thì dữ liệu sẽ được tìm thấy. Điều đó cũng có nghĩa là với CAS 2, chipset phải chờ 2 xung nhịp trước khi lấy được dữ liệu và với CAS3, thời gian chờ sẽ là 3 xung nhịp hệ thống. 

Bạn sẽ thắc mắc như vậy phải chăng CAS2 nhanh hơn CAS3 tới 33%, không đến mức như vậy bởi có rất nhiều yếu tố ảnh hưởng đến hiệu năng tổng thể của bộ nhớ điển hình như: 
+ Chuỗi xử lý thông tin: kích hoạt RAS, chờ khoảng thời gian trễ RAS-to-CAS Delay và CAS Latency. 
+ Truy cập bộ nhớ theo chuỗi: đôi khi chipset sẽ đọc dữ liệu trong bộ nhớ RAM theo chuỗi (burst) như vậy rất nhiều dữ liệu sẽ được chuyển đi một lần và tín hiệu CAS chỉ được kích hoạt một lần ở đầu chuỗi. 
+ Bộ vi xử lý có bộ đệm khá lớn nên chứa nhiều lệnh truy cập và dữ liệu; do đó thông tin được tìm kiếm trên bộ đệm trước khi truy cập vào RAM và tần số dữ liệu cần được tìm thấy trên bộ đệm (hit-rate) khá cao (vào khoảng 95%). 
Nói tóm lại việc chuyển từ CAS 3 sang CAS 2 sẽ tăng hiệu năng xử lý cho tất cả các ứng dụng. Những chương trình phụ thuộc vào bộ nhớ như game hay ứng dụng đồ họa sẽ chạy nhanh hơn. Điều này đồng nghĩa với việc những thanh RAM được đóng dấu CAS2 chắc chắn chạy nhanh hơn những thanh RAM CAS3. Nếu bạn dự định mua đồ chơi cho một cuộc đua ép xung hay đơn giản chỉ cần hệ thống đạt tốc độ tối ưu, hãy chọn RAM CAS2 nhưng nếu chỉ là công việc văn phòng, CAS 3 hoàn toàn vẫn đáp ứng yêu cầu. 

TẦN SỐ LÀM TƯƠI 
Thường thì khi nhắc tới khái niệm tần số làm tươi (RAM Refresh Rate), người ta thường nghĩ ngay đến màn hình máy tính, tuy nhiên bộ nhớ DRAM (Dynamic Random Access Memory) cũng có khái niệm này. Như bạn đã biết module DRAM được tạo nên bởi nhiều tế bào điện tử, mỗi tế bào này phải được nạp lại điện hàng nghìn lần mỗi giây vì nếu không dữ liệu chứa trong chúng sẽ bị mất. Một số loại DRAM có khả năng tự làm tươi dữ liệu độc lập với bộ xử lý thường được sử dụng trong những thiết bị di động để tiết kiệm điện năng. 

SDRAM ACCESS TIME 
Việc cho ra đời cách đọc dữ liệu theo từng chuỗi (Burst Mode) đã giúp khắc phục nhiều nhược điểm và tăng hiệu năng cho RAM, chu kì của chuỗi ngắn hơn rất nhiều chu kì trang của RAM loại cũ. Chu kì của chuỗi cũng được coi như là chu kì xung nhịp của SDRAM và chính vì thế nó được coi như thang xác định cho tốc độ của RAM bởi đó là khoảng thời gian cần thiết giữa các lần truy xuất dữ liệu theo chuỗi của RAM. Những con số -12, -10, -8... ghi trên các chip RAM cho biết khoảng thời gian tối thiểu giữa mỗi lần truy xuất dữ liệu: nhãn -12 xác định chu kì truy cập dữ liệu của RAM là 12ns (nano-giây) đồng nghĩa với việc tốc độ hoạt động tối đa của RAM sẽ là 83MHz. Thường RAM có tốc độ cao sẽ sử dụng chip RAM có chu kì truy xuất thấp nhưng với chu kì truy xuất thấp chưa chắc RAM đã có thể hoạt động ở tốc độ cao do còn phụ thuộc vào nhiều yếu tố khác. Do đó đôi khi bạn sẽ gặp trường hợp thanh RAM có tốc độ thấp nhưng khi đem vào 'thử lửa' ép xung thì lên được tốc độ cao hơn nhiều so với những loại RAM mặc định dán nhãn tốc độ cao.

Thứ Tư, 19 tháng 9, 2012

How To Make A Simple iPhone Game with Cocos2D Tutorial



If you're new here, you may want to subscribe to my RSS feed or follow me on Twitter. Thanks for visiting!
Ninjas Going Pew-Pew!
Ninjas Going Pew-Pew!
Cocos2D is a powerful library for the iPhone that can save you a lot of time while building your iPhone game. It has sprite support, cool graphical effects, animations, physics libraries, sound engines, and a lot more.
I am just starting to learn Cocos2D, and while there are various useful tutorials on getting started with Cocos2D out there, I couldn’t find anything quite like what I was looking for – making a very simple but functional game with animation, collisions, and audio without using too many advanced features. I ended up making a simple game of my own, and thought I’d write a tutorial series based on my experience in case it might be useful to other newcomers.
This tutorial series will walk you through the process of creating a simple game for your iPhone with Cocos2D, from start to finish. You can follow along with the series, or just jump straight to the sample project at the end of the article. And yes. There will be ninjas.
(Jump to Part 2 or Part 3 of the series.)

Downloading and Installing Cocos2D

You can download Cocos2D from the Cocos2D Google Code page.
After you pull down the code, you’ll want to install the useful project templates. Open up a Terminal window to the directory you downloaded Cocos2D to, and enter the following command: ./install-templates.sh -f -u
Note that you can optionally pass a parameter to the install script if you have XCode installed to a non-standard directory (like you might have done if you have more than one version of the SDK on your machine).

Hello, Cocos2D!

Let’s start by getting a simple Hello World project up and running by using the Cocos2D template we just installed. Start up XCode and create a new Cocos2D project by selecting the cocos2d Application template, and name the project “Cocos2DSimpleGame”.
Cocos2D Templates
Go ahead and build and run the template as-is. If all works OK, you should see the following:
HelloWorld Screenshot
Cocos2D is organized into the concept of “scenes”, which are kind of like “levels” or “screens” for a game. For example you might have a scene for the initial menu for the game, another for the main action of the game, and a game over scene to end. Inside scenes, you can have a number of layers (kind of like in Photoshop), and layers can contain nodes such as sprites, labels, menus, or more. And nodes can contain other nodes as well (i.e. a sprite could have a child sprite inside it).
If you take a look at the sample project, you’ll see there’s just one layer – HelloWorldLayer – and we’re going to start implementing our main gameplay in there. Go ahead and open it up – you’ll see that right now in the init method it’s adding a label that says “Hello World” to the layer. We’re going to take that out, and put a sprite in instead.

Adding A Sprite

Before we can add a sprite, we’ll need some images to work with. You can either create your own, or use the ones my lovely wife has created for the project: a Player imagea Projectile image, and a Target image.
Once you’ve obtained the images, drag them over to the resources folder in XCode, and make sure “Copy items into destination group’s folder (if needed)” is checked.
Now that we have our images, we have to figure out where we want to place the player. Note that in Cocos2D the bottom left corner of the screen has coordinates of (0,0) and the x and y values increase as you move to the upper right. Since this project is in landscape mode, this means that the upper right corner is (480, 320).
Also note that by default when we set the position of an object, the position is relative to the center of the sprite we are adding. So if we wanted our player sprite to be aligned with the left edge of the screen horizontally, and vertically centered:
  • For the x coordinate of the position, we’d set it to [player sprite's width]/2.
  • For the y coordinate of the position, we’d set it to [window height]/2
Here’s a picture that helps illustrate this a bit better:
Screen and Sprite Coordinates
So let’s give it a shot! Open up the Classes folder and click on HelloWorldLayer.m, and replace the init method with the following:
-(id) init
{
  if( (self=[super init] )) {
    CGSize winSize = [[CCDirector sharedDirector] winSize];
    CCSprite *player = [CCSprite spriteWithFile:@"Player.png" 
      rect:CGRectMake(0, 0, 27, 40)];
    player.position = ccp(player.contentSize.width/2, winSize.height/2);
    [self addChild:player];  
  }
  return self;
}
You can compile and run it, and your sprite should appear just fine, but note that the background defaults to black. For this artwork, white would look a lot better. One easy way to set the background of a layer in Cocos2D to a custom color is to use the CCLayerColor class. So let’s give this a shot. Click on HelloWorldLayer.h and change the HelloWorld interface declaration to read as follows:
@interface HelloWorldLayer : CCLayerColor
Then click on HelloWorldLayer.m and make a slight modification to the init method so we can set the background color to white:
if( (self=[super initWithColor:ccc4(255,255,255,255)] )) {
Go ahead and compile and run, and you should see your sprite on top of a white background. w00t our ninja looks ready for action!
Sprite Added Screenshot

Moving Targets

Next we want to add some targets into our scene for our ninja to combat. To make things more interesting, we want the targets to be moving – otherwise there wouldn’t be much of a challenge! So let’s create the targets slightly off screen to the right, and set up an action for them telling them to move to the left.
Add the following method right before the init method:
-(void)addTarget {
 
  CCSprite *target = [CCSprite spriteWithFile:@"Target.png" 
    rect:CGRectMake(0, 0, 27, 40)]; 
 
  // Determine where to spawn the target along the Y axis
  CGSize winSize = [[CCDirector sharedDirector] winSize];
  int minY = target.contentSize.height/2;
  int maxY = winSize.height - target.contentSize.height/2;
  int rangeY = maxY - minY;
  int actualY = (arc4random() % rangeY) + minY;
 
  // Create the target slightly off-screen along the right edge,
  // and along a random position along the Y axis as calculated above
  target.position = ccp(winSize.width + (target.contentSize.width/2), actualY);
  [self addChild:target];
 
  // Determine speed of the target
  int minDuration = 2.0;
  int maxDuration = 4.0;
  int rangeDuration = maxDuration - minDuration;
  int actualDuration = (arc4random() % rangeDuration) + minDuration;
 
  // Create the actions
  id actionMove = [CCMoveTo actionWithDuration:actualDuration 
    position:ccp(-target.contentSize.width/2, actualY)];
  id actionMoveDone = [CCCallFuncN actionWithTarget:self 
    selector:@selector(spriteMoveFinished:)];
  [target runAction:[CCSequence actions:actionMove, actionMoveDone, nil]];
 
}
I’ve spelled out things in a verbose manner here to make things as easy to understand as possible. The first part should make sense based on what we’ve discussed so far: we do some simple calculations to determine where we want to create the object, set the position of the object, and add it to the scene the same way we did for the player sprite.
The new element here is adding actions. Cocos2D provides a lot of extremely handy built-in actions you can use to animate your sprites, such as move actions, jump actions, fade actions, animation actions, and more. Here we use three actions on the target:
  • CCMoveTo: We use the CCMoveTo action to direct the object to move off-screen to the left. Note that we can specify the duration for how long the movement should take, and here we vary the speed randomly from 2-4 seconds.
  • CCCallFuncN: The CCCallFuncN function allows us to specify a callback to occur on our object when the action is performed. We are specifying a callback called “spriteMoveFinished” that we haven’t written yet – more below.
  • CCSequence: The CCSequence action allows us to chain together a sequence of actions that are performed in order, one at a time. This way, we can have the CCMoveTo action perform first, and once it is complete perform the CCCallFuncN action.
Next, add the callback function that we referred to in the CCCallFuncN action. You can add this right before addTarget:
-(void)spriteMoveFinished:(id)sender {
  CCSprite *sprite = (CCSprite *)sender;
  [self removeChild:sprite cleanup:YES];
}
The purpose of this function is to remove the sprite from the scene once it is off-screen. This is important so that we don’t leak memory over time by having tons of unused sprites sitting off-screen. Note that there are other (and better) ways to address this problem such as having reusable arrays of sprites, but for this beginner tutorial we are taking the simple path.
One last thing before we go. We need to actually call the method to create targets! And to make things fun, let’s have targets continuously spawning over time. We can accomplish this in Cocos2D by scheduling a callback function to be periodically called. Once per second should do for this. So add the following call to your init method before you return:
[self schedule:@selector(gameLogic:) interval:1.0];
And then implement the callback function simply as follows:
-(void)gameLogic:(ccTime)dt {
  [self addTarget];
}
That’s it! So now if you compile and run the project, now you should see targets happily moving across the screen:
Targets Screenshot

Shooting Projectiles

At this point, the ninja is just begging for some action – so let’s add shooting! There are many ways we could implement shooting, but for this game we are going to make it so when the user taps the screen, it shoots a projectile from the player in the direction of the tap.
I want to use a CCMoveTo action to implement this to keep things at a beginner level, but in order to use this we have to do a little math. This is because the CCMoveTo requires us to give a destination for the projectile, but we can’t just use the touch point because the touch point represents just the direction to shoot relative to the player. We actually want to keep the bullet moving through the touch point until the bullet goes off-screen.
Here’s a picture that illustrates the matter:
Projectile Triangle
So as you can see, we have a small triangle created by the x and y offset from the origin point to the touch point. We just need to make a big triangle with the same ratio – and we know we want one of the endpoints to be off the screen.
Ok, so onto the code. First we have to enable touches on our layer. Add the following line to your init method:
self.isTouchEnabled = YES;
Since we’ve enabled touches on our layer, we will now receive callbacks on touch events. So let’s implement the ccTouchesEnded method, which is called whenever the user completes a touch, as follows:
- (void)ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
 
  // Choose one of the touches to work with
  UITouch *touch = [touches anyObject];
  CGPoint location = [touch locationInView:[touch view]];
  location = [[CCDirector sharedDirector] convertToGL:location];
 
  // Set up initial location of projectile
  CGSize winSize = [[CCDirector sharedDirector] winSize];
  CCSprite *projectile = [CCSprite spriteWithFile:@"Projectile.png" 
    rect:CGRectMake(0, 0, 20, 20)];
  projectile.position = ccp(20, winSize.height/2);
 
  // Determine offset of location to projectile
  int offX = location.x - projectile.position.x;
  int offY = location.y - projectile.position.y;
 
  // Bail out if we are shooting down or backwards
  if (offX <= 0) return;
 
  // Ok to add now - we've double checked position
  [self addChild:projectile];
 
  // Determine where we wish to shoot the projectile to
  int realX = winSize.width + (projectile.contentSize.width/2);
  float ratio = (float) offY / (float) offX;
  int realY = (realX * ratio) + projectile.position.y;
  CGPoint realDest = ccp(realX, realY);
 
  // Determine the length of how far we're shooting
  int offRealX = realX - projectile.position.x;
  int offRealY = realY - projectile.position.y;
  float length = sqrtf((offRealX*offRealX)+(offRealY*offRealY));
  float velocity = 480/1; // 480pixels/1sec
  float realMoveDuration = length/velocity;
 
  // Move projectile to actual endpoint
  [projectile runAction:[CCSequence actions:
    [CCMoveTo actionWithDuration:realMoveDuration position:realDest],
    [CCCallFuncN actionWithTarget:self selector:@selector(spriteMoveFinished:)],
    nil]];
 
}
In the first portion, we choose one of the touches to work with, get the location in the current view, then call convertToGL to convert the coordinates to our current layout. This is important to do since we are in landscape mode.
Next we load up the projectile sprite and set the initial position as usual. We then determine where we wish to move the projectile to, using the vector between the player and the touch as a guide, according to the algorithm described previously.
Note that the algorithm isn’t ideal. We’re forcing the bullet to keep moving until it reaches the offscreen X position – even if we would have gone offscreen in the Y position first! There are various ways to address this including checking for the shortest length to go offscreen, having our game logic callback check for offscreen projectiles and removing rather than using the callback method, etc. but for this beginner tutorial we’ll keep it as-is.
The last thing we have to do is determine the duration for the movement. We want the bullet to be shot at a constant rate despite the direction of the shot, so again we have to do a little math. We can figure out how far we’re moving by using the Pythagorean Theorem. Remember from geometry, that is the rule that says the length of the hypotenuse of a triangle is equal to the square root of the sum of the squares of the two sides.
Once we have the distance, we just divide that by the velocity in order to get the duration. This is because velocity = distance over time, or in other words time = distance over velocity.
The rest is setting the actions just like we did for the targets. Compile and run, and now your ninja should be able to fire away at the oncoming hordes!
Projectiles Screenshot

Collision Detection

So now we have shurikens flying everywhere – but what our ninja really wants to do is to lay some smack down. So let’s add in some code to detect when our projectiles intersect our targets.
There are various ways to solve this with Cocos2D, including using one of the included physics libraries: Box2D or Chipmunk. However to keep things simple, we are going to implement simple collision detection ourselves.
To do this, we first need to keep better track of the targets and projectiles currently in the scene. Add the following to your HelloWorldLayer class declaration:
NSMutableArray *_targets;
NSMutableArray *_projectiles;
And initialize the arrays in your init method:
_targets = [[NSMutableArray alloc] init];
_projectiles = [[NSMutableArray alloc] init];
And while we’re thinking of it, clean up the memory in your dealloc method:
[_targets release];
_targets = nil;
[_projectiles release];
_projectiles = nil;
Now, modify your addTarget method to add the new target to the targets array and set a tag for future use:
target.tag = 1;
[_targets addObject:target];
And modify your ccTouchesEnded method to add the new projectile to the projectiles array and set a tag for future use:
projectile.tag = 2;
[_projectiles addObject:projectile];
Finally, modify your spriteMoveFinished method to remove the sprite from the appropriate array based on the tag:
if (sprite.tag == 1) { // target
  [_targets removeObject:sprite];
} else if (sprite.tag == 2) { // projectile
  [_projectiles removeObject:sprite];
}
Compile and run the project to make sure everything is still working OK. There should be no noticeable difference at this point, but now we have the bookkeeping we need to implement some collision detection.
Now add the following method to HelloWorldLayer:
- (void)update:(ccTime)dt {
 
  NSMutableArray *projectilesToDelete = [[NSMutableArray alloc] init];
  for (CCSprite *projectile in _projectiles) {
    CGRect projectileRect = CGRectMake(
      projectile.position.x - (projectile.contentSize.width/2), 
      projectile.position.y - (projectile.contentSize.height/2), 
      projectile.contentSize.width, 
      projectile.contentSize.height);
 
    NSMutableArray *targetsToDelete = [[NSMutableArray alloc] init];
    for (CCSprite *target in _targets) {
      CGRect targetRect = CGRectMake(
        target.position.x - (target.contentSize.width/2), 
        target.position.y - (target.contentSize.height/2), 
        target.contentSize.width, 
        target.contentSize.height);
 
      if (CGRectIntersectsRect(projectileRect, targetRect)) {
        [targetsToDelete addObject:target];    
      }      
    }
 
    for (CCSprite *target in targetsToDelete) {
      [_targets removeObject:target];
      [self removeChild:target cleanup:YES];         
    }
 
    if (targetsToDelete.count > 0) {
      [projectilesToDelete addObject:projectile];
    }
    [targetsToDelete release];
  }
 
  for (CCSprite *projectile in projectilesToDelete) {
    [_projectiles removeObject:projectile];
    [self removeChild:projectile cleanup:YES];
  }
  [projectilesToDelete release];
}
The above should be pretty clear. We just iterate through our projectiles and targets, creating rectangles corresponding to their bounding boxes, and use CGRectIntersectsRect to check for intersections. If any are found, we remove them from the scene and from the arrays. Note that we have to add the objects to a “toDelete” array because you can’t remove an object from an array while you are iterating through it. Again, there are more optimal ways to implement this kind of thing, but I am going for the simple approach.
You just need one more thing before you’re ready to roll – schedule this method to run as often as possible by adding the following line to your init method:
[self schedule:@selector(update:)];
Give it a compile and run, and now when your projectiles intersect targets they should disappear!

Finishing Touches

We’re pretty close to having a workable (but extremely simple) game now. We just need to add some sound effects and music (since what kind of game doesn’t have sound!) and some simple game logic.
If you’ve been following my blog series on audio programming for the iPhone, you’ll be extremely pleased to hear how simple the Cocos2D developers have made it to play basic sound effects in your game.
First, drag some background music and a shooting sound effect into your resources folder. Feel free to use the cool background music I made or my awesome pew-pew sound effect, or make your own.
Then, add the following import to the top of your HelloWorldLayer.m:
#import "SimpleAudioEngine.h"
In your init method, start up the background music as follows:
[[SimpleAudioEngine sharedEngine] playBackgroundMusic:@"background-music-aac.caf"];
And in your ccTouchesEnded method play the sound effect as follows:
[[SimpleAudioEngine sharedEngine] playEffect:@"pew-pew-lei.caf"];
Now, let’s create a new scene that will serve as our “You Win” or “You Lose” indicator. Click on the Classes folder and go to File\New File, and choose Objective-C class, and make sure subclass of NSObject is selected. Click Next, then type in GameOverScene as the filename, and make sure “Also create GameOverScene.h” is checked.
Then replace GameOverScene.h with the following code:
#import "cocos2d.h"
 
@interface GameOverLayer : CCLayerColor {
  CCLabelTTF *_label;
}
@property (nonatomic, retain) CCLabelTTF *label;
@end
 
@interface GameOverScene : CCScene {
  GameOverLayer *_layer;
}
@property (nonatomic, retain) GameOverLayer *layer;
@end
Then replace GameOverScene.m with the following code:
#import "GameOverScene.h"
#import "HelloWorldLayer.h"
 
@implementation GameOverScene
@synthesize layer = _layer;
 
- (id)init {
 
  if ((self = [super init])) {
    self.layer = [GameOverLayer node];
    [self addChild:_layer];
  }
  return self;
}
 
- (void)dealloc {
  [_layer release];
  _layer = nil;
  [super dealloc];
}
 
@end
 
@implementation GameOverLayer
@synthesize label = _label;
 
-(id) init
{
  if( (self=[super initWithColor:ccc4(255,255,255,255)] )) {
 
    CGSize winSize = [[CCDirector sharedDirector] winSize];
    self.label = [CCLabelTTF labelWithString:@"" fontName:@"Arial" fontSize:32];
    _label.color = ccc3(0,0,0);
    _label.position = ccp(winSize.width/2, winSize.height/2);
    [self addChild:_label];
 
    [self runAction:[CCSequence actions:
      [CCDelayTime actionWithDuration:3],
      [CCCallFunc actionWithTarget:self selector:@selector(gameOverDone)],
      nil]];
 
  } 
  return self;
}
 
- (void)gameOverDone {
 
  [[CCDirector sharedDirector] replaceScene:[HelloWorldLayer scene]];
 
}
 
- (void)dealloc {
  [_label release];
  _label = nil;
  [super dealloc];
}
 
@end
Note that there are two different objects here: a scene and a layer. The scene can contain any number of layers, however in this example it just has one. The layer just puts a label in the middle of the screen, and schedules a transition to occur 3 seconds in the future back to the Hello World scene.
Finally, let’s add some extremely basic game logic. First, let’s keep track of the projectiles the player has destroyed. Add a member variable to your HelloWorldLayer class in HelloWorldLayer.h as follows:
int _projectilesDestroyed;
Inside HelloWorldLayer.m, add an import for the GameOverScene class:
#import "GameOverScene.h"
Increment the count and check for the win condition in your update method inside the targetsToDelete loop right after removeChild:target:
_projectilesDestroyed++;
if (_projectilesDestroyed > 30) {
  GameOverScene *gameOverScene = [GameOverScene node];
  _projectilesDestroyed = 0;
  [gameOverScene.layer.label setString:@"You Win!"];
  [[CCDirector sharedDirector] replaceScene:gameOverScene];
}
And finally let’s make it so that if even one target gets by, you lose. Modify the spriteMoveFinished method by adding the following code inside the tag == 1 case right after removeChild:sprite:
GameOverScene *gameOverScene = [GameOverScene node];
[gameOverScene.layer.label setString:@"You Lose :["];
[[CCDirector sharedDirector] replaceScene:gameOverScene];
Go ahead and give it a compile and run, and you should now have win and lose conditions and see a game over scene when appropriate!

Gimme The Code!

And that’s a wrap! Here’s the full code for the simple Cocos2D iPhone game that we developed thus far.

Where To Go From Here?

This project could be a nice basis for playing around some more with Cocos2D by adding some new features into the project. Maybe try adding in a bar chart to show how many more targets you have to destroy before you win (check out the drawPrimitivesTest sample project for examples of how to do that). Maybe add cooler death animations for when the monsters are destroyed (see ActionsTest, EffectsTest, and EffectsAdvancedTest projects for that). Maybe add more sounds, artwork, or gameplay logic just for fun. The sky’s the limit!
If you want to keep going with this tutorial series, check out part two, How To Add A Rotating Turret, or part three, Harder Monsters and More Levels!
Also, if you’d like to keep learning more about Cocos2D, check out my tutorials on how to create buttons in Cocos2Dintro to Box2D, or how to create a simple Breakout game.
Feel free to chime in if you know of any better ways to do various things with this project or if there are any problems – like I said this is the first time I’ve played with Cocos2D so I have a lot left to learn!