I have to show score with SKLabel in gameOverScene. how can i show score in GameOverScene Label? I am tried, please help me.
My game scene codes here. You can see all details about score in down stair.
MyScene.m
#interface MyScene ()<SKPhysicsContactDelegate>
#property NSUInteger score;
#end
-(void)setupUI
{
self.score = 0;
SKLabelNode *scoreLabel = [SKLabelNode labelNodeWithFontNamed:#"Chalkduster"];
scoreLabel.fontColor = [SKColor redColor];
scoreLabel.fontSize = 20.0;
scoreLabel.text = #"SCORE: 0";
scoreLabel.name = #"scoreLabel";
scoreLabel.verticalAlignmentMode = SKLabelVerticalAlignmentModeCenter;
scoreLabel.position = CGPointMake(self.size.width/2, self.size.height - scoreLabel.frame.size.height);
[self addChild:scoreLabel];
}
-(void)adjustScoreBy:(NSUInteger)points {
self.score += points;
SKLabelNode* score = (SKLabelNode*)[self childNodeWithName:#"scoreLabel"];
score.text = [NSString stringWithFormat:#"SCORE: %lu", (unsigned long)self.score];
}
- (void)gameOver
{
GameOverScene *gameOverScene = [GameOverScene sceneWithSize:self.size];
[self.view presentScene:gameOverScene transition:[SKTransition pushWithDirection:SKTransitionDirectionLeft duration:0.5]];
}
GameOverScene.h
#interface GameOverScene : SKScene
#property NSUInteger *score;
#end
GameOverScene.m
#implementation GameOverScene
{
SKLabelNode *scoreLabel;
}
-(id)initWithSize:(CGSize)size {
if (self = [super initWithSize:size]) {
self.backgroundColor = [SKColor colorWithRed:1.5 green:1.0 blue:0.5 alpha:0.0];
[self addStartButton];
[self addRateButton];
[self addBackButton];
[self addScoreLabel];
}
return self;
}
-(void)addScoreLabel
{
scoreLabel = [SKLabelNode labelNodeWithFontNamed:#"Chalkduster"];
scoreLabel.text = [NSString stringWithFormat:#"SCORE: %lu", (unsigned long)self.score];
scoreLabel.position = CGPointMake(500, 50);
scoreLabel.name = #"gameOverScore";
[self addChild:scoreLabel];
}
There are several approaches to do this.
You could use a singleton class to handle that.
Other option would be to create a public score property in GameOverScene, and then pass the score value of MyScene to GameOverScene, something like this:
In GameOverScene.h add a score property
#interface GameOverScene : SKScene
#property NSUInteger score;
#end
Then in you gameOver method set the score value
- (void)gameOver
{
GameOverScene *gameOverScene = [GameOverScene sceneWithSize:self.size];
gameOverScene.score = self.score;
[self.view presentScene:gameOverScene transition:[SKTransition pushWithDirection:SKTransitionDirectionLeft duration:0.5]];
}
In GameOverScene create didMoveToView
- (void)didMoveToView:(SKView *)view
{
[self addScoreLabel];
}
You just need a property in your next scene (target class) and call it from (void)gameOver (in the source class)
Add it int your target class like this
#property int score;
then use it like this in your source class
gameOverScene.score = self.score
You will use this kind of stuff a lot for when moving data around.
Related
This is my first time really using cocoa to make an application for mac. The only problem is that drawRect isn't being called at all. The real kicker is that it used to, but now it doesn't, and I have no idea what I did wrong. :/
I am setting 'setNeedsDisplay' but it refuses to work. As you can see, I have two debug prints in there, but only "DEBUG 1" is being called. Any ideas?
//ScrollingTextView.h:
//Adapted from http://stackoverflow.com/a/3233802/3438793
#import <Cocoa/Cocoa.h>
#interface ScrollingTextView : NSView {
NSTimer *scroller;
NSPoint point;
NSString *text;
NSString *tempText;
NSString *nextText;
CGFloat stringWidth;
NSInteger delay;
BOOL draw;
NSDictionary *fontDict;
NSFont *font;
BOOL isBigger;
}
#property (nonatomic, copy) NSString *text;
#property (nonatomic, copy) NSString *tempText;
#property (nonatomic, copy) NSString *nextText;
#property (nonatomic) NSInteger delay;
#property (nonatomic) BOOL draw;
#property (nonatomic) NSDictionary *fontDict;
#property (nonatomic) NSFont *font;
#property (nonatomic) BOOL isBigger;
#end
//ScrollingTextView.m
//Adapted from http://stackoverflow.com/a/3233802/3438793
#import "ScrollingTextView.h"
#implementation ScrollingTextView
#synthesize text;
#synthesize tempText;
#synthesize nextText;
#synthesize delay;
#synthesize draw;
#synthesize fontDict;
#synthesize font;
#synthesize isBigger;
- (void) setNextText:(NSString *)newText {
font = [NSFont fontWithName:#"Lucida Grande" size:15.0];
fontDict = [NSDictionary dictionaryWithObjectsAndKeys:font, NSFontAttributeName, [NSNumber numberWithFloat:1.0], NSBaselineOffsetAttributeName, nil];
if (text == nil) {
text = [newText copy];
} else {
nextText = [newText copy];
}
point = NSZeroPoint;
stringWidth = [newText sizeWithAttributes:fontDict].width;
if (stringWidth <= 163) {
NSString *size = [#"{" stringByAppendingString:[[NSString stringWithFormat:#"%f", stringWidth] stringByAppendingString:#", 22}"]];
[self setFrameSize:NSSizeFromString(size)];
isBigger = false;
} else {
isBigger = true;
}
if (text != nil) {
scroller = nil;
scroller = [NSTimer scheduledTimerWithTimeInterval:0.03 target:self selector:#selector(moveText:) userInfo:nil repeats:YES];
}
draw = false;
delay = 100;
}
- (void) moveText:(NSTimer *)timer {
point.x = point.x - 1.0f;
[self setNeedsDisplay:YES];
NSLog(#"DEBUG 1");
}
- (void)drawRect:(NSRect)dirtyRect {
// Drawing code here.
NSLog(#"DEBUG 2");
//NSLog([#"Next: " stringByAppendingString:nextText]);
//NSLog([#"Temp: " stringByAppendingString:tempText]);
//NSLog([#"Main: " stringByAppendingString:text]);
if (isBigger) {
if (draw) {
CGFloat pointX = dirtyRect.size.width + (-1*(dirtyRect.size.width - stringWidth)) + 30;
if (point.x < -1*pointX) {
point.x += pointX;
draw = false;
delay = 100;
text = tempText;
tempText = nil;
}
[text drawAtPoint:point withAttributes:fontDict];
if (point.x < 0) {
NSPoint otherPoint = point;
otherPoint.x += pointX;
if (tempText != nil) {
[tempText drawAtPoint:otherPoint withAttributes:fontDict];
} else {
[text drawAtPoint:otherPoint withAttributes:fontDict];
}
}
} else {
if (nextText != nil) {
tempText = nextText;
nextText = nil;
}
point.x = 0;
[text drawAtPoint:point withAttributes:fontDict];
if (delay <= 0) {
draw = true;
} else {
delay -= 1;
}
}
} else {
dirtyRect.size.width = stringWidth;
point.x = 0;
text = nextText;
[text drawAtPoint:point withAttributes:fontDict];
}
}
#end
EDIT: I added a line to "moveText" to see what "needsDisplay" was, and it turns out that "[self setNeedsDisplay:YES];" is doing nothing. Here is the line I added:
- (void) moveText:(NSTimer *)timer {
point.x = point.x - 1.0f;
[self setNeedsDisplay:YES];
NSLog([NSString stringWithFormat:#"%hhd", [self needsDisplay]]); //This one
}
It just prints 0
I have several UIProgressViews that read the voltage of an external device attached to the iOS device. The view scales it from 0-5 volts and I wanted to know if there was a way to retrieve the current progress/voltage of the UIProgressView and compare it to a threshold that is input by a user. Once this threshold is surpassed; a method I have written should be called.
The problem isn't necessarily the comparison part or calling the method. I am having trouble retrieving a live update of what the current value of the progressview is.
Thanks for your time.
EDIT FOR PART II:
So the problem is I did not code this and it is code pertaining to a certain product called the Nanospark board. This board is an input/output control board for factory systems that is run by various iOS devices.
I cannot quite seem to figure out what the previous coder did within this class:
//
// AnalogVC.m
// NanosparkController
//
#import "AnalogVC.h"
#import "AppDelegate.h"
#interface InputItem : NSObject
#property (weak,nonatomic) UISwitch *onSwitch;
#property (weak,nonatomic) UIProgressView *progressView;
#property (weak,nonatomic) UILabel *valueLabel;
#end
#implementation InputItem
AppDelegate *appDelegate;
+ (id)itemWithSwitch:(id)temp progress:(id)progress label:(id)label
{
InputItem *item = [[InputItem alloc] init];
item.onSwitch = temp;
item.progressView = progress;
item.valueLabel = label;
return item;
}
- (void)setDisconnected
{
self.onSwitch.on = NO;
self.onSwitch.enabled = NO;
self.valueLabel.text = #"0.000 v";
self.progressView.progress = 0;
}
- (void)setOn
{
self.onSwitch.on = YES;
self.onSwitch.enabled = YES;
self.valueLabel.text = #"0.000 v";
self.progressView.progress = 0;
[appDelegate watchPins:#"testing ON"];
}
- (void)setOff
{
self.onSwitch.on = NO;
self.onSwitch.enabled = YES;
self.valueLabel.text = #"0.000 v";
self.progressView.progress = 0;
[appDelegate watchPins:#"testing OFF"];
}
- (void)setValue:(double)value
{
if (self.onSwitch.on)
{
self.valueLabel.text = [NSString stringWithFormat:#"%0.3f v",value];
self.progressView.progress = value/5.0;
if(value > 0.8){
[appDelegate watchPins:#"testing VALUE"];
}
}
}
#end
#interface AnalogVC ()
{
NSArray *_inputItems;
AppDelegate *appDelegate;
NSMutableArray *channel0Values;
UIColor *custom1;
UIColor *custom2;
UIColor *custom3;
UIColor *custom4;
}
#property (nonatomic) NCBoardManager *manager;
#property (weak,nonatomic) IBOutlet UISwitch *inputSwitch0;
#property (weak,nonatomic) IBOutlet UISwitch *inputSwitch1;
#property (weak,nonatomic) IBOutlet UISwitch *inputSwitch2;
#property (weak,nonatomic) IBOutlet UISwitch *inputSwitch3;
#property (weak,nonatomic) IBOutlet UISwitch *inputSwitch4;
#property (weak,nonatomic) IBOutlet UISwitch *inputSwitch5;
#property (weak,nonatomic) IBOutlet UIProgressView *inputProgress0;
#property (weak,nonatomic) IBOutlet UIProgressView *inputProgress1;
#property (weak,nonatomic) IBOutlet UIProgressView *inputProgress2;
#property (weak,nonatomic) IBOutlet UIProgressView *inputProgress3;
#property (weak,nonatomic) IBOutlet UIProgressView *inputProgress4;
#property (weak,nonatomic) IBOutlet UIProgressView *inputProgress5;
#property (weak,nonatomic) IBOutlet UILabel *inputValue0;
#property (weak,nonatomic) IBOutlet UILabel *inputValue1;
#property (weak,nonatomic) IBOutlet UILabel *inputValue2;
#property (weak,nonatomic) IBOutlet UILabel *inputValue3;
#property (weak,nonatomic) IBOutlet UILabel *inputValue4;
#property (weak,nonatomic) IBOutlet UILabel *inputValue5;
#property (weak,nonatomic) IBOutlet UISlider *outputSlider0;
#property (weak,nonatomic) IBOutlet UISlider *outputSlider1;
#property (weak,nonatomic) IBOutlet UIStepper *outputStepper0;
#property (weak,nonatomic) IBOutlet UIStepper *outputStepper1;
#property (weak,nonatomic) IBOutlet UILabel *outputValue0;
#property (weak,nonatomic) IBOutlet UILabel *outputValue1;
- (IBAction)inputChannelChanged:(UISwitch *)sender;
- (IBAction)outputSliderMoved:(UISlider *)sender;
- (IBAction)outputSliderStopped:(UISlider *)sender;
- (IBAction)outputStepperChanged:(UIStepper *)sender;
#end
#implementation AnalogVC{}
//////////////////////////////
#pragma mark View Lifecycle
//////////////////////////////
- (void)viewDidLoad
{
[super viewDidLoad];
NSLog(#"Analog VC loaded");
_inputItems = #[[InputItem itemWithSwitch:_inputSwitch0 progress:_inputProgress0 label:_inputValue0],
[InputItem itemWithSwitch:_inputSwitch1 progress:_inputProgress1 label:_inputValue1],
[InputItem itemWithSwitch:_inputSwitch2 progress:_inputProgress2 label:_inputValue2],
[InputItem itemWithSwitch:_inputSwitch3 progress:_inputProgress3 label:_inputValue3],
[InputItem itemWithSwitch:_inputSwitch4 progress:_inputProgress4 label:_inputValue4],
[InputItem itemWithSwitch:_inputSwitch5 progress:_inputProgress5 label:_inputValue5]];
_manager = [NCBoardManager sharedBoardManager];
__unsafe_unretained AnalogVC *vc = self;
[_manager setAnalogInputHandling:dispatch_get_main_queue()
filter:^(NCAnalogInputs *inputs){ return YES; }
handler:^(NCAnalogInputs *inputs){ [vc setAnalogInputs:inputs]; }];
// Register for notifications
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(boardConnected:)
name:CONNECTED_NOTIFICATION
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(boardDisconnected:)
name:DISCONNECTED_NOTIFICATION
object:nil];
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[self updateAnalogInputs];
[self updateAnalogOutputs];
custom1 = [UIColor whiteColor];
custom2 = [UIColor darkGrayColor];
custom3 = [UIColor blackColor];
custom4 = [UIColor colorWithRed:.97 green:.97 blue:.588 alpha:1.0];
CAGradientLayer *gradient = [CAGradientLayer layer];
gradient.frame = self.view.bounds;
gradient.colors = [NSArray arrayWithObjects:(id)[custom2 CGColor], (id)[custom1 CGColor], (id)[custom2 CGColor], nil];
gradient.startPoint = CGPointMake(0.5, 0);
gradient.endPoint = CGPointMake(0.5, 1.0);
gradient.locations = [NSArray arrayWithObjects: [NSNumber numberWithFloat:0.0], [NSNumber numberWithFloat:0.5], [NSNumber numberWithFloat:1.0], nil];
[self.view.layer insertSublayer:gradient atIndex:0];
[self.inputSwitch0 setOnTintColor:custom4];
[self.inputSwitch1 setOnTintColor:custom4];
[self.inputSwitch2 setOnTintColor:custom4];
[self.inputSwitch3 setOnTintColor:custom4];
[self.inputSwitch4 setOnTintColor:custom4];
[self.inputSwitch5 setOnTintColor:custom4];
[self.inputSwitch0 setTintColor:custom3];
[self.inputSwitch1 setTintColor:custom3];
[self.inputSwitch2 setTintColor:custom3];
[self.inputSwitch3 setTintColor:custom3];
[self.inputSwitch4 setTintColor:custom3];
[self.inputSwitch5 setTintColor:custom3];
self.inputProgress0.trackTintColor = custom3;
self.inputProgress1.trackTintColor = custom3;
self.inputProgress2.trackTintColor = custom3;
self.inputProgress3.trackTintColor = custom3;
self.inputProgress4.trackTintColor = custom3;
self.inputProgress5.trackTintColor = custom3;
self.inputProgress0.progressTintColor = custom4;
self.inputProgress1.progressTintColor = custom4;
self.inputProgress2.progressTintColor = custom4;
self.inputProgress3.progressTintColor = custom4;
self.inputProgress4.progressTintColor = custom4;
self.inputProgress5.progressTintColor = custom4;
self.outputSlider0.minimumTrackTintColor = custom4;
self.outputSlider1.minimumTrackTintColor = custom4;
self.outputSlider0.maximumTrackTintColor = custom3;
self.outputSlider1.maximumTrackTintColor = custom3;
self.outputSlider0.thumbTintColor = custom3;
self.outputSlider1.thumbTintColor = custom3;
if(_manager.isBoardConnected)
{
self.outputStepper0.tintColor = custom4;
self.outputStepper1.tintColor = custom4;
self.outputStepper0.enabled = TRUE;
self.outputStepper1.enabled = TRUE;
self.outputSlider0.enabled = TRUE;
self.outputSlider1.enabled = TRUE;
}
else
{
self.outputStepper0.tintColor = custom2;
self.outputStepper1.tintColor = custom2;
self.outputStepper0.enabled = FALSE;
self.outputStepper1.enabled = FALSE;
self.outputSlider0.enabled = FALSE;
self.outputSlider1.enabled = FALSE;
}
}
//////////////////////////////
#pragma mark Rotation Calls
//////////////////////////////
- (NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationPortrait;
}
- (BOOL)shouldAutorotate
{
return FALSE;
}
//////////////////////////
#pragma mark Board Calls
//////////////////////////
- (void)boardConnected:(NSNotification *)notification
{
[self updateAnalogInputs];
[self updateAnalogOutputs];
self.outputStepper0.enabled = TRUE;
self.outputStepper1.enabled = TRUE;
self.outputSlider0.enabled = TRUE;
self.outputSlider1.enabled = TRUE;
self.outputStepper0.tintColor = custom4;
self.outputStepper1.tintColor = custom4;
}
- (void)boardDisconnected:(NSNotification *)notification
{
[self updateAnalogInputs];
[self updateAnalogOutputs];
self.outputStepper0.enabled = FALSE;
self.outputStepper1.enabled = FALSE;
self.outputSlider0.enabled = FALSE;
self.outputSlider1.enabled = FALSE;
self.outputStepper0.tintColor = custom2;
self.outputStepper1.tintColor = custom2;
}
- (void)updateAnalogInputs
{
uint8_t channel = self.manager.analogInputChannels;
switch (self.manager.analogInputStatus)
{
case NCInputConnected:
// Check if channels we left on
if (channel) self.manager.analogInputChannels = 0;
[_inputItems makeObjectsPerformSelector:#selector(setOff)];
break;
case NCInputDisconnected:
[_inputItems makeObjectsPerformSelector:#selector(setDisconnected)];
break;
case NCInputLiveUpdating:
for (InputItem *item in _inputItems)
{
//if (channel & 1) [item setOn];
//else [item setOff];
channel >>= 1;
}
break;
case NCInputSampling:
[_inputItems makeObjectsPerformSelector:#selector(setDisconnected)];
break;
case NCInputTransfering:
[_inputItems makeObjectsPerformSelector:#selector(setDisconnected)];
break;
}
}
- (void)setAnalogInputs:(NCAnalogInputs *)inputs
{
int i = 0;
uint8_t channels = inputs.channels;
for (InputItem *item in _inputItems)
{
if (channels & 1)
{
[item setValue:[inputs valueForChannel:i]];
}
channels >>= 1;
i++;
}
}
- (void)updateAnalogOutputs
{
BOOL connected = [self.manager isBoardConnected];
self.outputSlider0.value = self.manager.analogOutput0;
self.outputSlider0.enabled = connected;
self.outputStepper0.value = self.outputSlider0.value * 1000;
self.outputStepper0.enabled = connected;
self.outputValue0.text = [NSString stringWithFormat:#"%0.3f v",self.outputSlider0.value];
self.outputSlider1.value = self.manager.analogOutput1;
self.outputSlider1.enabled = connected;
self.outputStepper1.value = self.outputSlider1.value * 1000;
self.outputStepper1.enabled = connected;
self.outputValue1.text = [NSString stringWithFormat:#"%0.3f v",self.outputSlider1.value];
}
///////////////////////////////
#pragma mark IBAction Methods
///////////////////////////////
- (IBAction)inputChannelChanged:(UISwitch *)sender
{
NSLog(#"TEST");
InputItem *item = [_inputItems objectAtIndex:sender.tag];
uint8_t channels = self.manager.analogInputChannels;
if (sender.on)
{
channels |= (1 << sender.tag);
[item setOn];
}
else
{
channels &= ~(1 << sender.tag);
[item setOff];
}
if (!self.manager.analogInputChannels) [self.manager startAnalogLiveUpdating];
else if(!channels) [self.manager stopAnalogLiveUpdating];
self.manager.analogInputChannels = channels;
}
- (IBAction)outputSliderMoved:(UISlider *)sender
{
if (!sender.tag)
{
self.manager.analogOutput0 = sender.value;
self.outputValue0.text = [NSString stringWithFormat:#"%0.3f v",sender.value];
}
else
{
self.manager.analogOutput1 = sender.value;
self.outputValue1.text = [NSString stringWithFormat:#"%0.3f v",sender.value];
}
}
- (IBAction)outputSliderStopped:(UISlider *)sender
{
if (!sender.tag)
{
self.manager.analogOutput0 = sender.value;
self.outputStepper0.value = round(sender.value * 1000.0);
self.outputValue0.text = [NSString stringWithFormat:#"%0.3f v",self.outputStepper0.value/1000.0];
}
else
{
self.manager.analogOutput1 = sender.value;
self.outputStepper1.value = round(sender.value * 1000.0);
self.outputValue1.text = [NSString stringWithFormat:#"%0.3f v",self.outputStepper1.value/1000.0];
}
}
- (IBAction)outputStepperChanged:(UIStepper *)sender
{
float value = sender.value/1000.0;
if (!sender.tag)
{
self.manager.analogOutput0 = value;
self.outputSlider0.value = value;
self.outputValue0.text = [NSString stringWithFormat:#"%0.3f v",value];
}
else
{
self.manager.analogOutput1 = sender.value/1000.0;
self.outputSlider1.value = value;
self.outputValue1.text = [NSString stringWithFormat:#"%0.3f v",value];
}
}
#end
The problem I am having is I cannot figure out how to take values to and from the UIProgressViews that are on the storyboard (which is, like you said, a trivial concept). However with this set up it is rather convoluted.
Second problem is that; I am not sure if there is a way I can debug this as the application only runs when the external device (the nanospark controller board) is connected to the iPod.
The last but final problem I am having is that I am assuming the IBAction InputChannelChanged is being called (cannot debug this regularly with a breakpoint as aforementioned because it requires the external device to run the application), but when I run the application it does everything it should and the buttons react correctly to what the original software developer had coded.
This means that if I add my texting method to the IBAction (by adding [appDelegate watchPins#"TEST"]) it does not send the text to the user, but the buttons do still do what they should have done in concordance to the previous developers' aspirations.... this implies that the IBAction method is indeed being called... but then why isn't my text going through? I know that [appDelegate watchPins:#"TEST"]; should work as I have used it within several of his other classes.
Here is a screenshot displaying the UI of the AnalogVC.m:
http://i.stack.imgur.com/NNpZk.png
Do not feel obligated to answer all of these questions it's just I felt it necessary to provided all three for greater context of the problem. Thanks and sorry for the TL;DR.
EDIT 2: I'd upload the image but I do not have the required minimum reputation.
EDIT 3: I have tried to add another IBAction just to see if the buttons react to that; still nothing even if I copied the exact code from the other working classes.
Solution 1:
You need to call your method when you update the UIProgressView I assume that use are using the setProgress: animated: method somewhere in your code to update the progress view. If so, try this code in the method in which you update the UIProgressView:
float myVoltageFromDevice = self.deviceInput / 5.0; //this can be whatever your input is mapped to 0.0...1.0
//the self.device input variable should be the input from the external device.
if(myFloatFromDevice > myThreshold){ //set my threshold to whatever you would like.
[self doAction]; //do whatever you need to do when the value is surpassed
}else{
[myProgressView setProgress:myVoltageFromDevice animated: NO];
}
Edit:
I commented in the code above //this can be whatever your input is mapped to 0.0...1.0. Just in case this isn't clear, to achieve mapping you would do:
float myVoltageFromDevice = self.deviceInput / 5.0;
because the device input variable should be a value from 0-5 as you said in the OP. This makes the value from 0.0-1.0 which is the range of values that UIProgressView will accept.
Solution 2:
If can't pull off the above (which you really should be able to do), you should use Key Value Observing (KVO) which is detailed in this apple developer doc.
Edit 2:
The code you posted is quite complicated, but I believe that the method that you need to edit is - (void)setAnalogInputs:(NCAnalogInputs *)inputs try changing some of the code to this:
for (InputItem *item in _inputItems)
{
if (channels & 1)
{
if([inputs valueForChannel:i] > myThreshold){
[self doAction]; //Do your action here.
}else{
[item setValue:[inputs valueForChannel:i]];
}
}
channels >>= 1;
i++;
}
The problems is the animation just run one time then cannot repeat again. Do I need to add one more NSTimer in somewhere ?
Anything I missing ? Looking for help and advice. Thanks a lot !
And here is the code.
First, in ViewController.h & ViewController.m
#interface ViewController : UIViewController {
GameView* gameView;
}
- (void)viewDidLoad
{
[super viewDidLoad];
if(gameView == nil) {
gameView = [[GameView alloc] initWithFrame:CGRectMake(0, 0, 320, 480)];
gameView.backgroundColor = [UIColor clearColor];
}
[self.view addSubview:gameView];
[[AppEngine sharedInstance] addSnow:CGPointMake((random() % 320),(random() % -20))];
[[AppEngine sharedInstance] addSnow:CGPointMake((random() % 320),(random() % -20))];
[[AppEngine sharedInstance] addSnow:CGPointMake((random() % 320),(random() % -20))];
[[AppEngine sharedInstance] addSnow:CGPointMake((random() % 320),(random() % -20))];
[[AppEngine sharedInstance] addSnow:CGPointMake((random() % 320),(random() % -20))];
}
In the GameView.h & .m
#interface GameView : UIView <UIAccelerometerDelegate>{
CADisplayLink* displayLink;
}
-(void) timeStep;
- (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
displayLink = [CADisplayLink displayLinkWithTarget:self selector:#selector(timeStep)];
[displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
}
return self;
}
-(void) timeStep {
[[AppEngine sharedInstance] timeStep];
[self setNeedsDisplay];
}
- (void)drawRect:(CGRect)rect {
[[UIImage imageNamed:#"Christmas.jpg"] drawInRect:CGRectMake(0,0,320,480)]; // set the background image
CGContextRef context = UIGraphicsGetCurrentContext();
for(MySnow* snowObject in [AppEngine sharedInstance].snowObjectArray)
{
CGContextSaveGState(context);
CGContextTranslateCTM(context, snowObject.x, snowObject.y);
NSString *imagePath = [NSString stringWithFormat:#"snowflake0%d.png",snowObject.type];
[[UIImage imageNamed: imagePath] drawInRect:CGRectMake(-16,-16,32,32)];
CGContextRestoreGState(context);
}
}
Third, in the snow.h & m
#interface MySnow : NSObject
{
float x,y;
float vx, vy;
float rotSpeed;
float rotation;
int type;
}
#property (nonatomic) float x,y;
#property (nonatomic) float vx, vy, rotSpeed,rotation;
#property (nonatomic) int type;
-(id) initWithStartPoint:(CGPoint) startPoint withType:(int) type;
-(void) timeStep;
#implementation MySnow
#synthesize x,y,vx,vy,rotation,rotSpeed,type;
-(id) initWithStartPoint:(CGPoint) startPoint withType:(int) _type {
self = [super init];
if(self) {
x = startPoint.x;
y = startPoint.y;
vx = RANDOM_FLOAT() * 1 + 0.1;
vy = RANDOM_FLOAT() * 2 + 0.1;
type = _type;
}
return self;
}
-(void) timeStep {
y += vy;
}
Finally, in AppEngine.h & m
#interface AppEngine : NSObject {
NSMutableArray* snowObjectArray;
float ax, ay;
}
#property (readonly) NSMutableArray* snowObjectArray;
#property (nonatomic) float ax,ay;
+(AppEngine*) sharedInstance;
+(void) destoryInstance;
-(void) timeStep;
-(void) addSnow:(CGPoint) point;
static AppEngine* _sharedEngine;
#implementation AppEngine
#synthesize snowObjectArray;
#synthesize ax,ay;
+(AppEngine*) sharedInstance {
if(_sharedEngine == nil)
_sharedEngine = [[AppEngine alloc] init];
return _sharedEngine;
}
+(void) destoryInstance {
if(_sharedEngine != nil) {
_sharedEngine = nil;
}
}
-(id) init {
self = [super init];
if(self) {
snowObjectArray = [[NSMutableArray alloc] init];
}
return self;
}
-(void) addSnow:(CGPoint) point {
int type = (arc4random() % 9) + 1; // random snow image 01 to 09
MySnow* snowObject = [[MySnow alloc] initWithStartPoint:point withType:type];
[snowObjectArray addObject:snowObject];
}
-(void) timeStep {
NSMutableArray* removeArray = [NSMutableArray array];
for(MySnow* item in snowObjectArray) {
[item timeStep];
if(item.y > 400 || item.y < -100)
[removeArray addObject:item];
}
[snowObjectArray removeObjectsInArray:removeArray];
[removeArray removeAllObjects];
}
Is this your code? Can you explain how it starts the animation?
It looks to me like the AppEngine's timeStep method has code that specifically deletes each item in the snowObjectsArray once it reaches some boundary. However, if this is your code, why don't you understand what it does?
EDIT: OK, so this is from a lecture.
If you want the animation to continue, here's what I would do:
Take the last block of code from your viewDidLoad method (the code that creates and adds snow objects) and put it in a separate method. Make viewDidLoad call that method. Let's call the method makeItSnow.
Then, at the end of your AppEngine timeStep method, if the object count in snowObjectArray drops to 0, call makeItSnow.
That approach would make a set of snowflakes start at the top, fall down and disappear, and then another group of snowflakes start. If you want a continuous stream of snowflakes to fall, then change the timeStep method to count the number of snowflake objects it deletes, and at the end of the method add that many snowflakes back to the array. That would cause your program to add a new snowflake as each one disappears.
Yet another approach would be to add a repeating timer to AppEngine, and make that timer create another snowflake. That would keep adding snowflakes on a regular interval.
How can I fix the problem of Incomplete Implementation?
View of Controller.m :
#import "Quiz_GameViewController.h"
#implementation Quiz_GameViewController
#synthesize theQuestion, timer, theScore, theLives, answerOne, answerTwo, answerThree, answerFour, theQuiz
;
-(void)askQuestion
{
// Unhide all the answer buttons.
[answerOne setHidden:NO];
[answerTwo setHidden:NO];
[answerThree setHidden:NO];
[answerFour setHidden:NO];
// Set the game to a "live" question (for timer purposes)
questionLive = YES;
// Set the time for the timer
time = 8.0;
// Go to the next question
questionNumber = questionNumber + 1;
// We get the question from the questionNumber * the row that we look up in the array.
NSInteger row = 0;
if(questionNumber == 1)
{
row = questionNumber - 1;
}
else
{
row = ((questionNumber - 1) * 6);
}
// Set the question string, and set the buttons the the answers
NSString *selected = [theQuiz objectAtIndex:row];
NSString *activeQuestion = [[NSString alloc] initWithFormat:#"Question: %#", selected];
[answerOne setTitle:[theQuiz objectAtIndex:row+1] forState:UIControlStateNormal];
[answerTwo setTitle:[theQuiz objectAtIndex:row+2] forState:UIControlStateNormal];
[answerThree setTitle:[theQuiz objectAtIndex:row+3] forState:UIControlStateNormal];
[answerFour setTitle:[theQuiz objectAtIndex:row+4] forState:UIControlStateNormal];
rightAnswer = [[theQuiz objectAtIndex:row+5] intValue];
// Set theQuestion label to the active question
theQuestion.text = activeQuestion;
// Start the timer for the countdown
timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(countDown) userInfo:nil repeats:YES];
[selected release];
[activeQuestion release];
}
-(void)updateScore
{
// If the score is being updated, the question is not live
questionLive = NO;
[timer invalidate];
// Hide the answers from the previous question
[answerOne setHidden:YES];
[answerTwo setHidden:YES];
[answerThree setHidden:YES];
[answerFour setHidden:YES];
NSString *scoreUpdate = [[NSString alloc] initWithFormat:#"Score: %d", myScore];
theScore.text = scoreUpdate;
[scoreUpdate release];
// END THE GAME.
NSInteger endOfQuiz = [theQuiz count];
if((((questionNumber - 1) * 6) + 6) == endOfQuiz)
{
// Game is over.
if(myScore > 0)
{
NSString *finishingStatement = [[NSString alloc] initWithFormat:#"Game Over!\nNice Game \nYou scored %i!", myScore];
theQuestion.text = finishingStatement;
[finishingStatement release];
}
else
{
NSString *finishingStatement = [[NSString alloc] initWithFormat:#"Game Over!\n You're terrible! \nYou scored %i.", myScore];
theQuestion.text = finishingStatement;
[finishingStatement release];
}
theLives.text = #"";
// Make button 1 appear as a reset game button
restartGame = YES;
[answerOne setHidden:NO];
[answerOne setTitle:#"Restart game!" forState:UIControlStateNormal];
}
else
{
// Give a short rest between questions
time = 3.0;
// Initialize the timer
timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(countDown) userInfo:nil repeats:YES];
}
}
-(void)countDown
{
// Question live counter
if(questionLive==YES)
{
time = time - 1;
theLives.text = [NSString stringWithFormat:#"Time remaining: %i!", time];
if(time == 0)
{
// Loser!
questionLive = NO;
theQuestion.text = #"HAHA now you lost alot of points!";
myScore = myScore - 1000;
[timer invalidate];
[self updateScore];
}
}
// In-between Question counter
else
{
time = time - 1;
theLives.text = [NSString stringWithFormat:#"Next question coming in...%i!", time];
if(time == 0)
{
[timer invalidate];
theLives.text = #"";
[self askQuestion];
}
}
if(time < 0)
{
[timer invalidate];
}
}
- (IBAction)buttonOne
{
if(questionNumber == 0){
// This means that we are at the startup-state
// We need to make the other buttons visible, and start the game.
[answerTwo setHidden:NO];
[answerThree setHidden:NO];
[answerFour setHidden:NO];
[self askQuestion];
}
else
{
NSInteger theAnswerValue = 1;
[self checkAnswer:(int)theAnswerValue];
if(restartGame==YES)
{
// Create a restart game function.
}
}
}
- (IBAction)buttonTwo
{
NSInteger theAnswerValue = 2;
[self checkAnswer:(int)theAnswerValue];
}
- (IBAction)buttonThree
{
NSInteger theAnswerValue = 3;
[self checkAnswer:(int)theAnswerValue];
}
- (IBAction)buttonFour
{
NSInteger theAnswerValue = 4;
[self checkAnswer:(int)theAnswerValue];
}
// Check for the answer (this is not written right, but it runs)
-(void)checkAnswer:(int)theAnswerValue
{
if(rightAnswer == theAnswerValue)
{
theQuestion.text = #"Daaamn";
myScore = myScore + 50;
}
else
{
theQuestion.text = #"hahaha!";
myScore = myScore - 50;
}
[self updateScore];
}
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {
[super viewDidLoad];
questionLive = NO;
restartGame = NO;
theQuestion.text = #"Think you can do it?";
theScore.text = #"Score:0";
theLives.text = #"";
questionNumber = 0;
myScore = 0;
myLives = 0;
[answerOne setTitle:#"I think i can!" forState:UIControlStateNormal];
[answerTwo setHidden:YES];
[answerThree setHidden:YES];
[answerFour setHidden:YES];
[self loadQuiz];
}
-(void)loadQuiz
{
// This is our forced-loaded array of quiz questions.
// FORMAT IS IMPORTANT!!!!
// 1: Question, 2 3 4 5: Answers 1-4 respectively, 6: The right answer
// THIS IS A TERRIBLE WAY TO DO THIS. I will figure out how to do nested arrays to make this better.
NSArray *quizArray = [[NSArray alloc] initWithObjects:#"Who is the president in USA?",#"Me",#"Obama",#"George Bush",#"Justin Bieber",#"2",
#"Capital in Norway?", #"Bergen", #"Trondheim", #"Oslo", #"Bærum", #"3",
#"The right answer is 3!", #"41", #"24", #"3", #"9", #"1",
#"Do I have a cat?", #"Yes", #"No", #"No, you have a dog", #"No, you have a flying hamster", #"4",
#"Baba", #"Daba jaba?", #"Laba daba haba?", #"Saba daba gaba?", #"Haba haba?", #"4",
nil];
self.theQuiz = quizArray;
[quizArray release];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning]; // Releases the view if it doesn't have a superview
// Release anything that's not essential, such as cached data
}
- (void)dealloc {
[theQuestion release];
[theScore release];
[theLives release];
[answerOne release];
[answerTwo release];
[answerThree release];
[answerFour release];
[theQuiz release];
[timer release];
[super dealloc];
}
#end
I'am new here and this is an example script from the internet...I use it to learn the language Objective-C and Cocoa...ViewController.h :
#import <UIKit/UIKit.h>
#interface Quiz_GameViewController : UIViewController {
IBOutlet UILabel *theQuestion;
IBOutlet UILabel *theScore;
IBOutlet UILabel *theLives;
IBOutlet UIButton *answerOne;
IBOutlet UIButton *answerTwo;
IBOutlet UIButton *answerThree;
IBOutlet UIButton *answerFour;
NSInteger myScore;
NSInteger myLives;
NSInteger questionNumber;
NSInteger rightAnswer;
NSInteger time;
NSArray *theQuiz;
NSTimer *timer;
BOOL questionLive;
BOOL restartGame;
}
#property (retain, nonatomic) UILabel *theQuestion;
#property (retain, nonatomic) UILabel *theScore;
#property (retain, nonatomic) UILabel *theLives;
#property (retain, nonatomic) UIButton *answerOne;
#property (retain, nonatomic) UIButton *answerTwo;
#property (retain, nonatomic) UIButton *answerThree;
#property (retain, nonatomic) UIButton *answerFour;
#property (retain, nonatomic) NSArray *theQuiz;
#property (retain, nonatomic) NSTimer *timer;
-(IBAction)buttonOne;
-(IBAction)buttonTwo;
-(IBAction)buttonThree;
-(IBAction)buttonFour;
-(void)checkAnswer;
-(void)askQuestion;
-(void)updateScore;
-(void)loadQuiz;
-(void)countDown;
#end
In your headerfile, you have declared the method -(void)checkAnswer, while in the .m file you have declared it -(void)checkAnswer:(int)theAnswerValue.
This means that your .m file is looking for a method -(void)checkAnswer, which does not exist, and it yields an Incomplete implementation warning. Simply change your declaration in the .h file to - (void)checkAnswer:(int)theAnswerValue, and you'll be fine.
See in .h you have (method with no parameters):
-(void)checkAnswer;
and in .m you have (method with one int parameter):
-(void)checkAnswer:(int)theAnswerValue
Incomplete Implementation means you declared something in .h but didn't implement that in .m.
The signature of checkAnswer is different in you .h and .m
in Quiz_GameViewController.h:
-(void)checkAnswer;
in Quiz_GameViewController.m
-(void)checkAnswer:(int)theAnswerValue
FIX : Change the Quiz_GameViewController.h to:
- (void)checkAnswer:(int)theAnswerValue,
in my game I made a subclass of CCSprite (cocos2d) for my enemies.
Because I want control over animation, from within every instance of this subclass, I had to translate my animation code in my main class, which loads
the enemies, to this subclass.
I found this rather hard but.... after some time it magically started to work.
Unfortunately after creating and setting properties in this subclass I started to have weird crashes. Because they are in cocosDenshion and other places which have nothing to do with my
enemy class and after a research in depth in my code and on the net, I'm convinced its some kind of data corruption and I'm almost completely certain its because I did my enemie class with his animation code completely the wrong way.
To be honest, I cannot even wrap my mind around what is going on here anymore and how this actually works :S...I'm completely stuck. any help is much appreciated!
So my main questions would be: What is the proper way to implement animation in a CCSprite subclass ? / what am I doing wrong here?
simplified my code here: (it triggers the animation every 2 seconds to show how I want
to use it)
#import "cocos2d.h"
#interface Npc : CCSprite
{
CCAction *_runAnimation;
NSString* name;
int strength;
}
#property (nonatomic, retain) CCAction *runAnimation;
#property int strength;
#property (nonatomic, retain) NSString* name;
- (Npc*)loadAnimation;
- (void)animate;
#end
#import "Npc.h"
#implementation Npc
#synthesize runAnimation = _runAnimation;
#synthesize name;
#synthesize strength;
-(id) initWithTexture:(CCTexture2D*)texture rect:(CGRect)rect
{
if( (self=[super initWithTexture:texture rect:rect]))
{
}
return self;
}
- (Npc*)loadAnimation
{
int lastFrame = 11;
NSString *creatureFile = #"vis 1";
[[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:
[NSString stringWithFormat:#"%#.plist", creatureFile]];
CCSpriteBatchNode* sheet = [CCSpriteBatchNode batchNodeWithFile:
[NSString stringWithFormat:#"%#.png", creatureFile]];
self = [Npc spriteWithTexture:sheet.texture];
NSMutableArray* animFrames = [[NSMutableArray alloc] init];
for (int x = 0; x < lastFrame; x++)
{
[animFrames addObject:
[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:
[NSString stringWithFormat:#"%# %d.png", creatureFile, x]]];
}
CCAnimation* anim = [CCAnimation animationWithFrames: animFrames delay: 0.1];
self.runAnimation = [CCAnimate actionWithAnimation:anim restoreOriginalFrame:NO];
[self runAction:_runAnimation];
return self;
}
- (void)animate
{
[self runAction:self.runAnimation];
}
- (void)dealloc
{
[super dealloc];
[name release];
}
#end
#import "HelloWorldLayer.h"
#import "Npc.h"
#implementation HelloWorldLayer
+(CCScene *) scene
{
CCScene *scene = [CCScene node];
HelloWorldLayer *layer = [HelloWorldLayer node];
[scene addChild: layer];
return scene;
}
-(id) init
{
if( (self=[super init]))
{
timer = 0;
creatureTemp = [Npc spriteWithFile:#"Icon.png"];
creature = [creatureTemp loadAnimation];
creature.position = ccp(100,100);
[self addChild:creature];
[self schedule:#selector(nextFrame:)];
}
return self;
}
- (void)nextFrame:(ccTime)dt
{
timer += dt;
if (timer > 2.)
{
[creature animate];
timer = 0.;
}
}
- (void) dealloc
{
[super dealloc];
}
#end
-------------------EDIT--------------------
I changed my code with help of a tutorial by Ray Wenderlich: http://www.raywenderlich.com/3888/how-to-create-a-game-like-tiny-wings-part-1
this is I think much closer to what it should be. Unfortunately it still crashes on my iphone (not the simulator) on SimpleAudioEngine (which I implement right) so I still do something wrong.
on top of the Npc class:
#synthesize batchNode = _batchNode;
the init of the Npc class:
-(id) initNpc
{
if( (self=[super initWithSpriteFrameName:#"vis 1 0.png"]))
{
_normalAnim = [[CCAnimation alloc] init];
NSMutableArray* animFrames = [[NSMutableArray alloc] init];
int lastFrame = 11;
for (int x = 0; x < lastFrame; x++)
{
[animFrames addObject:
[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:
[NSString stringWithFormat:#"vis 1 %d.png", x]]];
}
_normalAnim = [CCAnimation animationWithFrames: animFrames delay: 0.1];
self.runAnimation = [CCAnimate actionWithAnimation:_normalAnim restoreOriginalFrame:NO];
}
return self;
}
and the init of the HelloWorldLayer
-(id) init
{
if( (self=[super init]))
{
timer = 0;
_batchNode = [CCSpriteBatchNode batchNodeWithFile:#"vis 1.png"];
[self addChild:_batchNode];
[[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:#"vis 1.plist"];
creature = [[[Npc alloc] initNpc] autorelease];
creature.position = ccp(200,200);
[_batchNode addChild:creature];
[self schedule:#selector(nextFrame:)];
[[SimpleAudioEngine sharedEngine] preloadEffect:#"super1.mp3"];
}
return self;
}
You're reassigning self in loadAnimation:
self = [Npc spriteWithTexture:sheet.texture];
At that point I stopped reading the code. Since self already is an instance of the Npc class you have to ask yourself why you're doing this in an Npc instance method like loadAnimation.
So, I got it....here is the code:
Npc.h:
#import "cocos2d.h"
#interface Npc : CCSprite
{
CCAction *_runAnimation;
CCAnimation *_normalAnim;
CCAnimate *_normalAnimate;
}
#property (nonatomic, retain) CCAction *runAnimation;
- (void)animate;
- (id)initNpc;
#end
Npc.m
#synthesize runAnimation = _runAnimation;
#synthesize batchNode = _batchNode;
-(id) initNpc
{
if( (self=[super initWithSpriteFrameName:#"vis 1 0.png"]))
{
_normalAnim = [[CCAnimation alloc] init];
NSMutableArray* animFrames = [[NSMutableArray alloc] init];
int lastFrame = 7;
for (int x = 0; x < lastFrame; x++)
{
[animFrames addObject:
[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:
[NSString stringWithFormat:#"vis 1 %d.png", x]]];
}
_normalAnim = [CCAnimation animationWithFrames: animFrames delay: 0.1];
self.runAnimation = [CCAnimate actionWithAnimation:_normalAnim restoreOriginalFrame:NO];
}
return self;
}
- (void)animate
{
[self runAction:_runAnimation];
}
in the HelloWorldLayer.m
-(id) init
{
if( (self=[super init]))
{
_batchNode = [CCSpriteBatchNode batchNodeWithFile:#"vis 1.png"];
[self addChild:_batchNode];
[[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:#"vis 1.plist"];
timer = 0;
creature = [[[Npc alloc] initNpc] autorelease];
creature.position = ccp(200,200);
[_batchNode addChild:creature];
[self schedule:#selector(nextFrame:)];
}
return self;
}
- (void)nextFrame:(ccTime)dt
{
timer += dt;
if (timer > 2.)
{
[creature animate];
timer = 0.;
}
}
And about the weird crashes in cocosDenshion. That is also solved...it turned out to be a known bug in SimpleAudioEngine where it threw exceptions only when I had an exception breakpoint active. Workaround: made a class for my sound and if I need a exception breakpoint, I comment out the sound...
-- have to say, I do would prefer the:
_batchNode = [CCSpriteBatchNode batchNodeWithFile:#"vis 1.png"];
[self addChild:_batchNode];
[[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:#"vis 1.plist"];
inside the Npc class, but that is too advanced oop for me. If anybody knows that, let me know...would be great to know actually, to understand oop better.
But it is not strictly necessary...