I am new to the community, so let me know if my question is unclear. I am trying to make a choice reaction exercise on the iPAD. There are two images that should appear in random sequence on the left and right of the screen, and the user will respond by tapping a button that corresponds to the position of the appeared image. Here's the problem, I tried to get the two images to appear at random order using the following way:
- (void) viewDidAppear:(BOOL)animated
{
for(int n = 1; n <= 20; n = n + 1)
{
int r = arc4random() % 2;
NSLog(#"%i", r);
if(r==1)
{
[self greenCircleAppear:nil finished:nil context: nil];
}
else
{
[self redCircleAppear:nil finished:nil context: nil];
}
}
}
However, 20 random numbers get generated while only 1 set of animation is run. Is there a way to let the animation finish running in each loop before the next loop begins? Any help is appreciated, thanks in advance!
When you say "only one set of animation is run" I'm assuming that means greenCircleAppear and redCircleAppear begin the sequence of images appearing and the user pressing a button. If that's the case, I'd recommend not using a for loop in viewDidAppear but instead have viewDidAppear initialize the current state and call a method that presents the next animation. When the animation is finished, have it call the method that presents the next animation. Something along these lines:
Add this to the interface:
#interface ViewController ()
#property NSInteger currentIteration;
#end
This is in the implementation:
- (void)viewDidAppear:(BOOL)animated {
self.currentIteration = 0;
[self showNextAnimation];
}
- (void)greenCircleAppear:(id)arg1 finished:(id)arg2 context:(id)arg3 {
//perform animation
NSLog(#"green");
[self showNextAnimation];
}
- (void)redCircleAppear:(id)arg1 finished:(id)arg2 context:(id)arg3 {
//perform animation
NSLog(#"red");
[self showNextAnimation];
}
- (void)showNextAnimation {
self.currentIteration = self.currentIteration + 1;
if (self.currentIteration <= 20) { //you should replace '20' with a constant
int r = arc4random() % 2;
NSLog(#"%i", r);
if(r==1)
{
[self greenCircleAppear:nil finished:nil context: nil];
}
else
{
[self redCircleAppear:nil finished:nil context: nil];
}
}
else {
//do what needs to be done after the last animation
}
}
Related
I am using SpriteKit.
The code below basically makes a lattice of dots on the screen. However, I want to call each 'dot' a different name based on its position, so that I can access each dot individually in another method. I'm struggling a little on this, so would really appreciate if someone could point me in the right direction.
#define kRowCount 8
#define kColCount 6
#define kDotGridSpacing CGSizeMake (50,-50)
#import "BBMyScene.h"
#implementation BBMyScene
-(id)initWithSize:(CGSize)size {
if (self = [super initWithSize:size]) {
/* Setup your scene here */
// Background
self.backgroundColor = [SKColor colorWithRed:0.957 green:0.957 blue:0.957 alpha:1]; /*#f4f4f4*/
CGPoint baseOrigin = CGPointMake(35, 385);
for (NSUInteger row = 0; row < kRowCount; ++row) {
CGPoint dotPosition = CGPointMake(baseOrigin.x, row * (kDotGridSpacing.height) + baseOrigin.y);
for (NSUInteger col = 0; col < kColCount; ++col) {
SKSpriteNode *dot = [SKSpriteNode spriteNodeWithImageNamed:#"dot"];
dot.position = dotPosition;
[self addChild:dot];
//6
dotPosition.x += kDotGridSpacing.width;
}
}
}
return self;
}
Here is an image of what appears on screen when I run the above code...
http://cl.ly/image/3q2j3E0p1S1h/Image1.jpg
I simply want to be able to call an individual dot to do something when there is some form of user interaction, and I'm not sure how I would do that without each dot having a different name.
If anyone could help I would really appreciate it.
Thanks,
Ben
- (void)update:(NSTimeInterval)currentTime {
for(SKNode *node in self.children){
if ([node.name containsString:#"sampleNodeName"]) {
[node removeFromParent];
}
}
}
Hope this one helps!
You can set the name property of each node inside the loop.
Then you can access them with self.children[index].
If you want to find a specific node in your children, you have to enumerate through the array.
Update:
To clarify how to search for an item by iterating, here is a helper method:
- (SKNode *)findNodeNamed:(NSString *)nodeName
{
SKNode *nodeToFind = nil;
for(SKNode *node in self.children){
if([node.name isEqualToString:nodeName]){
nodeToFind = node;
break;
}
}];
return nodeToFind;
}
I'm just starting to wrap my brain around Sprite Kit and I am encountering a very strange error when attempting to change the property of a node in a for loop im using.
I have two SKSpriteNode objects, one is the child of a SKScene (BLATheBugs) and the other is a child of the first (BLAEmptySpaces). I have a grid laid out with BLAEmptySpaces, and BLATheBugs on top of those empty spaces which are supposed to take UITouch, and move to an empty space if its bool isOccpupied property == False. When the scene is set up, the SKScene triggers a method in TheBugs:
-(void) spawnEmptySpacesInitialize
{
[self addChild:[self spawnEmptySpaces]];
}
which in turn triggers:
-(BLAEmptySpaces *) spawnEmptySpaces
{
emptySpace = [[BLAEmptySpaces alloc] init];
emptySpace.numberOfEmptySpacesNeeded = 12;
[emptySpace spawnEmptySpaces];
[emptySpace positionTheEmptySpaces];
return emptySpace;
}
which finally triggers a method in the EmptySpaces object:
-(BLAEmptySpaces *) spawnEmptySpaces
{
_emptySpacesArray = [NSMutableArray new];
for (int x = 0; x < _numberOfEmptySpacesNeeded; x++)
{
_anEmptySpace = [[BLAEmptySpaces alloc] initWithImageNamed:#"BlueLight.png"];
_anEmptySpace.zPosition = 50;
[_emptySpacesArray addObject:_anEmptySpace];
[self addChild: _anEmptySpace];
}
return self;
}
everything seems fine, (except for needing the additional "addChild" in the EmptySpaces object to get them to be drawn on the screen which i have also been trying to fix) but when i call the method to move TheBugs:
-(void) moveLeftOneSpace
{
NSLog(#"%d", emptySpace.emptySpacesArray.count);
for (emptySpace in emptySpace.emptySpacesArray)
{
NSLog(#"cycle");
if (emptySpace.isOccupied == NO)
{
for (_yellowBug in yellowBugArray)
{
if (_positionOfFingerTouchX > _yellowBug.position.x - variableOne && _positionOfFingerTouchX < _yellowBug.position.x + variableTwo && _positionOfFingerTouchY > _yellowBug.position.y - variableOne && _positionOfFingerTouchY < _yellowBug.position.y + variableTwo && emptySpace.position.x == _yellowBug.position.x - 80 && emptySpace.position.y == _yellowBug.position.y)
{
_yellowBug.position = CGPointMake(_yellowBug.position.x - spaceBetweenBugs, _yellowBug.position.y);
emptySpace.isOccupied = YES;
NSLog(#"execute");
}
}
}
}
}
It at first tells me there are 12 objects in the array and runs the operation. if I try to move any piece again, it tells me there are now NO objects in the array (yellowBugArray). It is also probably worth noting that it will not let me access emptySpace.anEmptySpace. Throws me an error.
Sorry for the long post, but hopefully somewhere in here is the cause of my problem.
Thank you very much guys!
I'm working on my first big application and have inadvertently driven myself into a panic from a small flaw in design. I've made a timer that counts at the touch of a button, and upon a second touch, transitions into a secondary timer with a 60 second countdown.
The problem lies in the fact that once I repeat this process, the (kRest-Pause) call is remembered. I'm looking to create a default countdown of 60 without the continuation of the time. Should I kill it in memory and create a new instance for each subsequent button press? Or is there a logic game that looks at the aggregate time and corrects with each new occurance?
I don't know how to approach this, I'm done attempting -if statements with returns as I have learned that's not how that works. Any help would be appreciated
EDIT: Sorry for the lack of clarity. I'm pretty green on programming of any caliber. So far, the main timer counts down from 10-0 then up from 0-120. In that 2 minute period, if the button is pressed again, the 0-120 count is paused for 60 seconds or until the button is pressed for the third time. If this 60-0 countdown reaches 0 or is interrupted, the initial 0-120 countup resumes its count. My issue is that if I push the button a fourth time, the 60-0 countdown is resumed from the moment of interruption without retaining a default of 60. This is why I named the post "creating defaults in Objective C". It's the wrong use of the word and way to broad, but it's what I could come up with.
kRest=60
-(void)increase{
if (mode==1){
count++;
int d = 10-count;
if (d==0){ timeLabel.text = #"Begin";
[self startPlaybackForPlayer: self.startTimerSound];}
else {timeLabel.text = [NSString stringWithFormat:#"%d", abs(d)];}
if(d<0){
//workign out
active = TRUE;
if (d <= -20) {
[self stopTimer];
}
}
else{
//no user interface
active = FALSE;
}
}
else{
pause++;
countdownLabel.text = [NSString stringWithFormat:#"%d!", (kRest-pause)];
NSLog(#"Paused at time %d", pause);
UIColor *textColor = nil;
if (pause % 2==0){
textColor = [UIColor yellowColor];
}
else{
textColor = [UIColor redColor];
}
timeLabel.textColor = textColor;
if ((kRest-pause)==0){
countdownLabel.text = [NSString stringWithFormat:#"%d!",pause];
mode=1;
pause=0;
[button setTitle:#"Stop" forState:UIControlStateNormal];
repCount++;
myRepCount.text = [NSString stringWithFormat:#"Rep Count: %d", repCount];
countdownLabel.text = #"";
}
}
}
if you are using a timer to access this counter then you should be able to update the counter that the timer uses. Just make sure you synchronize the object so you dont edit while you are reading.
here is an example of what I mean.
int counter = 0;
int limit = 60;
- (BOOL) incrementUntilReached{
#synchronized(self){
if (counter == limit) return YES;
counter++;
return NO;
}
}
- (void) resetTimer{
#synchronized(self){
counter = 0;
}
}
- (int) countsLeft {
#synchronized(self){
return limit - counter;
}
}
I´m making an iphone app in objective-c with cocos2d, in the code below I try to detect a collision and then run an animation. (The box1 is moved by touch)
When the "[self getChildByTag:d]" and "box1" collide AND overlap I get the "JUMP NOW!" displayed but I don't get the jump itself, but when the box1 is moved away from the "[self getChildByTag:d]" the jump occurs.
I understand that this probably has to do with the fact that the action is called many times, but please explain to me exactly what happens and please help me with a solution!
- (void)update:(ccTime)dt {
for (int d = lowestAvailableTag; d <= highestAvailableTag; d++) {
if ([self getChildByTag:d].position.y < (box1.position.y+45)&&
[self getChildByTag:d].position.x > (box1.position.x-45) &&
[self getChildByTag:d].position.x < (box1.position.x+45) ) {
NSLog(#"JUMP NOW!");
if ([self getChildByTag:d].position.x < 150) {
[[self getChildByTag:d] runAction:
[CCJumpTo actionWithDuration:1.5
position:ccp(240, 140) height:110 jumps:1]];
}
}
}
}
//albar
You can add some BOOL flag to detect if your jump occured. Smth like:
- (void) update:(ccTime)dt
{
if( jumpOccured == false )
{
BOOL needToJump = // your jump condition
if( needToJump == true )
{
// your jump code
jumpOccured = true;
}
}
}
by the way, if you have many possible collisions, you can use box2d to detect them
I have an NSMUtable array of images where a different image is displayed with a previous and a next button, but when I get to the end of the array the simulator crashes. I want to loop the end of the array to the beginning so that when I get to the end of the array of images when I hit the next button again it loops back to the first image, also when Im at the first image if I hit the previous button it loops to the last image with no crashes
What you want is a circular array, which is easy to implement using a standard NSMutableArray. For instance, say you store your images in an array called imageArray and use a simple variable to keep track of the index of your current image, like:
int currentImageIndex = 0;
...then you might implement nextImage and previousImage like:
- (UIImage*) nextImage {
currentImageIndex = (currentImageIndex + 1) % [imageArray count];
return [imageArray objectAtIndex:currentImageIndex];
}
- (UIImage*) previousImage {
currentImageIndex--;
if (currentImageIndex < 0) {
currentImageIndex = [imageArray count] - 1;
}
return [imageArray objectAtIndex:currentImageIndex];
}
Then just use nextImage and previousImage whenever you want to step through the array, and problem solved.
Simple enough to do. all you need to do is create a check to see if you're on the last element, and if so, set your tracker (like count or i etc) to 0 again,
Heres the psudo code
//set index
if ( array [ index ] == len(array) - 1) //at end
{
index = 0
}
if(array [index] == -1)//at beginning
{
index = len(array) -1
}
// do something with array[index]
I want to propose this solution:
A property for the selected UIImage, a NSInteger property to hold the current index.
-(IBAction) nextButtonTapped:(id)sender
{
self.currentIndex = self.currentIndex++ % [self.images count];
self.selectedImage= [self.images objectAtIndex:self.currentIndex];
[self reloadImageView];
}
-(IBAction) previousButtonTapped:(id)sender
{
self.currentIndex--;
if (self.currentIndex < 0)
self.currentIndex += [self.images count];
self.selectedImage= [self.images objectAtIndex:self.currentIndex];
[self reloadImageView];
}
-(void)reloadImageView
{
//do, what is necessary to display new image. Animation?
}