iPhone, cocos2d and accelerometer - iphone

I'm reading 'Learn iPhone and iPad Cocos2D Game Development' and in chapter 4, there's a simple sample using accelerometer. It works well if I use x-axis only as the book but with y-axis, sprite's movement is not smooth if it on the edge of the screen.
+ (id)scene
{
CCScene* scene = [CCScene node];
CCLayer* layer = [GameScene node];
[scene addChild:layer];
return scene;
}
- (id)init
{
if ((self = [super init]))
{
CCLOG(#"%#: %#", NSStringFromSelector(_cmd), self);
self.isAccelerometerEnabled = YES;
player = [CCSprite spriteWithFile:#"alien.png"];
[self addChild:player z:0 tag:1];
CGSize screenSize = [[CCDirector sharedDirector] winSize];
float imageHeight = [player texture].contentSize.height;
player.position = CGPointMake(screenSize.width / 2, imageHeight / 2);
[self scheduleUpdate];
}
return self;
}
- (void)dealloc
{
CCLOG(#"%#: %#", NSStringFromSelector(_cmd), self);
[super dealloc];
}
- (void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration
{
float deceleration = 0.4f;
float sensitivity = 6.0f;
float maxVelocity = 100;
playerVelocity.x = playerVelocity.x * deceleration + acceleration.x * sensitivity;
playerVelocity.y = playerVelocity.y * deceleration + acceleration.y * sensitivity;
if (playerVelocity.x > maxVelocity)
{
playerVelocity.x = maxVelocity;
}
else if (playerVelocity.x < -maxVelocity)
{
playerVelocity.x = -maxVelocity;
}
if (playerVelocity.y > maxVelocity)
{
playerVelocity.y = maxVelocity;
}
else if (playerVelocity.y < -maxVelocity)
{
playerVelocity.y = -maxVelocity;
}
}
- (void)update:(ccTime)delta
{
CGPoint pos = player.position;
pos.x += playerVelocity.x;
pos.y += playerVelocity.y;
CGSize screenSize = [[CCDirector sharedDirector] winSize];
float imageWidthHalved = [player texture].contentSize.width * 0.5f;
float leftBorderLimit = imageWidthHalved;
float rightBorderLimit = screenSize.width - imageWidthHalved;
if (pos.x < leftBorderLimit)
{
pos.x = leftBorderLimit;
playerVelocity = CGPointZero;
}
else if (pos.x > rightBorderLimit)
{
pos.x = rightBorderLimit;
playerVelocity = CGPointZero;
}
float imageHeightHalved = [player texture].contentSize.height * 0.5f;
float topBorderLimit = screenSize.height - imageHeightHalved;
float bottomBorderLimit = imageHeightHalved;
if (pos.y < bottomBorderLimit)
{
pos.y = bottomBorderLimit;
playerVelocity = CGPointZero;
}
else if (pos.y > topBorderLimit)
{
pos.y = topBorderLimit;
playerVelocity = CGPointZero;
}
player.position = pos;
}
What's the problem?

If you want you can try what I did in my game:
#define SIGN(x) ((x < 0.0f) ? -1.0f : 1.0f)
- (void)accelerometer:(UIAccelerometer*)accelerometer didAccelerate:(UIAcceleration*)acceleration {
float kFilteringFactor = 0.01;
accels[0] = acceleration.x * kFilteringFactor + accels[0] * (1.0f - kFilteringFactor);
accels[1] = acceleration.y * kFilteringFactor + accels[1] * (1.0f - kFilteringFactor);
accels[2] = acceleration.z * kFilteringFactor + accels[2] * (1.0f - kFilteringFactor);
float xx;
float yy;
// extract the acceleration components
xx = -[acceleration x];
yy = [acceleration y];
// Has the direction changed?
float accelDirX = SIGN(xvelocity) * -1.0f;
float newDirX = SIGN(xx);
float accelDirY = SIGN(yvelocity) * -1.0f;
float newDirY = SIGN(yy);
// Accelerate. To increase viscosity, lower the values below 1.0f
if (accelDirX == newDirX)
xaccel = (abs(xaccel) + 0.99f) * SIGN(xaccel);
if (accelDirY == newDirY)
yaccel = (abs(yaccel) + 0.99f) * SIGN(yaccel);
// Apply acceleration changes to the current velocity
xvelocity = -xaccel * xx;
yvelocity = -yaccel * yy;
[sprite moveByAccelerometerX:yvelocity Y:xvelocity];
}

First of all, thanks for reading my book! :)
You can find an improved filtering method (ease exponential) that I'm using in this article, it also contains basic info on how the accelerometer works.
You can learn more about accelerometer input from the Tilt to Live developers and their approach, comes with a sample project.

I have bought the book and I found that the edge of screen collision detection doesn't work properly unless you have the same size sprite as in the example. Either make your sprite the same size or make the sprite wrap around the screen instead of stopping, which is what I did.

Related

How to make background repeat in vertical direction using parallax

I have been looking to make background repeat in vertical direction but there is always some flickering..
I searched a lot on goggle and some book for reference but not able to find a proper reply
There are lot of proper reply for background repeat on horizontal direction
-(void) update:(ccTime)delta
{
CCSprite* sprite;
CCARRAY_FOREACH([spriteBatch children], sprite)
{
NSNumber* factor = [speedFactors objectAtIndex:sprite.zOrder];
CGPoint pos = sprite.position;
pos.y -= scrollSpeed * [factor floatValue] * (delta * 50);
if (pos.y < -screenSize.height)
{
pos.y += (screenSize.height * 2) - 2;
}
sprite.position = pos;
}
}
Loading new background each time? I strongly suspect flickering is caused by loading time in texture. You can use threaded loading to avoid flickering.
Here is once other question with something similar problem.
Continuous-horizontal-scrolling-of-background-in-cocos2d: Refer my answer
Continuous vertical scroll:
#define IS_IPAD (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
#define MM_BG_SPEED_DUR ( IS_IPAD ? (6.0f) : (2.0f) )
-(void)onEnter
{
[super onEnter];
[self initBackground];
[self schedule: #selector(tick:)];
}
-(void)initBackground
{
NSString *tex = #"BG/Background.png";//[self getThemeBG];
mBG1 = [CCSprite spriteWithFile:tex];
mBG1.position = ccp(s.width*0.5f,s.height*0.5f);
[self addChild:mBG1 z:LAYER_BACKGROUND];
mBG2 = [CCSprite spriteWithFile:tex];
mBG2.position = ccp(s.width*0.5f,s.height*0.5f+mBG1.contentSize.Height);
mBG2.flipY = true;
[self addChild:mBG2 z:LAYER_BACKGROUND];
}
-(void)scrollBackground:(ccTime)dt
{
CGSize s = [[CCDirector sharedDirector] winSize];
CGPoint pos1 = mBG1.position;
CGPoint pos2 = mBG2.position;
pos1.y -= MM_BG_SPEED_DUR;
pos2.y -= MM_BG_SPEED_DUR;
if(pos1.y <=-(s.height*0.5f) )
{
pos1.y = pos2.y + mBG2.contentSize.height;
}
if(pos2.y <=-(s.height*0.5f) )
{
pos2.y = pos1.y + mBG1.contentSize.height;
}
mBG1.position = pos1;
mBG2.position = pos2;
}
-(void)tick:(ccTime)dt
{
[self scrollBackground:dt];
}

Accelerometer based movement

Now woking on game that uses accelerometer to move player sprite left and right.
I used this tutorial: COCOS2D_ACCELEROMETER_MOVEMENT
This works only sometime….some time not move..How can I resolve this problem?
Here is my sample: See this Sample
Thanks for reading this…what's wrong with my code ? Is there any other way?
Here is my code:
#define kHeroMovementAction 1
#define kPlayerSpeed 500
- (void) accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration {
// use the running scene to grab the appropriate game layer by it's tag
// grab the player sprite from that layer using it's tag
CCSprite *playerSprite = mPlayer;
float destX, destY;
BOOL shouldMove = NO;
float currentX = playerSprite.position.x;
float currentY = playerSprite.position.y;
if(acceleration.x > 0.25) { // tilting the device upwards
destX = currentX - (acceleration.y * kPlayerSpeed);
destY = currentY + (acceleration.x * kPlayerSpeed);
shouldMove = YES;
} else if (acceleration.x < -0.25) { // tilting the device downwards
destX = currentX - (acceleration.y * kPlayerSpeed);
destY = currentY + (acceleration.x * kPlayerSpeed);
shouldMove = YES;
} else
if(acceleration.y < -0.25) { // tilting the device to the right
destX = currentX - (acceleration.y * kPlayerSpeed);
destY = currentY + (acceleration.x * kPlayerSpeed);
shouldMove = YES;
} else if (acceleration.y > 0.25) { // tilting the device to the left
destX = currentX - (acceleration.y * kPlayerSpeed);
destY = currentY + (acceleration.x * kPlayerSpeed);
shouldMove = YES;
} else {
destX = currentX;
destY = currentY;
}
if(shouldMove)
{
CGSize wins = [[CCDirector sharedDirector] winSize];
// ensure we aren't moving out of bounds
if(destX < 30 || destX > wins.width - 30 || destY < 30 || destY > wins.height - 100) {
// do nothing
} else {
CCAction *action = [CCMoveTo actionWithDuration:0.5f position: CGPointMake(destX, playerSprite.position.y)];
[playerSprite stopActionByTag:kHeroMovementAction];
[action setTag:kHeroMovementAction];
[playerSprite runAction:action];
}
} else {
// should stop
[playerSprite stopActionByTag:kHeroMovementAction];
}
}
Updates: Here is best way to do this.
You should look at Ray Wenderlich's scrolling tutorial here
His accelerometer part is near the bottom of the page.

How to move CCSprite Using Accelerometer

hi I am developing a cocos2d Game. I want to move CCSprite with accelerometer value change. I have implemented this code for accelerometer. but in landscape position tilt iphone sprite is moving up and down. but i want to move sprite forward and backward.
[[UIAccelerometer sharedAccelerometer] setUpdateInterval:1/60];
[[UIAccelerometer sharedAccelerometer] setDelegate:self];
[self scheduleUpdate];
- (void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration
{
float deceleration = 0.4f;
float sinsitivity = 6.0f;
//float maxVelocity = 100;
// because we are in landscape mode where x is always +90 or -90
// float acely = acceleration.x;
float acelx = acceleration.y;
movement = movement * deceleration + acelx * sinsitivity;
float angleRadians = atanf((float)acceleration.y / (float)acceleration.x);
float angleDegrees = CC_RADIANS_TO_DEGREES(angleRadians);
// float cocosAngle = angleDegrees;
if(angleDegrees<85 && angleDegrees >-85 )
{
_player.rotation = angleDegrees;
}
//NSLog(#" angle = %f",angleDegrees);
if([ShieldCover visible]==TRUE)
{
ShieldCover.rotation= angleDegrees;
}
// CGPoint converted = ccp( (float)acceleration.y, (float)acceleration.x);
// update the rotation based on the z-rotation
// the sprite will always be 'standing up'
//_player.rotation = (float) CC_RADIANS_TO_DEGREES( atan2f( converted.x, converted.y) + M_PI );
// ShieldCover.rotation =(float) CC_RADIANS_TO_DEGREES( atan2f( converted.x, converted.y) + M_PI );
}
- (void)update:(ccTime)delta {
//assuming that you have a sprite called _fireman with 100 px width
if ( _player.position.y > 0 && _player.position.y < 320) {
//_fireman is at neither edge of the screen so move the paddle!
_player.position = ccp(_player.position.x, _player.position.y + movement);
}
if ( _player.position.y < 0 ) {
//_fireman hit the left edge of the screen, set the left bound position with no movement.
_player.position = ccp( _player.position.x, 319);
}
if ( _player.position.y > 320 ) {
//_fireman hit the right edge of the screen, set the right bound position with no movement.
_player.position = ccp(_player.position.x, 1 );
}
if ( _player.position.y < 1 && movement > 1 ) {
//_fireman is at the left edge of the screen and the device is tiled right. Move the _fireman!
_player.position = ccp(_player.position.x , _player.position.y+ movement);
}
if ( _player.position.y > 319 && movement < 0) {
//_fireman is at the right edge of the screen and the device is tiled left. Move the _fireman!
_player.position = ccp(_player.position.x , _player.position.y+ movement);
}
barracuda.position = ccp(barracuda.position.x,_player.position.y);
particles.position = ccp(_player.position.x-30, _player.position.y-10);
parteMagnet.position = ccp(_player.position.x, _player.position.y);
}
// Try this
-(id) init
{
if (self == [super init])
{
[[UIAccelerometer sharedAccelerometer] setUpdateInterval:1/60];
[[UIAccelerometer sharedAccelerometer] setDelegate:self];
[self scheduleUpdate];
}
return self;
}
- (void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration
{
float deceleration = 0.4f;
float sinsitivity = 6.0f;
float acelx = acceleration.y;
movement = movement * deceleration + acelx * sinsitivity;
float angleRadians = atanf((float)acceleration.y / (float)acceleration.x);
float angleDegrees = CC_RADIANS_TO_DEGREES(angleRadians);
if(angleDegrees<85 && angleDegrees >-85 )
{
_player.rotation = angleDegrees;
}
if([ShieldCover visible]==TRUE)
{
ShieldCover.rotation= angleDegrees;
}
}
- (void)update:(ccTime)delta
{
if ( _player.position.y > 0 && _player.position.y < 320)
{
_player.position = ccp(_player.position.x, _player.position.y + movement);
}
if ( _player.position.y < 0 )
{
_player.position = ccp( _player.position.x, 319);
}
if ( _player.position.y > 320 )
{
_player.position = ccp(_player.position.x, 1 );
}
if ( _player.position.y < 1 && movement > 1 )
{
_player.position = ccp(_player.position.x , _player.position.y+ movement);
}
if ( _player.position.y > 319 && movement < 0)
{
_player.position = ccp(_player.position.x , _player.position.y+ movement);
}
barracuda.position = ccp(barracuda.position.x,_player.position.y);
particles.position = ccp(_player.position.x-30, _player.position.y-10);
parteMagnet.position = ccp(_player.position.x, _player.position.y);
}

Cocos2D and iPhone's accelerometer

good afternoon!
Today I've started to develop a game and I got a trouble. So, first at all I would like to say that I have no experience developing games...
So, I've a CCSprite in the layer and I want to move this between the scene with a margin (top, bottom, left and right).
The minimum X should be -0.8 (in X-axis using the accelerometer) and the maximum 8. The minimun Y should be -1 (in Y-axis) or 0 in Z-axis and the maximum 0 (in Y-axis) or -1 (in Z-axis).
Ok, knowing this, I've tried to do this using the range between minimum and maximum space and accelerometer value but I haven't getting this working vertically (Y-axis on the iPhone). Then I got a done code in the web but this don't works when I want to move the object to back (the object only goes).
Did someone know how to fix this?
My actual code:
- (void)updatePosition:(ccTime)dt {
CGSize winSize = [[CCDirector sharedDirector] winSize];
float maxY = winSize.height - car.contentSize.height/2 - 20;
float minY = car.contentSize.height/2 + 20;
float newY = car.position.y + (carPointsPerSecY * dt);
newY = MIN(MAX(newY, minY), maxY);
float maxX = winSize.width - car.contentSize.width/2 - 40;
float minX = car.contentSize.width/2 + 40;
float newX = car.position.x + (carPointsPerSecX * dt);
newX = MIN(MAX(newX, minX), maxX);
car.position = ccp(newX, newY);
}
- (void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration {
float speedY = acceleration.y * 500;
if(carPointsPerSecY < speedY) {
carPointsPerSecY = MIN(carPointsPerSecY + 10, speedY);
} else {
carPointsPerSecY = MAX(carPointsPerSecY - 2, speedY);
}
float speedX = acceleration.x * 200;
if(carPointsPerSecX < speedX) {
carPointsPerSecX = MIN(carPointsPerSecX + 10, speedX);
} else {
carPointsPerSecX = MAX(carPointsPerSecX - 10, speedX);
}
NSLog(#"Acceleration: X (%f) - Y (%f) - Z (%f)", acceleration.x, acceleration.y, acceleration.z);
}
I'm not sure I completely understand what you want but I hope this helps you with your end goal:
-(void)updatePosition:(ccTime)dt {
CGSize size = [[CCDirector sharedDirector] winSize];
int margin = 20;
float speed = 15;
float maxX = size.width - car.contentSize.width / 2 - margin;
float minX = car.contentSize.width / 2 + margin;
float maxY = size.height - car.contentSize.height / 2 - margin;
float minY = car.contentSize.height / 2 + margin;
float newX = MIN(MAX(car.position.x + xAccel * speed, minX), maxX);
float newY = MIN(MAX(car.position.y + yAccel * speed, minY), maxY);
car.position = ccp(newX, newY);
}
//define in header: float xAccel, yAccel;
- (void)accelerometer: (UIAccelerometer *)accelerometer didAccelerate: (UIAcceleration *)acceleration {
yAccel = acceleration.x;
xAccel = -acceleration.y;
}

cocos2d: How do I Control a scrolling map

I made my map to scroll automatically however I would like to know how can I slow down the scrolling before the map reaches the end and when it does I would like the map to stop scrolling. I want to know how to do this because my game is about the player trying to shoot the enemy before he reaches the end of the map where there is shelter for him to hide. I would like that before the enemy reaches the shelter have the scrolling slow down and when the enemy reaches the shelter I would like the map to stop scrolling.
Here is the code:
#implementation GameplayScrollingLayer
// Scrolling with TileMap Layers inside of a Parallax Node
-(void)addScrollingBackgroundWithTileMapInsideParallax {
CGSize screenSize = [[CCDirector sharedDirector] winSize];
CGSize levelSize = [[GameManager sharedGameManager]
getDimensionsOfCurrentScene];
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
tileMapNode = [CCTMXTiledMap
tiledMapWithTMXFile:#"Level2TileMap.tmx"];
} else {
tileMapNode = [CCTMXTiledMap
tiledMapWithTMXFile:#"Level2TileMapiPhone.tmx"];
}
CCTMXLayer *groundLayer = [tileMapNode layerNamed:#"GroundLayer"];
CCTMXLayer *rockColumnsLayer = [tileMapNode
layerNamed:#"RockColumnsLayer"];
CCTMXLayer *rockBoulderLayer = [tileMapNode
layerNamed:#"RockBoulderLayer"];
parallaxNode = [CCParallaxNode node];
[parallaxNode setPosition:
ccp(levelSize.width/2,screenSize.height/2)];
float xOffset = 0.0f;
xOffset = (levelSize.width/2);
[groundLayer retain];
[groundLayer removeFromParentAndCleanup:NO];
[groundLayer setAnchorPoint:CGPointMake(0.5f, 0.5f)];
[parallaxNode addChild:groundLayer z:30 parallaxRatio:ccp(1,1)
positionOffset:ccp(0,0)];
[groundLayer release];
xOffset = (levelSize.width/2) * 0.8f;
[rockColumnsLayer retain];
[rockColumnsLayer removeFromParentAndCleanup:NO];
[rockColumnsLayer setAnchorPoint:CGPointMake(0.5f, 0.5f)];
[parallaxNode addChild:rockColumnsLayer z:20
parallaxRatio:ccp(0.2,1)
positionOffset:ccp(xOffset, 0.0f)];
[rockColumnsLayer release];
xOffset = (levelSize.width/2) * 0.3f;
[rockBoulderLayer retain];
[rockBoulderLayer removeFromParentAndCleanup:NO];
[rockBoulderLayer setAnchorPoint:CGPointMake(0.5f, 0.5f)];
[parallaxNode addChild:rockBoulderLayer z:30
parallaxRatio:ccp(0.7,1)
positionOffset:ccp(xOffset, 0.0f)];
[rockBoulderLayer release];
[self addChild:parallaxNode z:1];
}
// Accelerometer
-(void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration { //new
shipSpeedY = 9.0 + acceleration.x*20;
shipSpeedX = -acceleration.y*20;
}
// Updating ship based on accelerometer
-(void)updateShip {
float maxY = winSize.height - ship.contentSize.height/2;
float minY = ship.contentSize.height/2;
float newY = ship.position.y + shipSpeedY;
newY = MIN(MAX(newY, minY), maxY);
float maxX = winSize.width - ship.contentSize.width/2;
float minX = ship.contentSize.width/2;
float newX = ship.position.x + shipSpeedX;
newX = MIN(MAX(newX, minX), maxX);
ship.position = ccp(newX, newY);
}
// Making background scroll automatically
-(void)update:(ccTime)dt {
[self updateShip];
CGPoint backgroundScrollVel = ccp(-100, 0);
parallaxNode.position = ccpAdd(parallaxNode.position, ccpMult(backgroundScrollVel, dt));
}
// Adding sprite ship
-(id)init {
self = [super init];
if (self != nil) {
winSize = [CCDirector sharedDirector].winSize;
ship=[CCSprite spriteWithFile:#"ship.png"];
ship.position=ccp(60,160);
[self addChild:ship z:100];
self.isAccelerometerEnabled = YES; //new
[self scheduleUpdate]; //new
[self addScrollingBackgroundWithTileMapInsideParallax];
}
return self;
}
- (void) dealloc
{
[super dealloc];
}
#end