UIAccelerometer issue with landscape mode - ios

I am using UIAccelerometer in my game and it is working fine in portrait mode but not working properly in landscape mode.
Can some one fix the issue in my code
I am putting my code as below:
#import "GameLayer.h"
#implementation GameLayer
+(id)scene
{
CCScene *scene = [CCScene node];
CCLayer *layer = [GameLayer node];
[scene addChild:layer];
return scene;
}
- (id)init
{
if ((self = [super init]))
{
self.isAccelerometerEnabled = YES;
player = [CCSprite spriteWithFile:#"spaceship.png"];
[self addChild:player];
CGSize screenSize = [CCDirector sharedDirector].winSize;
player.position = CGPointMake(screenSize.width / 2, screenSize.height / 2);
[self scheduleUpdate];
}
return self;
}
- (void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration
{
float deceleration = 1.0f;
float maxVelocity = 50;
playerVelocity.x = playerVelocity.x * deceleration + acceleration.x;
playerVelocity.y = playerVelocity.y * deceleration + acceleration.y;
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 imageHeightHalved = player.texture.contentSize.height * 0.5f;
float leftBorderLimit = imageWidthHalved;
float rightBorderLimit = screenSize.width - imageWidthHalved;
float topBorderLimit = imageHeightHalved;
float bottomBorderLimit = screenSize.height - imageHeightHalved;
if (pos.x < leftBorderLimit)
{
pos.x = leftBorderLimit;
playerVelocity.x = 0;
}
else if (pos.x > rightBorderLimit)
{
pos.x = rightBorderLimit;
playerVelocity.x = 0;
}
if (pos.y < topBorderLimit)
{
pos.y = topBorderLimit;
playerVelocity.y = 0; }
else if (pos.y > bottomBorderLimit)
{
pos.y = bottomBorderLimit;
playerVelocity.y = 0;
}
player.position = pos;
}
#end

The accelerometer axes do not change with change in orientation. You will have to handle the different orientation cases in your - (void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration method by detecting the current device orientation.

Related

Sprite is "lagging" with accelerometer

The sprite rotate and move based on accelerometer's x axis. When the phone tilts further the sprite rotate and move faster. It's all working, but not smooth. When the sprite is moving slowly it is lagging.
I tried controlling the speed based on accelerometer's x axis.
if (data.acceleration.x >= 0.09) {
angle = 0.4 * data.acceleration.x;
}
if (data.acceleration.x >= 0.20) {
angle = 0.6 * data.acceleration.x;
}
if (data.acceleration.x <= -0.09) {
angle = 0.4 * data.acceleration.x;
}
if (data.acceleration.x <= -0.20) {
angle = 0.6 * data.acceleration.x;
}
if (data.acceleration.x <= 0.09 & data.acceleration.x >= -0.09) {
angle = 0;
}
But it does not solve the issue. Does somebody knows how to stop the lagging?
Code:
#import "GameScene.h"
static int kPlayerSpeed = 20.0;
#implementation GameScene
{
SKSpriteNode *_character;
// cmmotionmanager
float _destY;
float _currentY;
float _currentX;
CMAccelerometerData *_lastReading;
BOOL _shouldMoveToRight;
BOOL _shouldMoveToLeft;
}
-(void)didMoveToView:(SKView *)view {
/* Setup your scene here */
// background settings
self.backgroundColor = [SKColor whiteColor];
// setup charachter
_character = [SKSpriteNode spriteNodeWithImageNamed:#"Monster_final_01"];
_character.position = CGPointMake(self.size.width * 0.5, self.size.height * 0.2);
_character.anchorPoint = CGPointMake(0.5, 0.5);
_character.xScale = 0.3;
_character.yScale = 0.3;
[self addChild:_character];
// setup motionmanager
self.manager = [[CMMotionManager alloc] init];
[self.manager setAccelerometerUpdateInterval:1.0/30.0];
[self.manager startAccelerometerUpdates];
}
-(void)acceleratorUpdates
{
CMAccelerometerData *data = self.manager.accelerometerData;
if(_lastReading == nil)
{
_lastReading = data;
}
BOOL threshhold = (fabs(_lastReading.acceleration.x - data.acceleration.x) > 0.01);
//if the absolute of acceleration is < the absolute of last, then we changed direction
BOOL changeDir = (fabs(data.acceleration.x) < fabs(_lastReading.acceleration.x));
//if changing direction is above our threshhold, or we didnt change direction
BOOL _aboveThreshold = ( threshhold && changeDir ) || (!changeDir);
CGFloat angle = 0;
CGFloat _destX = 0.0;
if (data.acceleration.x >= 0.09) {
angle = 0.4 * data.acceleration.x;
}
if (data.acceleration.x >= 0.20) {
angle = 0.6 * data.acceleration.x;
}
if (data.acceleration.x <= -0.09) {
angle = 0.4 * data.acceleration.x;
}
if (data.acceleration.x <= -0.20) {
angle = 0.6 * data.acceleration.x;
}
if (data.acceleration.x <= 0.09 & data.acceleration.x >= -0.09) {
angle = 0;
}
if(fabs(data.acceleration.x) > 0.25) { // tilting the device to the right
_destX = -(data.acceleration.x * kPlayerSpeed);
}
[_character removeAllActions];
SKAction *moveAction = [SKAction moveByX:_destX y:0 duration:0];
[_character runAction:moveAction];
_character.position = CGPointMake(_character.position.x + _destX, _character.position.y);
if(_aboveThreshold)
{
SKAction *rotateAction = [SKAction rotateByAngle:angle duration:0];
[_character runAction:rotateAction];
_lastReading = data;
}
NSLog(#"_lastReading.acceleration.x = %f & data.acceleration.x = %f", _lastReading.acceleration.x, data.acceleration.x);
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
/* Called when a touch begins */
for (UITouch *touch in touches) {
CGPoint location = [touch locationInNode:self];
}
}
-(void)update:(CFTimeInterval)currentTime {
/* Called before each frame is rendered */
[self acceleratorUpdates];
}

SKPhysics: Made a rope, why does it break?

I've been experimenting with sprite kit a little bit, building a prototype for an idea I have. I've been connecting a string of physics bodies together using an SKPhysicsJointPin, to make a rope (actually more like a bike chain, but it's good enough). Also in the scene are a number of balls, and I can drop them when I tap them. This leads to the following:
However, when I drop more balls, the chain seems to be unable to handle it, and 'breaks':
Here is a movie showing the phenomenon
What's happening? The documentation never suggests SKPhysicsJointPin has a limited maximum strength or elasticity or similar. Is this a 'bug' in sprite kit, or am I using the wrong approach?
I faced a similar elasticity bug with a rope simulation and could finally come up with a workaround.
Here's my rope interface:
#import <SpriteKit/SpriteKit.h>
#interface ALRope : NSObject
#property(nonatomic, readonly) NSArray *ropeRings;
#property(nonatomic) int ringCount;
#property(nonatomic) CGFloat ringScale;
#property(nonatomic) CGFloat ringsDistance;
#property(nonatomic) CGFloat jointsFrictionTorque;
#property(nonatomic) CGFloat ringsZPosition;
#property(nonatomic) CGPoint startRingPosition;
#property(nonatomic) CGFloat ringFriction;
#property(nonatomic) CGFloat ringRestitution;
#property(nonatomic) CGFloat ringMass;
#property(nonatomic) BOOL shouldEnableJointsAngleLimits;
#property(nonatomic) CGFloat jointsLowerAngleLimit;
#property(nonatomic) CGFloat jointsUpperAngleLimit;
-(instancetype)initWithRingTexture:(SKTexture *)ringTexture;
-(void)buildRopeWithScene:(SKScene *)scene;
-(void)adjustRingPositions;
-(SKSpriteNode *)startRing;
-(SKSpriteNode *)lastRing;
#end
Rope Implementation:
#import "ALRope.h"
#implementation ALRope
{
SKTexture *_ringTexture;
NSMutableArray *_ropeRings;
}
static CGFloat const RINGS_DISTANCE_DEFAULT = 0;
static CGFloat const JOINTS_FRICTION_TORQUE_DEFAULT = 0;
static CGFloat const RING_SCALE_DEFAULT = 1;
static int const RING_COUNT_DEFAULT = 30;
static CGFloat const RINGS_Z_POSITION_DEFAULT = 1;
static BOOL const SHOULD_ENABLE_JOINTS_ANGLE_LIMITS_DEFAULT = NO;
static CGFloat const JOINT_LOWER_ANGLE_LIMIT_DEFAULT = -M_PI / 3;
static CGFloat const JOINT_UPPER_ANGLE_LIMIT_DEFAULT = M_PI / 3;
static CGFloat const RING_FRICTION_DEFAULT = 0;
static CGFloat const RING_RESTITUTION_DEFAULT = 0;
static CGFloat const RING_MASS_DEFAULT = -1;
-(instancetype)initWithRingTexture:(SKTexture *)ringTexture
{
if(self = [super init]) {
_ringTexture = ringTexture;
//apply defaults
_startRingPosition = CGPointMake(0, 0);
_ringsDistance = RINGS_DISTANCE_DEFAULT;
_jointsFrictionTorque = JOINTS_FRICTION_TORQUE_DEFAULT;
_ringScale = RING_SCALE_DEFAULT;
_ringCount = RING_COUNT_DEFAULT;
_ringsZPosition = RINGS_Z_POSITION_DEFAULT;
_shouldEnableJointsAngleLimits = SHOULD_ENABLE_JOINTS_ANGLE_LIMITS_DEFAULT;
_jointsLowerAngleLimit = JOINT_LOWER_ANGLE_LIMIT_DEFAULT;
_jointsUpperAngleLimit = JOINT_UPPER_ANGLE_LIMIT_DEFAULT;
_ringFriction = RING_FRICTION_DEFAULT;
_ringRestitution = RING_RESTITUTION_DEFAULT;
_ringMass = RING_MASS_DEFAULT;
}
return self;
}
-(void)buildRopeWithScene:(SKScene *)scene
{
_ropeRings = [NSMutableArray new];
SKSpriteNode *firstRing = [self addRopeRingWithPosition:_startRingPosition underScene:scene];
SKSpriteNode *lastRing = firstRing;
CGPoint position;
for (int i = 1; i < _ringCount; i++) {
position = CGPointMake(lastRing.position.x, lastRing.position.y - lastRing.size.height - _ringsDistance);
lastRing = [self addRopeRingWithPosition:position underScene:scene];
}
[self addJointsWithScene:scene];
}
-(SKSpriteNode *)addRopeRingWithPosition:(CGPoint)position underScene:(SKScene *)scene
{
SKSpriteNode *ring = [SKSpriteNode spriteNodeWithTexture:_ringTexture];
ring.xScale = ring.yScale = _ringScale;
ring.position = position;
ring.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:ring.size.height / 2];
ring.physicsBody.allowsRotation = YES;
ring.physicsBody.friction = _ringFriction;
ring.physicsBody.restitution = _ringRestitution;
if(_ringMass > 0) {
ring.physicsBody.mass = _ringMass;
}
[scene addChild:ring];
[_ropeRings addObject:ring];
return ring;
}
-(void)addJointsWithScene:(SKScene *)scene
{
for (int i = 1; i < _ropeRings.count; i++) {
SKSpriteNode *nodeA = [_ropeRings objectAtIndex:i-1];
SKSpriteNode *nodeB = [_ropeRings objectAtIndex:i];
SKPhysicsJointPin *joint = [SKPhysicsJointPin jointWithBodyA:nodeA.physicsBody
bodyB:nodeB.physicsBody
anchor:CGPointMake(nodeA.position.x,
nodeA.position.y - (nodeA.size.height + _ringsDistance) / 2)];
joint.frictionTorque = _jointsFrictionTorque;
joint.shouldEnableLimits = _shouldEnableJointsAngleLimits;
if(_shouldEnableJointsAngleLimits) {
joint.lowerAngleLimit = _jointsLowerAngleLimit;
joint.upperAngleLimit = _jointsUpperAngleLimit;
}
[scene.physicsWorld addJoint:joint];
}
}
//workaround for elastic effect should be called from didSimulatePhysics
-(void)adjustRingPositions
{
//based on zRotations of all rings and the position of start ring adjust the rest of the rings positions starting from top to bottom
for (int i = 1; i < _ropeRings.count; i++) {
SKSpriteNode *nodeA = [_ropeRings objectAtIndex:i-1];
SKSpriteNode *nodeB = [_ropeRings objectAtIndex:i];
CGFloat thetaA = nodeA.zRotation - M_PI / 2,
thetaB = nodeB.zRotation + M_PI / 2,
jointRadius = (_ringsDistance + nodeA.size.height) / 2,
xJoint = jointRadius * cosf(thetaA) + nodeA.position.x,
yJoint = jointRadius * sinf(thetaA) + nodeA.position.y,
theta = thetaB - M_PI,
xB = jointRadius * cosf(theta) + xJoint,
yB = jointRadius * sinf(theta) + yJoint;
nodeB.position = CGPointMake(xB, yB);
}
}
-(SKSpriteNode *)startRing
{
return _ropeRings[0];
}
-(SKSpriteNode *)lastRing
{
return [_ropeRings lastObject];
}
#end
Scene code to showcase how to use the Rope:
#import "ALRopeDemoScene.h"
#import "ALRope.h"
#implementation ALRopeDemoScene
{
__weak SKSpriteNode *_branch;
CGPoint _touchLastPosition;
BOOL _branchIsMoving;
ALRope *_rope;
}
-(id)initWithSize:(CGSize)size {
if (self = [super initWithSize:size]) {
/* Setup your scene here */
self.backgroundColor = [SKColor colorWithRed:0.2 green:0.5 blue:0.6 alpha:1.0];
[self buildScene];
}
return self;
}
-(void) buildScene {
SKSpriteNode *branch = [SKSpriteNode spriteNodeWithImageNamed:#"Branch"];
_branch = branch;
branch.position = CGPointMake(CGRectGetMaxX(self.frame) - branch.size.width / 2,
CGRectGetMidY(self.frame) + 200);
branch.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:CGSizeMake(2, 10)];
branch.physicsBody.dynamic = NO;
[self addChild:branch];
_rope = [[ALRope alloc] initWithRingTexture:[SKTexture textureWithImageNamed:#"rope_ring"]];
//configure rope params if needed
// _rope.ringCount = ...;//default is 30
// _rope.ringScale = ...;//default is 1
// _rope.ringsDistance = ...;//default is 0
// _rope.jointsFrictionTorque = ...;//default is 0
// _rope.ringsZPosition = ...;//default is 1
// _rope.ringFriction = ...;//default is 0
// _rope.ringRestitution = ...;//default is 0
// _rope.ringMass = ...;//ignored unless mass > 0; default -1
// _rope.shouldEnableJointsAngleLimits = ...;//default is NO
// _rope.jointsLowerAngleLimit = ...;//default is -M_PI/3
// _rope.jointsUpperAngleLimit = ...;//default is M_PI/3
_rope.startRingPosition = CGPointMake(branch.position.x - 100, branch.position.y);//default is (0, 0)
[_rope buildRopeWithScene:self];
//attach rope to branch
SKSpriteNode *startRing = [_rope startRing];
CGPoint jointAnchor = CGPointMake(startRing.position.x, startRing.position.y + startRing.size.height / 2);
SKPhysicsJointPin *joint = [SKPhysicsJointPin jointWithBodyA:branch.physicsBody bodyB:startRing.physicsBody anchor:jointAnchor];
[self.physicsWorld addJoint:joint];
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
CGPoint location = [touch locationInNode:self];
if(CGRectContainsPoint(_branch.frame, location)) {
_branchIsMoving = YES;
_touchLastPosition = location;
}
}
-(void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
_branchIsMoving = NO;
}
-(void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{
if(_branchIsMoving) {
UITouch *touch = [touches anyObject];
CGPoint location = [touch locationInNode:self],
branchCurrentPosition = _branch.position;
CGFloat dx = location.x - _touchLastPosition.x,
dy = location.y - _touchLastPosition.y;
_branch.position = CGPointMake(branchCurrentPosition.x + dx, branchCurrentPosition.y + dy);
_touchLastPosition = location;
}
}
-(void)didSimulatePhysics
{
//workaround for elastic effect
[_rope adjustRingPositions];
}
#end
Notice the [rope adjustRingPositions] call from [scene didSimulatePhysics]. That was the actual workaround for the elastic bug.
Complete demo code is here. I hope this helps!

Setting CPU Difficulty for Pong

Second time on here hoping that someone can guide me in the right direction.
I'm trying to implement a Pong game within an app for iOS devices (iPhone/iPod/iPad) and it works just fine, except for the fact that I can't beat the CPU, let alone score a point. Here's the implementation .m code:
#import "BTM_pongGame.h"
#import <QuartzCore/QuartzCore.h>
#define STEP_DURATION 0.05
#define RESET_BALL_ANIMATION_DURATION 0.5f
#define MARGIN_WHERE_BALL_IS_LEAVING 40
//#define CPU_SKILL 20
#interface BTM_pongGame ()
#end
#implementation BTM_pongGame
#synthesize cpuSkill, ballShape;
- (void)viewDidLoad
{
[super viewDidLoad];
cpuSkill = [BT_strings getJsonPropertyValue:self.screenData.jsonVars nameOfProperty:#"cpuSkill" defaultValue:#"20"];
ballShape = [BT_strings getJsonPropertyValue:self.screenData.jsonVars nameOfProperty:#"ballShape" defaultValue:#"1"];
if ([ballShape isEqual: #"1"]) {
self.ball.layer.cornerRadius = self.ball.frame.size.width / 2;
} else {
//self.ball.layer.cornerRadius = self.ball.frame.size.width / 2;
}
}
- (void) wordsPerLineInfoShowAlert {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Choose Game"
message:#"Multiplayer or Single Player? You decide! Choose below."
delegate:self
cancelButtonTitle:#"Single Player"
otherButtonTitles:#"Go Back",#"Multi Player", nil];
[alert show];
}
- (void)alertView: (UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
NSString *title = [alertView buttonTitleAtIndex:buttonIndex];
if([title isEqualToString:#"Single Player"]) {
[self resetPlayerScoreLabels];
[self updatePlayerScoreLabels];
self.mode = kGameSinglePlayer;
[self moveComputerPaddle];
//Disable panning of computer paddle
[self.playerOne.superview setGestureRecognizers:#[]];
[self resetBoardForNewRound];
} else if ([title isEqualToString:#"Multi Player"]) {
[self resetPlayerScoreLabels];
[self updatePlayerScoreLabels];
self.mode = kGameMultiPlayer;
[self resetBoardForNewRound];
} else if ( [title isEqualToString:#"Go Back"]){
[self navLeftTap];
}
}
// thanks to MrsVanBeveren for coding the reset score stuff
-(void)resetPlayerScoreLabels
{
playerOneScore = 0;
playerTwoScore = 0;
}
-(void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
[self wordsPerLineInfoShowAlert];
[self startGameTimer];
}
-(void)viewDidDisappear:(BOOL)animated
{
[super viewDidDisappear:animated];
[_gameTimer invalidate];
}
-(void)quitPressed:(id)sender
{
[self dismissViewControllerAnimated:YES completion:nil];
}
-(void)startGameTimer
{
[_gameTimer invalidate];
_gameTimer = [NSTimer scheduledTimerWithTimeInterval:STEP_DURATION target:self selector:#selector(step:) userInfo:nil repeats:YES];
}
#pragma mark Game setup
/*
* Some maths to calculate a new starting direction
* By choosing mid left/right part of the unit circle
* we avoid getting straight up/down directions
*/
-(void)resetBallDirection
{
float randomUnity = arc4random_uniform(100)/100.0;
int horizontalDirection = (arc4random() % 2 ? 1 : -1);
float angle = M_PI_4 + randomUnity * M_PI_2;
float direction = horizontalDirection * angle;
dirX = sin(direction);
dirY = cos(direction);
}
-(void)resetBoardForNewRound
{
speed = self.view.frame.size.width / 50.0;
[self resetBallDirection];
[_gameTimer invalidate];
[UIView animateWithDuration:RESET_BALL_ANIMATION_DURATION animations:^{
self.ball.center = CGPointMake(self.view.bounds.size.width / 2.0, self.view.bounds.size.height / 2.0);
} completion:^(BOOL finished){
[self startGameTimer];
}];
[self enlargeAnimation:self.ball];
}
-(void)updatePlayerScoreLabels
{
self.playerOneScoreLabel.text = [NSString stringWithFormat:#"%d",playerOneScore];
self.playerTwoScoreLabel.text = [NSString stringWithFormat:#"%d",playerTwoScore];
}
#pragma mark Paddle handling
- (IBAction)paddlePanned:(UIPanGestureRecognizer*)recognizer {
UIView *paddleWrapper = recognizer.view;
UIView *paddle = [[paddleWrapper subviews] lastObject];
switch([recognizer state]) {
case UIGestureRecognizerStateBegan: {
paddle.backgroundColor = UIColor.whiteColor;
}
break;
case UIGestureRecognizerStateChanged: {
CGPoint position = [recognizer locationInView:self.view];
CGFloat haldPaddleHeight = paddleWrapper.frame.size.height / 2.0;
CGPoint newCenter = paddleWrapper.center;
newCenter.y = position.y;
newCenter.y = MAX(haldPaddleHeight, newCenter.y);
newCenter.y = MIN(self.view.bounds.size.height - haldPaddleHeight, newCenter.y);
paddleWrapper.center = newCenter;
}
break;
case UIGestureRecognizerStateEnded: {
paddle.backgroundColor = UIColor.grayColor;
}
break;
default:
break;
}
}
#pragma mark Game loop
/*
* Game loop
* - Moves the ball and checks for obstacles
*/
- (void)step:(NSTimer*)timer
{
speed += 0.05;
[self checkForBallLevingSide];
CGPoint newCenter = self.ball.center;
CGFloat ballRadius = self.ball.frame.size.height / 2.0;
newCenter.x += dirX * speed;
newCenter.y += dirY * speed;
CGFloat upperEdge = ballRadius;
CGFloat bottomEdge = self.view.bounds.size.height - ballRadius;
// Bounce ball of top/bottom walls
if (newCenter.y <= upperEdge) {
dirY = ABS(dirY);
newCenter.y = upperEdge;
} else if (newCenter.y >= bottomEdge) {
dirY = -ABS(dirY);
newCenter.y = bottomEdge;
}
[UIView animateWithDuration:STEP_DURATION animations:^{
self.ball.center = newCenter;
}];
}
-(BOOL)didBallHitPaddle:(UIView *)paddle withinLimit:(CGFloat)limit
{
if (CGRectIntersectsRect(paddle.frame, self.ball.frame)){
[self deflectBallFromPaddle:paddle];
CGRect ballFrame = self.ball.frame;
ballFrame.origin.x = limit;
self.ball.frame = ballFrame;
return YES;
} else
return NO;
}
-(void)checkForBallLevingSide
{
float limitLeft = MARGIN_WHERE_BALL_IS_LEAVING;
float limitRight = self.view.bounds.size.width - self.ball.frame.size.width - MARGIN_WHERE_BALL_IS_LEAVING;
CGRect ballFrame = self.ball.frame;
CGFloat ballX = ballFrame.origin.x;
if (ballX < limitLeft) {
if (![self didBallHitPaddle:self.playerOne.superview withinLimit:limitLeft])
[self playerDidMiss:kPlayerOne];
}else if (ballX > limitRight) {
if (![self didBallHitPaddle:self.playerTwo.superview withinLimit:limitRight])
[self playerDidMiss:kPlayerTwo];
}
}
/*
* Calculates new dirX and dirY after the bounce.
* The longer from the paddle's middle the bigger the result angle gets. (Pong style)
*/
-(void)deflectBallFromPaddle:(UIView *)paddle
{
dirX *= -1;
CGFloat diff = self.ball.center.y - paddle.center.y;
float p = diff / paddle.frame.size.height * 2.0f;
dirY += p * 0.5;
}
-(void)playerDidMiss:(kPlayer)player
{
if (player == kPlayerOne) {
playerTwoScore++;
[self victoryShake:self.playerTwo];
[self enlargeAnimation:self.playerTwoScoreLabel];
}
else if (player == kPlayerTwo) {
playerOneScore++;
[self victoryShake:self.playerOne];
[self enlargeAnimation:self.playerOneScoreLabel];
}
[self resetBoardForNewRound];
[self updatePlayerScoreLabels];
}
-(void)moveComputerPaddle
{
UIView *paddle = self.playerOne.superview;
CGPoint cpuCenter = paddle.center;
CGFloat diff = self.ball.center.y - paddle.center.y;
CGFloat movement = MIN((int)cpuSkill, ABS(diff));
movement *= diff > 0 ? 1 : -1;
cpuCenter.y += movement;
[UIView animateWithDuration:0.1 animations:^{
self.playerOne.superview.center = cpuCenter;
} completion:^(BOOL b) {
[self moveComputerPaddle];
}];
}
#pragma mark Animation
-(void)victoryShake:(UIView *)view
{
CAKeyframeAnimation * anim = [ CAKeyframeAnimation animationWithKeyPath:#"transform" ] ;
anim.values = [ NSArray arrayWithObjects:
[ NSValue valueWithCATransform3D:CATransform3DMakeTranslation(0.0f, -20.0f, 0.0f) ],
[ NSValue valueWithCATransform3D:CATransform3DMakeTranslation(0.0f, 20.0f, 0.0f) ],
nil ] ;
anim.autoreverses = YES ;
anim.repeatCount = 4.0f ;
anim.duration = 0.07f ;
[view.layer addAnimation:anim forKey:nil];
}
-(void)enlargeAnimation:(UIView *)view
{
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:#"transform"];
animation.fromValue = [NSValue valueWithCATransform3D:CATransform3DMakeScale(1.0, 1.0, 1.0)];
animation.toValue = [NSValue valueWithCATransform3D:CATransform3DMakeScale(3.0, 3.0, 1.0)];
[animation setDuration:RESET_BALL_ANIMATION_DURATION * 0.5];
animation.repeatCount = 1.0f ;
[animation setAutoreverses:YES];
[view.layer addAnimation:animation forKey:nil];
}
#end
I've simply tried changing the number where it states #define CPU_SkILL and again #"cpuSkill" defaultValue:#"20"];, but I've had no luck with changing the number in any direction.
Any ideas?
Thank you in advance.
The cpuSkill variable controls the movement of the CPU-controlled paddle:
CGFloat movement = MIN((int)cpuSkill, ABS(diff));
So maybe the cpuSkill is higher than intended in every situation. Try much lower values or make some random little adjustment to movement after the calculation.
Also, you should ABS() the cpuSkill to avoid perfect moving when negative moving.

"How To Make a Tile-Based Game with Cocos2D 2.X" Make this tutorial with cocos2d V3

I have a small problem. In this tutorial How To Make a Tile-Based Game with Cocos2D 2.X used cocos2d V2.0, I wanna make this in cocos2d V3.0. So, it doesn't work! Thanks! (I don't speak english)
I think problem in this line - self.position = viewPoint;
#property (strong) CCTiledMap *tileMap;
#property (strong) CCTiledMapLayer *background;
#property (strong) CCSprite *player;
- (id)init
{
// Apple recommend assigning self with supers return value
self = [super init];
if (!self) return(nil);
// Enable touch handling on scene node
self.userInteractionEnabled = YES;
self.tileMap = [CCTiledMap tiledMapWithFile:#"TileMap.tmx"];
self.background = [_tileMap layerNamed:#"Background"];
[self addChild:_tileMap z:-1];
CCTiledMapObjectGroup *objectGroup = [_tileMap objectGroupNamed:#"Objects"];
NSAssert(objectGroup != nil, #"tile map has no objects object layer");
NSDictionary *spawnPoint = [objectGroup objectNamed:#"SpawnPoint"];
int x = [spawnPoint[#"x"] integerValue];
int y = [spawnPoint[#"y"] integerValue];
_player = [CCSprite spriteWithImageNamed:#"Player.png"];
_player.position = ccp(x,y);
[self addChild:_player];
[self setViewPointCenter:_player.position];
// done
return self;
}
- (void)setViewPointCenter:(CGPoint) position {
CGSize winSize = [CCDirector sharedDirector].viewSize;
int x = MAX(position.x, winSize.width/2);
int y = MAX(position.y, winSize.height/2);
x = MIN(x, (_tileMap.mapSize.width * _tileMap.tileSize.width) - winSize.width / 2);
y = MIN(y, (_tileMap.mapSize.height * _tileMap.tileSize.height) - winSize.height/2);
CGPoint actualPosition = ccp(x, y);
CGPoint centerOfView = ccp(winSize.width/2, winSize.height/2);
CGPoint viewPoint = ccpSub(centerOfView, actualPosition);
self.position = viewPoint;
}
-(void)touchBegan:(UITouch *)touch withEvent:(UIEvent *)event
{
CGPoint touchLocation = [touch locationInView:touch.view];
touchLocation = [[CCDirector sharedDirector] convertToGL:touchLocation];
touchLocation = [self convertToNodeSpace:touchLocation];
CGPoint playerPos = _player.position;
CGPoint diff = ccpSub(touchLocation, playerPos);
if ( abs(diff.x) > abs(diff.y) ) {
if (diff.x > 0) {
playerPos.x += _tileMap.tileSize.width;
} else {
playerPos.x -= _tileMap.tileSize.width;
}
} else {
if (diff.y > 0) {
playerPos.y += _tileMap.tileSize.height;
} else {
playerPos.y -= _tileMap.tileSize.height;
}
}
CCLOG(#"playerPos %#",CGPointCreateDictionaryRepresentation(playerPos));
// safety check on the bounds of the map
if (playerPos.x <= (_tileMap.mapSize.width * _tileMap.tileSize.width) &&
playerPos.y <= (_tileMap.mapSize.height * _tileMap.tileSize.height) &&
playerPos.y >= 0 &&
playerPos.x >= 0 )
{
[self setPlayerPosition:playerPos];
}
[self setViewPointCenter:_player.position];
NSLog(#"%#", NSStringFromCGPoint(touchLocation));
}
-(void)setPlayerPosition:(CGPoint)position {
_player.position = position;
}
The problem is that the area of the user interaction is by default bound to the contentSize of the scene (screen size).
When calling your setViewPointCenter method, you are moving the scene position out of this area where the touch event is not handled.
You have to extend this area of the contentSize of the tile map like that :
[self setContentSize:[_tileMap contentSize]];
self.userInteractionEnabled = YES;

Sprite wont spawn [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 9 years ago.
Improve this question
This code spawns a monster, but no enemy.
I expect an enemy to be spawned, why doesn't it?
#import "MyScene.h"
#import "GameOverScene.h"
static const uint32_t projectileCategory = 0x1 << 0;
static const uint32_t monsterCategory = 0x1 << 1;
static const uint32_t enemyCategory = 0x1 << 1;
// 1
#interface MyScene () <SKPhysicsContactDelegate>
#property (nonatomic) SKSpriteNode * player;
#property (nonatomic) NSTimeInterval lastSpawnTimeInterval;
#property (nonatomic) NSTimeInterval lastUpdateTimeInterval;
#property (nonatomic) int monstersDestroyed;
#property (nonatomic) int enemysDestroyed;
#end
static inline CGPoint rwAdd(CGPoint a, CGPoint b) {
return CGPointMake(a.x + b.x, a.y + b.y);
}
static inline CGPoint rwSub(CGPoint a, CGPoint b) {
return CGPointMake(a.x - b.x, a.y - b.y);
}
static inline CGPoint rwMult(CGPoint a, float b) {
return CGPointMake(a.x * b, a.y * b);
}
static inline float rwLength(CGPoint a) {
return sqrtf(a.x * a.x + a.y * a.y);
}
// Makes a vector have a length of 1
static inline CGPoint rwNormalize(CGPoint a) {
float length = rwLength(a);
return CGPointMake(a.x / length, a.y / length);
}
#implementation MyScene
-(id)initWithSize:(CGSize)size {
if (self = [super initWithSize:size]) {
// 2
NSLog(#"Size: %#", NSStringFromCGSize(size));
// 3
self.backgroundColor = [SKColor colorWithRed:1.0 green:1.0 blue:1.0 alpha:1.0];
// 4
self.player = [SKSpriteNode spriteNodeWithImageNamed:#"player"];
self.player.position = CGPointMake(self.player.size.width/2, self.frame.size.height/2);
[self addChild:self.player];
self.physicsWorld.gravity = CGVectorMake(0,0);
self.physicsWorld.contactDelegate = self;
}
return self;
}
-(void)addMonster {
// Create sprite
SKSpriteNode * monster = [SKSpriteNode spriteNodeWithImageNamed:#"monster"];
monster.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:monster.size]; // 1
monster.physicsBody.dynamic = YES; // 2
monster.physicsBody.categoryBitMask = monsterCategory; // 3
monster.physicsBody.contactTestBitMask = projectileCategory; // 4
monster.physicsBody.collisionBitMask = 0; // 5
// Determine where to spawn the monster along the Y axis
int minY = monster.size.height / 2;
int maxY = self.frame.size.height - monster.size.height / 2;
int rangeY = maxY - minY;
int actualY = (arc4random() % rangeY) + minY;
// Create the monster slightly off-screen along the right edge,
// and along a random position along the Y axis as calculated above
monster.position = CGPointMake(self.frame.size.width + monster.size.width/2, actualY);
[self addChild:monster];
// Determine speed of the monster
int minDuration = 2.0;
int maxDuration = 4.0;
int rangeDuration = maxDuration - minDuration;
int actualDuration = (arc4random() % rangeDuration) + minDuration;
// Create the actions
SKAction * actionMove = [SKAction moveTo:CGPointMake(-monster.size.width/2, actualY) duration:actualDuration];
SKAction * actionMoveDone = [SKAction removeFromParent];
SKAction * loseAction = [SKAction runBlock:^{
SKTransition *reveal = [SKTransition flipHorizontalWithDuration:0.5];
SKScene * gameOverScene = [[GameOverScene alloc] initWithSize:self.size won:NO];
[self.view presentScene:gameOverScene transition: reveal];
}];
[monster runAction:[SKAction sequence:#[actionMove, loseAction, actionMoveDone]]];
}
- (void)updateWithTimeSinceLastUpdate:(CFTimeInterval)timeSinceLast {
self.lastSpawnTimeInterval += timeSinceLast;
if (self.lastSpawnTimeInterval > 1) {
self.lastSpawnTimeInterval = 0;
[self addMonster];
}
}
- (void)update:(NSTimeInterval)currentTime {
// Handle time delta.
// If we drop below 60fps, we still want everything to move the same distance.
CFTimeInterval timeSinceLast = currentTime - self.lastUpdateTimeInterval;
self.lastUpdateTimeInterval = currentTime;
if (timeSinceLast > 1) { // more than a second since last update
timeSinceLast = 1.0 / 60.0;
self.lastUpdateTimeInterval = currentTime;
}
[self updateWithTimeSinceLastUpdate:timeSinceLast];
}
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
[self runAction:[SKAction playSoundFileNamed:#"pew-pew-lei.caf" waitForCompletion:NO]];
// 1 - Choose one of the touches to work with
UITouch * touch = [touches anyObject];
CGPoint location = [touch locationInNode:self];
// 2 - Set up initial location of projectile
SKSpriteNode * projectile = [SKSpriteNode spriteNodeWithImageNamed:#"projectile"];
projectile.position = self.player.position;
projectile.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:projectile.size.width/2];
projectile.physicsBody.dynamic = YES;
projectile.physicsBody.categoryBitMask = projectileCategory;
projectile.physicsBody.contactTestBitMask = monsterCategory;
projectile.physicsBody.contactTestBitMask = enemyCategory;
projectile.physicsBody.collisionBitMask = 0;
projectile.physicsBody.usesPreciseCollisionDetection = YES;
// 3- Determine offset of location to projectile
CGPoint offset = rwSub(location, projectile.position);
// 4 - Bail out if you are shooting down or backwards
if (offset.x <= 0) return;
// 5 - OK to add now - we've double checked position
[self addChild:projectile];
// 6 - Get the direction of where to shoot
CGPoint direction = rwNormalize(offset);
// 7 - Make it shoot far enough to be guaranteed off screen
CGPoint shootAmount = rwMult(direction, 1000);
// 8 - Add the shoot amount to the current position
CGPoint realDest = rwAdd(shootAmount, projectile.position);
// 9 - Create the actions
float velocity = 480.0/1.0;
float realMoveDuration = self.size.width / velocity;
SKAction * actionMove = [SKAction moveTo:realDest duration:realMoveDuration];
SKAction * actionMoveDone = [SKAction removeFromParent];
[projectile runAction:[SKAction sequence:#[actionMove, actionMoveDone]]];
}
- (void)projectile:(SKSpriteNode *)projectile didCollideWithMonster:(SKSpriteNode *)monster {
NSLog(#"Hit");
[projectile removeFromParent];
[monster removeFromParent];
self.monstersDestroyed++;
if (self.monstersDestroyed > 80) {
SKTransition *reveal = [SKTransition flipHorizontalWithDuration:0.5];
SKScene * gameOverScene = [[GameOverScene alloc] initWithSize:self.size won:YES];
[self.view presentScene:gameOverScene transition: reveal];
}
}
- (void)didBeginContact:(SKPhysicsContact *)contact
{
// 1
SKPhysicsBody *firstBody, *secondBody, *thirdBody;
if (contact.bodyA.categoryBitMask < contact.bodyB.categoryBitMask)
{
firstBody = contact.bodyA;
secondBody = contact.bodyB;
thirdBody = contact.bodyB;
}
else
{
firstBody = contact.bodyB;
secondBody = contact.bodyA;
thirdBody = contact.bodyA;
}
// 2
if ((firstBody.categoryBitMask & projectileCategory) != 0 &&
(secondBody.categoryBitMask & enemyCategory) != 0 &&
(thirdBody.categoryBitMask & monsterCategory) != 0)
{
[self projectile:(SKSpriteNode *) firstBody.node didCollideWithMonster:(SKSpriteNode *) secondBody.node];
[self projectile:(SKSpriteNode *) firstBody.node didCollideWithEnemy: (SKSpriteNode *) secondBody.node];
}
}
- (void)addEnemy {
// Create sprite
SKSpriteNode * enemy = [SKSpriteNode spriteNodeWithImageNamed:#"enemy"];
enemy.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:enemy.size]; // 1
enemy.physicsBody.dynamic = YES; // 2
enemy.physicsBody.categoryBitMask = enemyCategory; // 3
enemy.physicsBody.contactTestBitMask = projectileCategory; // 4
enemy.physicsBody.collisionBitMask = 0; // 5
// Determine where to spawn the monster along the Y axis
int minY = enemy.size.height / 2;
int maxY = self.frame.size.height - enemy.size.height / 2;
int rangeY = maxY - minY;
int actualY = (arc4random() % rangeY) + minY;
// Create the monster slightly off-screen along the right edge,
// and along a random position along the Y axis as calculated above
enemy.position = CGPointMake(self.frame.size.width + enemy.size.width/2, actualY);
[self addChild:enemy];
// Determine speed of the monster
int minDuration = 1.0;
int maxDuration = 6.0;
int rangeDuration = maxDuration - minDuration;
int actualDuration = (arc4random() % rangeDuration) + minDuration;
// Create the actions
SKAction * actionMove = [SKAction moveTo:CGPointMake(-enemy.size.width/2, actualY) duration:actualDuration];
SKAction * actionMoveDone = [SKAction removeFromParent];
SKAction * loseAction = [SKAction runBlock:^{
SKTransition *reveal = [SKTransition flipHorizontalWithDuration:0.5];
SKScene * gameOverScene = [[GameOverScene alloc] initWithSize:self.size won:NO];
[self.view presentScene:gameOverScene transition: reveal];
}];
[enemy runAction:[SKAction sequence:#[actionMove, loseAction, actionMoveDone]]];
}
- (void)projectile:(SKSpriteNode *)projectile didCollideWithEnemy:(SKSpriteNode *)enemy {
NSLog(#"Hit");
[projectile removeFromParent];
[enemy removeFromParent];
self.enemysDestroyed++;
if (self.enemysDestroyed > 80) {
SKTransition *reveal = [SKTransition flipHorizontalWithDuration:0.5];
SKScene * gameOverScene = [[GameOverScene alloc] initWithSize:self.size won:YES];
[self.view presentScene:gameOverScene transition: reveal];
}
}
#end
I am not sure if you realize this, but you never actually call addEnemy. Look through the code. You will find a call to addMonster but never addEnemy. Implementing the method is one thing- without calling the method, whatever is inside will never run.

Resources