How to implement water ripples? - iphone

I'm working on an iphone game. In that i had to produce water ripples. I dont know how to get that. I heard thatit can be done with openGL. I am very new to this concept. Can any one guide me?

Here are some resources I found:
Language Agnostic 2d Water Ripple Algorithm
(source: virgin.net)
(source: virgin.net)
OpenGL Project with Water Ripples (Source)
(source: sulaco.co.za)
You also might want to swing by GameDev's FAQ. Scroll down to the "Water Rendering" section.

jk:
z=sin(x)+cos(y)
More seriously, doesn't the Quartz Composer basically do ripples for you as one of the effects layers? Or was that announced only for the iPhone 3.0 SDK?

I found the source code of the water ripple effect so following code to implement into your project and solove your problem also.
import "HelloWorldLayer.h"
// HelloWorldLayer implementation
#implementation HelloWorldLayer
+(CCScene *) scene
{
// 'scene' is an autorelease object.
CCScene *scene = [CCScene node];
// 'layer' is an autorelease object.
HelloWorldLayer *layer = [HelloWorldLayer node];
// add layer as a child to scene
[scene addChild: layer];
// return the scene
return scene;
}
// on "init" you need to initialize your instance
-(id) init
{
if( (self=[super init])) {
rippleImage = [ pgeRippleSprite ripplespriteWithFile:#"image_old.png" ];
[ self addChild:rippleImage ];
CCLabelTTF *label = [CCLabelTTF labelWithString:#"Hello Cocos2D Forum" fontName:#"Marker Felt" fontSize:16];
label.position = ccp( 80 , 300 );
[self addChild: label];
[ [ CCTouchDispatcher sharedDispatcher ] addTargetedDelegate:self priority:0 swallowsTouches:YES ];
// schedule update
[ self schedule:#selector( update: ) ];
}
return self;
}
float runtime = 0;
-( BOOL )ccTouchBegan:( UITouch* )touch withEvent:( UIEvent* )event {
runtime = 0.1f;
[ self ccTouchMoved:touch withEvent:event ];
return( YES );
}
-( void )ccTouchMoved:(UITouch *)touch withEvent:(UIEvent *)event {
CGPoint pos;
if ( runtime >= 0.1f ) {
runtime -= 0.1f;
// get touch position and convert to screen coordinates
pos = [ touch locationInView: [ touch view ] ];
pos = [ [ CCDirector sharedDirector ] convertToGL:pos ];
// [ rippleImage addRipple:pos type:RIPPLE_TYPE_RUBBER strength:1.0f ];
[ rippleImage addRipple:pos type:RIPPLE_TYPE_WATER strength:2.0f ];
}
}
-( void )update:( ccTime )dt {
runtime += dt;
[ rippleImage update:dt ];
}
// on "dealloc" you need to release all your retained objects
- (void) dealloc
{
// in case you have something to dealloc, do it in this method
// in this particular example nothing needs to be released.
// cocos2d will automatically release all the children (Label)
// don't forget to call "super dealloc"
[super dealloc];
}
#end
Also you can download the source code from the Git

Related

Cocos2d: Initializing layers by node - class is nil

I am a Cocos2d beginner so although there is a bit much code here. Some with experience should be able to see what I am doing wrong here. It Crashes on the NSAssert in backgroundLayer when I try to get a instance of the GameBackground class that is added as a child to this layer in the +(id)scene class method. It crashes cause it is Nil (
the GameBackground class). But I thought i initialized it in the +(id)scene method when asking for it´s node? But please correct me, my thinking is fuzzy regarding this matter.
static GameLayer *sharedGameLayer = nil;
+(id) scene
{
CCScene *scene = [CCScene node];
//GameLayer* layer = [GameLayer node];
//[scene addChild:layer];
CCNode *backgroundLayer = [GameBackground node];
[scene addChild:backgroundLayer z:1 tag:LayerTagBackgroundLayer];
CCLayer *cocosObjectsLayer = [HelloWorldLayer node];
[scene addChild:cocosObjectsLayer z:2 tag:LayerTagGameLayer];
CCLayer *userTouchInterface = [GameUserTouchInteface node];
[scene addChild:userTouchInterface z:3 tag:LayerTagUILayer];
return scene;
}
// To access this scene: MultiLayerScene* sceneLayer = [MultiLayerScene sharedLayer];
+ (GameLayer *) sharedLayer
{
NSAssert(sharedGameLayer = nil, #"sharedGameLayer not available.");
//if (sharedGameLayer == nil) sharedGameLayer = [[GameLayer alloc] init];
return sharedGameLayer;
}
-(id) init
{
NSLog(#"init called");
self = [super init];
if (self)
{
NSAssert(sharedGameLayer == nil, #"another GameLayer is already in use!");
sharedGameLayer = self;
// uncomment if you want the update method to be executed every frame
//[self scheduleUpdate];
}
return self;
}
// MultiLayerScene* sceneLayer = [MultiLayerScene sharedLayer];
// To access this scene: GameBackgroundLayer* backgroundLayer = [sceneLayer backgroundLayer];
-(GameBackground *) backgroundLayer
{
CCNode *layer = [self getChildByTag:LayerTagBackgroundLayer];
NSAssert([layer isKindOfClass:[GameBackground class]], #"%#: not a BackgroundLayer!", NSStringFromSelector(_cmd));
return (GameBackground *)layer;
}
Then trying to get an instance of the background layer from another class:
GameBackground *backgroundLayer = [GameLayer sharedLayer].backgroundLayer;
[backgroundLayer runAction:sequence];
I'm guessing the assertion that is failing is.-
NSAssert(sharedGameLayer = nil, #"sharedGameLayer not available.");
You're assigning nil to sharedGameLayer instead of comparing (==). Also, you've commented the line where you set sharedGameLayer. Just guessing here, but you may want to do something like this.-
+(id) scene
{
CCScene *scene = [CCScene node];
sharedGameLayer = [GameLayer node];
[scene addChild:layer];
return scene;
}
Leave your static constructor as clean as possible.
+ (GameLayer *) sharedLayer
{
return sharedGameLayer;
}
-(id) init
{
NSLog(#"init called");
self = [super init];
if (self)
{
CCNode *backgroundLayer = [GameBackground node];
[self addChild:backgroundLayer z:1 tag:LayerTagBackgroundLayer];
CCLayer *cocosObjectsLayer = [HelloWorldLayer node];
[self addChild:cocosObjectsLayer z:2 tag:LayerTagGameLayer];
CCLayer *userTouchInterface = [GameUserTouchInteface node];
[self addChild:userTouchInterface z:3 tag:LayerTagUILayer];
// uncomment if you want the update method to be executed every frame
//[self scheduleUpdate];
}
return self;
}
Create your nodes tree in the init method, and add them as children of your root layer (sharedGameLayer) instead of scene object.

Move Image in CocoS2d

I am developing game in Cocos2d. In it background of scene moving constantly with x - axis.
I want to understand how can i do it because i am new in cocos2d.
thanks in advance
Take a look to my code - here are the sources. Find the "moving" technique in HelloWorldLayer.m. I have taken a 360 panorama picture and put it to move continuously from right to left, in fullscreen.
In your YourClass.h file:
#import "cocos2d.h"
#interface YourClass : CCLayer
+(CCScene *) scene;
#end
In your YourClass.m file:
#import "YourClass.h"
#implementation YourClass
CCSprite *panorama;
CCSprite *appendix;
//_____________________________________________________________________________________
+(CCScene *) scene
{
// 'scene' is an autorelease object.
CCScene *scene = [CCScene node];
// 'layer' is an autorelease object.
YourClass *layer = [YourClass node];
// add layer as a child to scene
[scene addChild: layer];
// return the scene
return scene;
}
//_____________________________________________________________________________________
// on "init" you need to initialize your instance
-(id) init
{
// always call "super" init
// Apple recommends to re-assign "self" with the "super" return value
if( (self=[super init])) {
panorama = [CCSprite spriteWithFile: #"panorama.png"];
panorama.position = ccp( 1709/2 , 320/2 );
[self addChild:panorama];
appendix = [CCSprite spriteWithFile: #"appendix.png"];
appendix.position = ccp( 1709+480/2-1, 320/2 );
[self addChild:appendix];
// schedule a repeating callback on every frame
[self schedule:#selector(nextFrame:)];
}
return self;
}
//_____________________________________________________________________________________
- (void) nextFrame:(ccTime)dt {
panorama.position = ccp(panorama.position.x - 100 * dt, panorama.position.y);
appendix.position = ccp(appendix.position.x - 100 * dt, appendix.position.y);
if (panorama.position.x < -1709/2) {
panorama.position = ccp( 1709/2 , panorama.position.y );
appendix.position = ccp( 1709+480/2-1, appendix.position.y );
}
}
// on "dealloc" you need to release all your retained objects
- (void) dealloc
{
// in case you have something to dealloc, do it in this method
// in this particular example nothing needs to be released.
// cocos2d will automatically release all the children (Label)
// don't forget to call "super dealloc"
[super dealloc];
}
//_____________________________________________________________________________________
#end
Play a little with this code and you will get what you need.

Cocos2D random sprite movement

As a very beginner in Cocos2D i´m trying to make an iPhone game where some cows move randomly around the screen. I used the code for moving the sprites from here: highoncoding.com/.../. I´m adding the sprites in the init method wia an addAnimal method:
-(void) addAnimal {
animal = [CCSprite spriteWithFile:#"cow.png"];
animal.position = [self generateRandomCoordinates];
[self addChild:animal];
[self startAnimation:animal];
}
My problem:
When i add more than one cow to my game, they move from that random spawn position to another random position and then the first cow stops and the other cow goes on correctly. The startAnimation command in the finishedMoving method goes always to the last sprite. That means i need better control over my sprites but how to da that right?
You can try to implement animal class, that will contain your sprite and incapsulate random movement. Smth like
#implementation Cow
- (id) init
{
self = [super init];
if( self != nil )
{
CCSprite* cowSprite = [CCSprite spriteWithFile:#"cow.png"];
[self addChild: cowSprite];
}
return self;
}
- (void) onEnter
{
[super onEnter];
[self makeRandomMovement];
}
- (void) makeRandomMovement
{
id randomMoveAction = // create your random move action here
id moveEndCallback = [CCCallFunc actionWithTarget: self selector: #selector(makeRandomMovement)];
id sequence = [CCSequence actionOne: randomMoveAction two: moveEndCallback];
[self runAction: sequence];
}
#end
In such way after ending random movement part, method makeRandomMovement will be called again to generate and start new random movement part.
then remake your addAnimal method to smth like
- (void) addAnimal
{
Cow* newCow = [Cow node];
[newCow setPosition: [self generateRandomPosition]];
[self addChild: newCow];
}

Sprite and its body don't act the same way to forces

So I created a body and filled it with a sprite. The problem is that if I apply a force on the body, the sprite goes higher than the body (which I can see from debug_draw). Any idea why this is happening?
UPDATE
- (void)tick:(ccTime) dt {
_world->Step(dt, 10, 10);
for(b2Body *b = _world->GetBodyList(); b; b=b->GetNext()) {
if (b->GetUserData() != NULL) {
CCSprite *playerData = (CCSprite *)b->GetUserData();
playerData.position = ccp(b->GetPosition().x * PTM_RATIO,
b->GetPosition().y * PTM_RATIO);
playerData.rotation = -1 * CC_RADIANS_TO_DEGREES(b->GetAngle());
}
}
}
And here's how I call this in my init method:
[self schedule:#selector(tick:)];
The for loop which gets the User_Data is kept on repeating now and then so to update the position of the creature would be difficult.. Please move the sprites position in the tick method....
-(void) moveCreature
{
// Please use the position to set the directions. This is used to fall from upside down in Portrait mode
[spriteCreature setPosition:ccp(spriteCreature.position.x,spriteCreature.position.y-5)];
}
Now in the init method schedule the sprite
-(id) init
{
if((self = [super init]))
{
// Create your World and other stuffs
[self schedule:#selector(moveCreature)];
}
return self;
}
The above stuff would carry the sprite in the body n fall down...

iPhone, Cocos2D - moving sprite left/right while touching screen

I'm new to Objective C and app development so please go easy on me!
I'm trying to make a basic game and need to move a sprite left or right continuously while the user's finger is on the screen - left side to go left, right to go right...
I'm trying to use update to repeat movements of a few pixels every 1/60th second. So far, this is what I have (and sorry about the formatting):
#import "GameplayLayer.h"
#implementation GameplayLayer
-(id)init {
self = [super init];
if (self != nil) {
CGSize screenSize = [CCDirector sharedDirector].winSize;
// enable touches
self.isTouchEnabled = YES;
blobSprite = [CCSprite spriteWithFile:#"blob.png"];
[blobSprite setPosition: CGPointMake(screenSize.width/2, screenSize.height*0.17f)];
ball = [CCSprite spriteWithFile:#"ball.png"];
[ball setPosition:CGPointMake(10, screenSize.height*0.75f)];
[self addChild:blobSprite];
[self addChild:ball];
[self schedule:#selector(update) interval:1.0f/60.0f];
}
return self;
}
-(void) update:(ccTime)dt{
if (_tapDownLeft == YES){
blobSprite.position.x==blobSprite.position.x-5;
}
if (_tapDownRight == YES){
blobSprite.position.x==blobSprite.position.x+5;
}
}
-(void) ccTouchesBegan:(UITouch*)touch withEvent: (UIEvent *)event{
CGPoint touchLocation = [touch locationInView:[touch view]];
touchLocation = [[CCDirector sharedDirector] convertToGL:touchLocation];
if (touchLocation.x > 400) {
if ((blobSprite.position.x+10)<460){
_tapDownRight = YES;
}
}
if (touchLocation.x < 200) {
if ((blobSprite.position.x-10>20)){
_tapDownLeft = YES;
}
}
else {
_tapDownLeft = NO;
_tapDownRight = NO;
}
}
-(void)ccTouchEnded:(UITouch *)touch withEvent:(UIEvent *)event{
_tapDownLeft = NO;
_tapDownRight = NO;
}
-(void) registerWithTouchDispatcher{
[[CCTouchDispatcher sharedDispatcher]addTargetedDelegate:self priority:0 swallowsTouches:YES];
}
#end
Am I on the right lines with this? At the moment it's giving me 'expression result unused' in update. Could anyone tell me what I'm missing? Any help would be greatly appreciated.
Thanks,
Patrick
i see a few things here:
not certain your selector will call update : #selector(update:)
I would not rely on dt being either exactly 1/60th of a second, nor being constant. I would favor defining a speed constant (in points per second) and compute the deltaX in points based on the desired speed and dt, at each update cycle.
I dont see a 'registerWithTouchDispatcher' call (i try to place them in onEnter and onExit) methods.
Somewhere in there, make certain you remove your children (either in dealloc, or better in a local cleanup method (dont forget to invoke [super cleanup]).
Remove the argument in the update function