UIButton won't generate randomly when score is added? - ios

I am having a problem with my coding on Xcode. I am making an app in which a target appears, then you have to tap it, but the time allowed between each tap shortens gradually.
MY PROBLEM: whenever I try and make a UILabel update after a tap, the target goes back to it's original position on my view controller. I have all relevant code here:
-(IBAction)startButtonPressed:(id)sender {
startButton.hidden = YES;
Text.hidden = YES;
targX = arc4random() %769;
targY = arc4random() % 925;
Target.center = CGPointMake(targX, targY);
Target.hidden = NO;
}
-(IBAction)targetTapped:(id)sender {
[Time invalidate];
targX = arc4random() %769;
targY = arc4random() % 925;
[self scoreAdd:(id)sender];
Target.center = CGPointMake(targX, targY);
timeMax = 5 - (Score * 0.05);
if (Score >= 90) {
timeMax = 0.5;
}
Time = [NSTimer scheduledTimerWithTimeInterval:timeMax target:self selector:#selector(Lose:) userInfo:nil repeats:NO];
}
-(void)Lose:(id)sender {
Target.hidden = YES;
Text.hidden = NO;
}
-(void)scoreAdd:(id)sender{
Score = Score + 1;
scoreLabel.text = [NSString stringWithFormat:#"Score: %li", Score];
}

print
targX = arc4random() %769;
targY = arc4random() % 925;
in both methods , check whether you are getting proper points. And check generated points lies with in device screen.

Related

SKSpriteNode loses its physicsBody properties

I'm using SpriteKit to create a game in which objects at the bottom of the map move.
The objects are crocodiles and coins.
The scene uses an NSTimer to that calls this selector:
timer = [NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:#selector(generateBottomSprite) userInfo:nil repeats:YES];
-(void) generateBottomSprite{
int random = (arc4random() % difficulty+3) + difficulty-3;
if (counter >random){
SKSpriteNode *bottomSprite;
if (random>difficulty){
bottomSprite = [SKSpriteNode spriteNodeWithImageNamed:#"crocodile"];
bottomSprite.size = CGSizeMake(70, 120);
bottomSprite.physicsBody.categoryBitMask = crocMask;
}else{
bottomSprite = [SKSpriteNode spriteNodeWithImageNamed:#"coin"];
bottomSprite.size = CGSizeMake(50, 50);
bottomSprite.physicsBody.categoryBitMask = coinMask;
}
//create a crocodile
bottomSprite.position = CGPointMake(self.frame.size.width,bottomSprite.frame.size.height/2);
bottomSprite.name = #"bottomSprite";
[self addChild: bottomSprite];
counter = 0;
[self enumerateChildNodesWithName:#"bottomSprite" usingBlock: ^(SKNode *node, BOOL *stop) {
node.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:node.frame.size];
node.physicsBody.affectedByGravity = NO;
node.physicsBody.mass = 8000.0;
node.physicsBody.friction = 2.50;
node.physicsBody.usesPreciseCollisionDetection = YES;
}];
}
}
The problem: all the physicsWorld's properties are re-initialized on each call to the selector and i must iterate over the children of the scene in order to re-assign them.
Why are the properties get re-initialized?
you are setting the categorybitmask before creating the skphysicsbody itself
bottomSprite = [SKSpriteNode spriteNodeWithImageNamed:#"crocodile"];
bottomSprite.size = CGSizeMake(70, 120);
//add the following
bottomSprite.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:bottomSprite.frame.size];
///////////////
bottomSprite.physicsBody.categoryBitMask = crocMask;
move all the physics settings outside the enumeration like so
if (counter >random){
SKSpriteNode *bottomSprite;
int currentBitMask;
if (random>difficulty){
bottomSprite = [SKSpriteNode spriteNodeWithImageNamed:#"crocodile"];
bottomSprite.size = CGSizeMake(70, 120);
currentBitMask = crocMask;
}else{
bottomSprite = [SKSpriteNode spriteNodeWithImageNamed:#"coin"];
bottomSprite.size = CGSizeMake(50, 50);
currentBitMask = coinMask;
}
**bottomSprite.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:bottomSprite.frame.size];**
bottomSprite.physicsBody.categoryBitMask = currentBitMask ;
bottomSprite.physicsBody.affectedByGravity = NO;
bottomSprite.physicsBody.mass = 8000.0;//way too high
bottomSprite.physicsBody.friction = 2.50;//probably high
bottomSprite.physicsBody.usesPreciseCollisionDetection = YES;//overkill, set only if critical
//create a crocodile
bottomSprite.position = CGPointMake(self.frame.size.width,bottomSprite.frame.size.height/2);
bottomSprite.name = #"bottomSprite";
[self addChild: bottomSprite];
you also might wanna make use of the update method in the skscene and nstimeintervals to measure time till you pass half a second then call the generateBottomSprite method, it should be more efficient than using an additional NSTimer.
Feel free to ask if anything is unclear, hope this helps.

How to save Best Time score using NSUserDefault

Hey guys I'm extremely new to programming and especially with Objective C so please bear with me. I been practicing my skills on an iPhone app project I have been working on and now am stuck on an issue with saving time. I have a simple slider puzzle game that has a timer that increases until you finish the puzzle. the time is represent in this format "00:00". i would like to be able to save the lowest time after completion and present it on the screen on the start of the app for reference on the time to beat. The problem I face however is that it keeps saving the time 0 as the lowest and nothing can beat that.
Below is code of my:
Timer
-(void)setTimer
{
self.secondsCount = 0;
self.gameCountDownTimer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:#selector(timerRun) userInfo:nil repeats:YES];
}
-(void)timerRun
{
self.secondsCount++;
NSString *timerOutput = [NSString stringWithFormat:#" %02.f : %02i", round(self.secondsCount / 60), self.secondsCount % 60 ];
self.timeLabel.text = timerOutput;
}
StartGame Button
- (IBAction)start:(id)sender {
// reset steps
self.secondsCount=0;
step = 0;
[self setTimer];
// set the view so that it can interact with touches
[board setUserInteractionEnabled:YES];
// set the label text to 'reset'
[startButton setTitle:#"Reset" forState:UIControlStateNormal];
// initialize the board, lets play!
[board playWithImage:image andSize:(boardSize.selectedSegmentIndex+3)];
}
End of Game
(void)puzzleBoardDidFinished:(PuzzleGameView *)puzzleBoard {
// add the full image with 0.0 alpha in view
if(self.secondsCount!=0){
self.finalTime = self.secondsCount;
NSLog(#"seconds is: %i",self.secondsCount);
[self saveTime];
if(self.finalTime<self.bestTime) {
NSLog(#"bestTime! is: %i",self.finalTime);
[self saveTime];
}
}
[self.gameCountDownTimer invalidate];
self.gameCountDownTimer = nil;
UIImageView *fullImage = [[UIImageView alloc]initWithImage:image];
fullImage.frame = board.bounds;
fullImage.alpha = 0.0;
[board addSubview:fullImage];
[UIView animateWithDuration:.4
animations:^{
// set the alpha of full image to 1.0
fullImage.alpha = 1.0;
}
completion:^(BOOL finished){
// set the view interaction and set the label text
NSLog(#"Congrats! You finish this %d x %d puzzle with %d steps", (boardSize.selectedSegmentIndex+3), (boardSize.selectedSegmentIndex+3), step);
[board setUserInteractionEnabled:NO];
[startButton setTitle:#"Start" forState:UIControlStateNormal];
}];
}
And Attempt to save the data
-(void)saveTime {
[[NSUserDefaults standardUserDefaults]setInteger:self.secondsCount forKey:#"BestTime"];
[[NSUserDefaults standardUserDefaults]synchronize];
}
This was in my viewdidload
self.bestTime = [[NSUserDefaults standardUserDefaults]integerForKey:#"BestTime"];
self.bestTimeLabel.text = [NSString stringWithFormat:#" %02.f : %02i", round(self.bestTime / 60), self.bestTime % 60 ];
As stated before Im pretty new so any advice and recommendations would be awesome. Im definitely eager to learn more about this stuff and would greatly appreciate if you guys could help with the journey. Thank You
It looks like [[NSUserDefaults standardUserDefaults]integerForKey:#"BestTime"] is 0 every time you assign its value to self.bestTime.
This code might help:
if(self.bestTime == 0){
self.bestTime = finalTime;
}
Your code looks ok. I'm pretty sure it's just the showing the value in NSLog that is not working.
Change:
self.bestTimeLabel.text = [NSString stringWithFormat:#" %02.f : %02i", round(self.bestTime / 60), self.bestTime % 60 ];
To:
self.bestTimeLabel.text = [NSString stringWithFormat:#" %02.f : %02i", round(self.bestTime / 60.0f), self.bestTime % 60 ];
For float variable: int / int yields integer which you are assigning to float and printing it so it's 0.00.

How to create simple start screen using spritebuilder?

At the time of this post, I am using the latest versions of XCode and SpriteBuilder.
I have 2 games, one of which is built using purely Objective-C on XCode and another which uses Objective-C on XCode as well as SpriteBuilder. The non-SpriteBuilder game has a tap to play screen whose background looks the same as the in-game background. The second you tap the screen, you go straight into the game.
The Sprite Builder game is the one I am trying to implement a Start screen on. I read a few tutorials, http://www.reigndesign.com/blog/creating-a-simple-menu-with-scene-transition-in-cocos2d/, but it didn't help me. I don't want to transition from one screen to another using different background images.
This is the start screen that my non-SpriteBuilder game uses:
-(void)NewGame{
Bottom1.hidden = YES;
Bottom2.hidden = YES;
Bottom3.hidden = YES;
Bottom4.hidden = YES;
Bottom5.hidden = YES;
Bottom6.hidden = YES;
Bottom7.hidden = YES;
Top1.hidden = YES;
Top2.hidden = YES;
Top3.hidden = YES;
Top4.hidden = YES;
Top5.hidden = YES;
Top6.hidden = YES;
Top7.hidden = YES;
Obstacle.hidden = YES;
Obstacle2.hidden = YES;
Intro1.hidden = NO;
Intro2.hidden = NO;
Intro3.hidden = NO;
Heli.hidden = NO;
Heli.center = CGPointMake(31, 74);
Heli.image = [UIImage imageNamed:#"HeliUp.png"];
Start = YES;
ScoreNumber = 0;
Score.text = [NSString stringWithFormat:#"Score: 0"];
Intro3.text = [NSString stringWithFormat:#"High Score: %i", HighScore];
All obstacles are hidden except the background and the intro labels. You also see your high score and the tap to play button.
When you tap the screen, this is the next code:
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
if (Start == YES) {
Intro1.hidden = YES;
Intro2.hidden = YES;
Intro3.hidden = YES;
timer = [NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:#selector(HeliMove) userInfo:nil repeats:YES];
Scorer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:#selector(Scoring) userInfo:nil repeats:YES];
Start = NO;
Bottom1.hidden = NO;
Bottom2.hidden = NO;
Bottom3.hidden = NO;
Bottom4.hidden = NO;
Bottom5.hidden = NO;
Bottom6.hidden = NO;
Bottom7.hidden = NO;
Top1.hidden = NO;
Top2.hidden = NO;
Top3.hidden = NO;
Top4.hidden = NO;
Top5.hidden = NO;
Top6.hidden = NO;
Top7.hidden = NO;
Obstacle.hidden = NO;
Obstacle2.hidden = NO;
RandomPosition = arc4random() %75;
RandomPosition = RandomPosition + 110;
Obstacle.center = CGPointMake(570,RandomPosition);
RandomPosition = arc4random() %75;
RandomPosition = RandomPosition + 110;
Obstacle2.center = CGPointMake(855,RandomPosition);
RandomPosition = arc4random() %55;
Top1.center = CGPointMake(560, RandomPosition);
RandomPosition = RandomPosition +265;
Bottom1.center = CGPointMake(560, RandomPosition);
RandomPosition = arc4random() %55;
Top2.center = CGPointMake(640, RandomPosition);
RandomPosition = RandomPosition +265;
Bottom2.center = CGPointMake(640, RandomPosition);
RandomPosition = arc4random() %55;
Top3.center = CGPointMake(720, RandomPosition);
RandomPosition = RandomPosition +265;
Bottom3.center = CGPointMake(720, RandomPosition);
RandomPosition = arc4random() %55;
Top4.center = CGPointMake(800, RandomPosition);
RandomPosition = RandomPosition +265;
Bottom4.center = CGPointMake(800, RandomPosition);
RandomPosition = arc4random() %55;
Top5.center = CGPointMake(880, RandomPosition);
RandomPosition = RandomPosition +265;
Bottom5.center = CGPointMake(880, RandomPosition);
RandomPosition = arc4random() %55;
Top6.center = CGPointMake(960, RandomPosition);
RandomPosition = RandomPosition +265;
Bottom6.center = CGPointMake(960, RandomPosition);
RandomPosition = arc4random() %55;
Top7.center = CGPointMake(1040, RandomPosition);
RandomPosition = RandomPosition +265;
Bottom7.center = CGPointMake(1040, RandomPosition);
}
Y = -7;
Heli.image = [UIImage imageNamed:#"HeliUp.png"];
}
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{
Y = 7;
Heli.image = [UIImage imageNamed:#"HeliDown.png"];
}
In basic terms, all obstacles are loaded and are generated in random positions, the object moves with u tap the screen and drops if you don't tap the screen. The intro labels are hidden.
Here's the code for my SpriteBuilder game:
- (void)didLoadFromCCB {
self.userInteractionEnabled = TRUE;
_grounds = #[_ground1, _ground2];
for (CCNode *ground in _grounds) {
// set collision txpe
ground.physicsBody.collisionType = #"level";
ground.zOrder = DrawingOrderGround;
_scrollSpeed = 80.f;
}
// set this class as delegate
_physicsNode.collisionDelegate = self;
// set collision txpe
_hero.physicsBody.collisionType = #"hero";
_hero.zOrder = DrawingOrdeHero;
_obstacles = [NSMutableArray array];
[self spawnNewObstacle];
[self spawnNewObstacle];
[self spawnNewObstacle];
}
- (void)touchBegan:(UITouch *)touch withEvent:(UIEvent *)event {
if (!_gameOver) {
[_hero.physicsBody applyImpulse:ccp(0, 400.f)];
[_hero.physicsBody applyAngularImpulse:10000.f];
_sinceTouch = 0.f;
}
}
Really short code. Basically, after the logo screen disappears, the game starts right away without a start screen. When the game ends, it restarts and you immediately start playing again.
Trying to figure out how I can add another void statement to the SpriteBuilder game so that a person goes from tapping the screen then to playing the game instead of immediately going into playing the game.
I can add the viewDidLoad statement to the SpriteBuilder game but I wonder if it will conflict with the didLoadfromCCB statement. I need to have the start screen transition into the game screen using the same background. Only difference is, the start screen will hide the obstacles and show the play now labels, then the labels will hide and obstacles become visible in the game screen.
I would suggest doing it following the spritebuilder tutorial. This will probably require you to rejig your code. The following tutorial also helps you with linking spritebuilder to backend code, and also how to transition between scenes.
I'm not 100% sure why you included so much detail in your question, I'm confused with what is game logic, and what is other logic... So If I'm off the mark, let me know and I'll update my answer.
https://www.makegameswith.us/tutorials/getting-started-with-spritebuilder/menus/
Smells a bit like Flappy Bird to me.
Either way I would implement it with a gameState variable and a layer with the menu in.
When you open the game (viewDidLoad) set the gameState to 0 e.g. Menu
then in the touch method I would have a switch like the following:
switch(gameState){
case 0: //Menu
menuLayer.hidden = YES;
gameState = 1 //IN_GAME
break;
case 1: //In game
//Do your game tap code
break;
case 2: //Game Over
gameOverLayer.hidden = NO;
break;
}
Or you could duplicate the CCb and remove the game code and load the game cCB on touch, but I think the former is the best option.

'CALayer position contains NaN: [nan nan]' when working with Bouncing Ball Array in C4

So I'm trying to just recreate a bouncing ball app using xcode and C4. What I'm trying to do right now is re-create some of the examples in Dan Shiffmans Nature of Code book in C4.
So far I've managed to create my own class of "Mover" objects that bounce around the screen. That's all working great. The next step was to start "applying some forces" to the movers and play around with that.
I seem to be getting an exception thats crashing the program now that I've added methods to apply force. I put on exception breakpoints and this line in C4Control.m is where it stops:
if(_animationDuration == 0.0f) super.center = center;
Looking into this more, I notice that neither super.center or center properties have a value assigned to them (both of NaN). I'm not sure what's causing this? This seemed to start once I decided to set each Movers initial velocity/accel to 0 and only assign "fores" (C4Vectors for wind and gravity) to create motion in these objects. When I comment out the 2 lines that apply each force, the problem goes away.
This is the implementation of my mover class:
//Init Method
- (id)initWithPoint:(CGPoint)point andCanvasController:(C4CanvasController *)canvasController {
self = [super init];
if (self) {
canvasFrame = CGPointMake(canvasController.canvas.width,
canvasController.canvas.height);
diam = [C4Math randomInt:70];
mass = diam * 0.5f;
CGRect ellipseFrame = CGRectMake(0, 0, diam, diam);
[self ellipse:ellipseFrame];
self.lineWidth = 0.0f;
self.fillColor = [UIColor colorWithRed:[C4Math randomInt:60]/60
green:[C4Math randomInt:100]/100.0f
blue:0.9f
alpha:0.3f];
int foo = arc4random() % (int)([canvasController.canvas height]);
int bar = arc4random() % (int)([canvasController.canvas width]);
self.location = [C4Vector vectorWithX:foo
Y:bar
Z:0.0f];
self.origin = self.location.CGPoint;
self.accel = [C4Vector vectorWithX:0.00f Y:0.0f Z:0.0f];
self.vel = [C4Vector vectorWithX:0.00f Y:0.0f Z:0.0f];
}
return self;
}
//Method to calculate updated mover position
-(void)update{
[self.vel add:self.accel];
[self.location add:self.vel];
self.origin = self.location.CGPoint;
[self.accel multiplyScalar:0];
[self checkBounds];
}
//Checking if mover has reached edge of screen
-(void)checkBounds{
if (self.origin.x > canvasFrame.x - diam){
self.location.x = canvasFrame.x - diam;
self.vel.x *= -1;
}
else if (self.origin.x < 0){
self.vel.x *= -1;
self.location.x = 0;
}
if(self.origin.y > canvasFrame.y - diam){
self.location.y = canvasFrame.y - diam;
self.vel.y *= -1;
}
else if(self.origin.y < 0){
self.vel.y *= -1;
self.location.y = 0;
}
}
//Start C4Timer to run update every 1/60th of a second
- (void) run{
updateTimer = [C4Timer automaticTimerWithInterval:1/60.0f
target:self
method:#"update"
repeats:YES];
}
//Calculate a force to apply to mover
- (void)applyForce:(C4Vector *)force{
[force divideScalar:mass];
[self.accel add:force];
}
In my C4WorkSpace.m file:
#import "C4Workspace.h"
#import "Mover.h"
#implementation C4WorkSpace{
Mover *testMover;
NSMutableArray *moverArray;
}
-(void)setup {
C4Vector *gravity = [C4Vector vectorWithX:0.01f Y:0.0 Z:0.0f];
C4Vector *wind = [C4Vector vectorWithX:0 Y:0.4 Z:0];
moverArray = [[NSMutableArray alloc]init];
//Not using foo/bar variables right now, but usually use them to create CGPoint p
//int foo = arc4random() % (int)([self.canvas height]);
//int bar = arc4random() % (int)([self.canvas width]);
for (int i = 0; i < 500; i++) {
CGPoint p = CGPointMake(0,0);
Mover *m = [[Mover alloc]initWithPoint:p andCanvasController:self];
[moverArray addObject:m];
}
for (Mover *m in moverArray){
[self addShape:m];
[m run];
[m applyForce:gravity];
[m applyForce:wind];
}
}
#end
Sorry for how long this was, any and all help is much appreciated!

Set sprite using background position

I am new to cocos2d so please help me if u can
I have background moving from right to left, and the background contains small windows with 3 rows of windows
_spaceDust1 = [CCSprite spriteWithFile:#"bg_front_spacedust.png"];
_spaceDust2 = [CCSprite spriteWithFile:#"bg_front_spacedust.png"];
CGPoint dustSpeed = ccp(0.1 , 0.1);
CGPoint bgSpeed = ccp(0.05 , 0.05);
[_backgroundNode addChild:_spaceDust1 z:0 parallaxRatio:dustSpeed positionOffset:ccp(0,winSize.height / 2)];
[_backgroundNode addChild:_spaceDust2 z:0 parallaxRatio:dustSpeed positionOffset:ccp(_spaceDust1.contentSize.width , winSize.height / 2)];
Now add enemies wich also move from right to left with same speed
_robbers = [[CCArray alloc] initWithCapacity:kNumAstroids];
for (int i = 0; i < kNumAstroids; ++i) {
CCSprite *asteroid = [CCSprite spriteWithSpriteFrameName:#"robber.png"];
asteroid.visible = NO;
[_batchNode addChild:asteroid];
[_robbers addObject:asteroid];
}
in update method:
double curTime = CACurrentMediaTime();
if (curTime > _nextRunemanSpawn) {
float randSecs = [self randomValueBetween:0.20 andValue:1.0];
_nextRunemanSpawn = randSecs + curTime;
float randY = 80.0;
float randY1 = 185.0;
float randY2 = 293.0;
float randDuration = [self randomValueBetween:5.2 andValue:5.2];
float randDuration1 = [self randomValueBetween:1.0 andValue:1.0];
CCSprite *asteroid = [_robbers objectAtIndex:_nextRobber];
_nextRobber++;
if (_nextRobber >= _robbers.count) {
_nextRobber = 0;
}
//[asteroid stopAllActions];
int winChoice = arc4random() % 3;
if (winChoice == 0) {
asteroid.position = ccp(winSize.width +asteroid.contentSize.width / 2 , randY);
asteroid.visible = YES;
}
else if(winChoice == 1){
asteroid.position = ccp(winSize.width +asteroid.contentSize.width / 2 , randY1);
asteroid.visible = YES;
}else {
asteroid.position = ccp(winSize.width +asteroid.contentSize.width / 2 , randY2);
asteroid.visible = YES;
}
[asteroid runAction:[CCSequence actions:[CCMoveBy actionWithDuration:randDuration position:ccp(-winSize.width-asteroid.contentSize.width, 0)],
[CCCallFuncN actionWithTarget:self selector:#selector(setInvisible:)],nil]];
All is going well but i want to set this enemies in to window and in random position
so how can i set x-argument of enemies so it can be fix in to window of the background?
For some reason I cannot comment so this is written as an answer. What exactly are you trying to do? I am a bit confused. It sounds like you want the X position to be set so that it is in one of 3 random positions, is that correct?

Resources