Core-Plot unable to plot multiple graphs on one page (iPad) - objective-c

I am trying to display multiple chart's on one screen but i am not able to get it to work. I am trying to get to a point where i have 3 x pieGraphs and 1 x scattered graph on this display.
I have tried: Unable to have two CorePlot graphs show simultaneously but not been able to solve this. I am using the example app from Core-Plot as a base for the design of the code. I see no difference when i try to emulate the solution to that problem in my code.
I am able to display the first pie chart: "matchPieChart" but not the second one "questionsPieChart". It does not look like it even process the second chart.
Without consideration of the other similar problem solution (above) the result is:
The legend on the right side is the one that is associated with the pie that is displayed to the left, i guess it hook up to the second pie that i try to display. It is displayed where the second pie chart should be displayed.
Here is the code execution, see the NSLog in the code:
iPad_matchPieChartConfiguration
numberOfRecordsForPlot:
numberOfRecordsForPlot:
numberForPlot:
numberForPlot:
numberOfRecordsForPlot:
numberOfRecordsForPlot:
legendTitleForPieChart: matchPieChart
legendTitleForPieChart: matchPieChart
iPad_questionsPieChartConfiguration
legendTitleForPieChart: matchPieChart
legendTitleForPieChart: matchPieChart
legendTitleForPieChart: matchPieChart
legendTitleForPieChart: matchPieChart
dataLabelForPlot:
dataLabelForPlot: matchPieChart
dataLabelForPlot:
dataLabelForPlot: matchPieChart
legendTitleForPieChart: matchPieChart
legendTitleForPieChart: matchPieChart
legendTitleForPieChart: matchPieChart
legendTitleForPieChart: matchPieChart
And here is the actual code:
-(void)iPad_matchPieChartConfiguration {
NSLog(#"iPad_matchPieChartConfiguration");
// Set titles
playerName_label.text = playerName;
myString = [[NSString alloc]initWithFormat:#"Total number of Games played: %.0f", nrGamesPlayed];
title_Matches_label.text = myString;
//Create host view
matchChartView = [[CPTGraphHostingView alloc] initWithFrame:[[UIScreen mainScreen]bounds]];
[self.view addSubview:matchChartView];
matchPieGraph = [[CPTXYGraph alloc] initWithFrame:CGRectZero];
matchChartView.hostedGraph = matchPieGraph;
matchPieGraph.plotAreaFrame.masksToBorder = NO;
matchPieGraph.paddingLeft = 10.0;
matchPieGraph.paddingTop = 120.0;
matchPieGraph.paddingRight = 350.0;
matchPieGraph.paddingBottom = 360.0;
matchPieGraph.axisSet = nil;
//====ADD MATCH PIE CHART====//
matchPiePlot = [[CPTPieChart alloc]init];
matchPiePlot.dataSource = self;
matchPiePlot.pieRadius = 100.0;
matchPiePlot.identifier = #"matchPieChart";
matchPiePlot.startAngle = M_PI_4;
matchPiePlot.sliceDirection = CPTPieDirectionCounterClockwise;
matchPiePlot.borderLineStyle = [CPTLineStyle lineStyle];
matchPiePlot.labelOffset = 5.0;
matchPieGraph.titleTextStyle = whiteText;
[matchPieGraph addPlot:matchPiePlot];
// 1 - Get graph instance
CPTGraph *matchGraph = matchChartView.hostedGraph;
// 2 - Create legend
CPTLegend *theMatchLegend = [CPTLegend legendWithGraph:matchGraph];
// 3 - Configure legen
CPTMutableTextStyle *legendMatchTextStyle = [CPTTextStyle textStyle];
legendMatchTextStyle.fontSize = 12.0f;
legendMatchTextStyle.fontName = #"Noteworthy-Bold";
legendMatchTextStyle.color = [CPTColor whiteColor];
theMatchLegend.numberOfColumns = 2;
theMatchLegend.fill = nil;
theMatchLegend.borderLineStyle = nil;
theMatchLegend.cornerRadius = 5.0;
theMatchLegend.textStyle = legendMatchTextStyle;
// 4 - Add legend to graph
matchGraph.legend = theMatchLegend;
matchGraph.legendAnchor = CPTRectAnchorRight;
matchGraph.legendDisplacement = CGPointMake(-460.0, -10.0);
}
-(void)iPad_questionsPieChartConfiguration {
NSLog(#"iPad_questionsPieChartConfiguration");
// Set titles
playerName_label.text = playerName;
myString = [[NSString alloc]initWithFormat:#"Total number of Questions answered: %.0f", nrQuestionsAnswered];
title_Questions_label.text = myString;
//Create host view
questionsChartView = [[CPTGraphHostingView alloc] initWithFrame:[[UIScreen mainScreen]bounds]];
[self.view addSubview:questionsChartView];
questionsPieGraph = [[CPTXYGraph alloc] initWithFrame:CGRectZero];
questionsChartView.hostedGraph = matchPieGraph;
questionsPieGraph.plotAreaFrame.masksToBorder = NO;
questionsPieGraph.paddingLeft = 10.0;
questionsPieGraph.paddingTop = 120.0;
questionsPieGraph.paddingRight = 150.0;
questionsPieGraph.paddingBottom = 360.0;
questionsPieGraph.axisSet = nil;
//====ADD MATCH PIE CHART====//
questionsPiePlot = [[CPTPieChart alloc]init];
questionsPiePlot.dataSource = self;
questionsPiePlot.pieRadius = 100.0;
questionsPiePlot.identifier = #"questionsPieChart";
questionsPiePlot.startAngle = M_PI_4;
questionsPiePlot.sliceDirection = CPTPieDirectionCounterClockwise;
questionsPiePlot.borderLineStyle = [CPTLineStyle lineStyle];
questionsPiePlot.labelOffset = 5.0;
questionsPieGraph.titleTextStyle = whiteText;
[questionsPieGraph addPlot:questionsPiePlot];
// 1 - Get graph instance
CPTGraph *questionsGraph = questionsChartView.hostedGraph;
// 2 - Create legend
CPTLegend *theQuestionsLegend = [CPTLegend legendWithGraph:questionsGraph];
// 3 - Configure legen
CPTMutableTextStyle *legendQuestionsTextStyle = [CPTTextStyle textStyle];
legendQuestionsTextStyle.fontSize = 12.0f;
legendQuestionsTextStyle.fontName = #"Noteworthy-Bold";
legendQuestionsTextStyle.color = [CPTColor whiteColor];
theQuestionsLegend.numberOfColumns = 2;
theQuestionsLegend.fill = nil;
theQuestionsLegend.borderLineStyle = nil;
theQuestionsLegend.cornerRadius = 5.0;
theQuestionsLegend.textStyle = legendQuestionsTextStyle;
// 4 - Add legend to graph
questionsGraph.legend = theQuestionsLegend;
questionsGraph.legendAnchor = CPTRectAnchorRight;
questionsGraph.legendDisplacement = CGPointMake(-160.0, -10.0);
}
- (void)viewDidLoad {
[super viewDidLoad];
playerName_label.text = playerName;
AccessPlayerData *checkPlayerDiffFunction = [AccessPlayerData new];
int diffLevel = [checkPlayerDiffFunction checkPlayersDifficultyLevel:playerName];
switch (diffLevel) {
case 1:
playerDifficulty_label.text = #"Difficuly Level: Children / Easy";
break;
case 2:
playerDifficulty_label.text = #"Difficuly Level : Teenager / Medium";
break;
case 3:
playerDifficulty_label.text = #"Difficuly Level: Adult / Hard";
break;
default:
break;
}
nrGamesPlayed_label.text = [NSString stringWithFormat:#"Total number of games played: %.0f", nrGamesPlayed];
//====IF THIS IS IPAD PROCESS ALL GRAPHS====//
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
double nrOfSingleGames = nrGamesPlayed -(nrGamesWon + nrGamesLost);
double nrOfTotalGames = nrGamesPlayed;
double percentageNrOfSingleGames = (nrOfSingleGames / nrOfTotalGames) * 100;
double percentageNrOfMatchGames = ((nrOfTotalGames - nrOfSingleGames) / nrOfTotalGames) * 100;
NSString *singleGames = [[NSString alloc]initWithFormat:#"%.0f (%.0f%%)", nrOfSingleGames, percentageNrOfSingleGames];
NSString *matchesGames = [[NSString alloc]initWithFormat:#"%.0f (%.0f%%)", (nrOfTotalGames - nrOfSingleGames), percentageNrOfMatchGames];
//=========ADD DATA FOR MATCHES PIE GRAPH==========//
NSMutableArray *contentMatchArray = [NSMutableArray arrayWithObjects:[NSNumber numberWithDouble:nrOfSingleGames], [NSNumber numberWithDouble:(nrOfTotalGames - nrOfSingleGames)], nil];
labelMatchOrder = [[NSArray alloc]initWithObjects:singleGames, matchesGames, nil];
legendMatchOrder = [[NSArray alloc] initWithObjects:#"Single Games", #"Matches", nil];
self.dataForMatchChart = contentMatchArray;
//=========ADD DATA FOR QUESTIONS PIE GRAPH==========//
nrQuestionsWrongAnswers = nrQuestionsAnswered - nrQuestionsCorrectAnswered;
double percentageCorrectAnswers = (nrQuestionsCorrectAnswered / nrQuestionsAnswered) * 100;
double percentageWrongAnswers = (nrQuestionsWrongAnswers / nrQuestionsAnswered) * 100;
NSString *answerCorrect = [[NSString alloc]initWithFormat:#"%.0f (%.0f%%)", nrQuestionsCorrectAnswered, percentageCorrectAnswers];
NSString *answerWrong = [[NSString alloc]initWithFormat:#"%.0f (%.0f%%)", nrQuestionsWrongAnswers, percentageWrongAnswers];
playerName_label.text = playerName;
myString = [[NSString alloc]initWithFormat:#"Total number of questions answered: %.0f",nrQuestionsAnswered];
title_Questions_label.text = myString;
NSMutableArray *contentQuestionsArray = [NSMutableArray arrayWithObjects:[NSNumber numberWithDouble:nrQuestionsWrongAnswers], [NSNumber numberWithDouble:nrQuestionsCorrectAnswered], nil];
labelQuestionsOrder = [[NSArray alloc]initWithObjects:answerWrong, answerCorrect, nil];
legendQuestionsOrder = [[NSArray alloc] initWithObjects:#"Correct answers", #"Wrong answers", nil];
self.dataForQuestionsChart = contentQuestionsArray;
NSLog(#"ContentQuestionsArray: %#", contentQuestionsArray);
//====SET GLOBAL PARAMETERS FOR THE GRAPHs====//
whiteText = [CPTMutableTextStyle textStyle];
whiteText.color = [CPTColor whiteColor];
whiteText.fontSize = 14;
whiteText.fontName = #"Noteworthy-Bold";
[self iPad_matchPieChartConfiguration];
[self iPad_questionsPieChartConfiguration];
}
}
#pragma mark -
#pragma mark Plot Data Source Methods
-(NSString *)legendTitleForPieChart:(CPTPieChart *)pieChart recordIndex:(NSUInteger)index {
if ( [matchPiePlot.identifier isEqual:[NSString stringWithFormat:#"matchPieChart"]] ) {
NSLog(#"legendTitleForPieChart: matchPieChart");
if (index < [legendMatchOrder count]) {
return [legendMatchOrder objectAtIndex:index];
}
}
else if ( [matchPiePlot.identifier isEqual:[NSString stringWithFormat:#"questionsPieChart"]] ) {
NSLog(#"legendTitleForPieChart: questionsPieChart");
}
return #"N/A";
}
-(NSUInteger)numberOfRecordsForPlot:(CPTPlot *)plot {
NSLog(#"numberOfRecordsForPlot:");
if ([plot isKindOfClass:[CPTPieChart class]]) {
return [dataForMatchChart count];
}
else {
return 10; //>>>dummy
}
}
-(NSNumber *)numberForPlot:(CPTPlot *)plot field:(NSUInteger)fieldEnum recordIndex:(NSUInteger)index {
NSLog(#"numberForPlot:");
NSDecimalNumber *num = nil;
if ([plot isKindOfClass:[CPTPieChart class]]) {
if (index >= [dataForMatchChart count]) {
return nil;
}
if (fieldEnum == CPTPieChartFieldSliceWidth) {
num = [dataForMatchChart objectAtIndex:index];
}
else {
num = (NSDecimalNumber *) [NSDecimalNumber numberWithUnsignedInteger:index];
}
}
return num;
}
-(CPTLayer *)dataLabelForPlot:(CPTPlot *)plot recordIndex:(NSUInteger)index {
NSLog(#"dataLabelForPlot:");
CPTTextLayer *label = nil;
if ( [plot.identifier isEqual:[NSString stringWithFormat:#"matchPieChart"]] ) {
NSLog(#"dataLabelForPlot: matchPieChart");
label = [[CPTTextLayer alloc] initWithText:[labelMatchOrder objectAtIndex:index]];
CPTMutableTextStyle *textStyle = [label.textStyle mutableCopy];
matchPiePlot.labelOffset = -80;
textStyle.fontName = #"Noteworthy-Bold";
textStyle.color = [CPTColor whiteColor];
textStyle.fontSize = 16;
label.textStyle = textStyle;
return label;
}
else if ( [plot.identifier isEqual:[NSString stringWithFormat:#"matchPieChart"]] ) {
NSLog(#"dataLabelForPlot: MATCH");
}
return label;
}
//====SET COLOR FOR SLICES IN PIE GRAPH====//
-(CPTFill *)sliceFillForPieChart:(CPTPieChart *)pieChart recordIndex:(NSUInteger)index {
// For index = 0
double red1 = 222.0;
double green1 = 184.0;
double blue1 = 135.0;
float alpha1 = 0.5f;
double red2 = 155.0;
double green2 = 00.0;
double blue2 = 0.0;
float alpha2 = 0.3f;
if (index == 0) {
CPTFill *fill = [CPTFill fillWithColor:[CPTColor colorWithComponentRed:red1 green:green1 blue:blue1 alpha:alpha1]];
return fill;
}
if (index == 1) {
CPTFill *fill = [CPTFill fillWithColor:[CPTColor colorWithComponentRed:red2 green:green2 blue:blue2 alpha:alpha2]];
return fill;
}
return 0;
}
I am really struggling with this and would appreciate help :-)

Change this line
questionsChartView.hostedGraph = matchPieGraph;
to
questionsChartView.hostedGraph = questionsPieGraph;
Also, check how the two hosting views are laid out within their superview (self.view). Make sure both are visible and positioned correctly.

Related

CAEmitterLayer CAEmitterCell animation bug

CAEmitterCell contents picCAEmitterLayer emits multiple CAEmitterCells with specified trajectories. When the trajectory CAEmitterCells fly to the end of time, it will become a particle graph displayed by CAEmitterCells, and then the particle graph will be scattered 360 °. However, only one trajectory particle can be animated completely, but more than two particles will appear. The trajectory particle graph will turn white
Adding a boomEmitterCell will cause the contents of CAEmitterCell in getDogLeftDownEmitterWithImageName and getRedLeftEmitterWithImageName to not display the picture and white blocks
CAEmitterLayer *emitterLayer = [[CAEmitterLayer alloc] init];
emitterLayer.emitterPosition = CGPointMake(self.view.layer.bounds.size.width -100, self.view.layer.bounds.size.height - 100);
emitterLayer.emitterSize = CGSizeMake(50, 100.f);
emitterLayer.emitterShape = kCAEmitterLayerLine;
emitterLayer.emitterMode = kCAEmitterLayerOutline;
emitterLayer.renderMode = kCAEmitterLayerOldestLast;
CAEmitterCell *dogleftEmitterCell = [self getRedLeftEmitterWithImageName:[imageArray objectAtIndex:0]];
CAEmitterCell *redLeftEmitterCell = [self getRedLeftEmitterWithImageName:[imageArray objectAtIndex:0]];
emitterLayer.emitterCells = #[dogleftEmitterCell,redLeftEmitterCell];
[self.view.layer addSublayer:emitterLayer];
//狗头左下
- (CAEmitterCell *)getDogLeftDownEmitterWithImageName:(NSString *)imageName {
CAEmitterCell *emitterCell = [[CAEmitterCell alloc] init];
emitterCell.name = #"左下狗头";
emitterCell.contents = (__bridge id _Nullable)[UIImage imageNamed:#"emoji_6"].CGImage;
//产生频率
emitterCell.birthRate = 1;
//存活时长
emitterCell.lifetime = 0.6;
//速度
emitterCell.velocity = 100;
emitterCell.xAcceleration = -1000.f; // 模拟重力影响
emitterCell.scale = 0.2;
emitterCell.scaleSpeed = 0.25;
emitterCell.emissionLongitude = M_PI_2;
// emitterCell.emissionRange = M_PI_4;
emitterCell.emitterCells = #[[self boomEmitterCell]];
return emitterCell;
}
//红包左上
- (CAEmitterCell *)getRedLeftEmitterWithImageName:(NSString *)imageName {
CAEmitterCell *emitterCell = [[CAEmitterCell alloc] init];
emitterCell.name = #"红包";
emitterCell.contents = (__bridge id _Nullable)[UIImage imageNamed:#"emoji_7"].CGImage;
//产生频率
emitterCell.birthRate = 10;
//存活时长
emitterCell.lifetime = 0.6;
// emitterCell.beginTime = self.beginTime;
//速度
emitterCell.velocity = 100;
emitterCell.yAcceleration = -1000.f; // 模拟重力影响
emitterCell.scale = 0.2;
// emitterCell.scaleRange = 0.06;
emitterCell.scaleSpeed = 0.25;
emitterCell.emissionLongitude = M_PI;
// CAEmitterCell *emitterCell = [self boomEmitterCell];
emitterCell.emitterCells = #[[self boomEmitterCell]];
return emitterCell;
}
- (CAEmitterCell *)boomEmitterCell {
// 爆炸
CAEmitterCell * explodeCell = [CAEmitterCell emitterCell];
explodeCell.name = #"explodeCell";
explodeCell.birthRate = 2.f;
explodeCell.lifetime = 0.6f;
// explodeCell.velocity = 0.f;
// explodeCell.scale = 1.0;
// explodeCell.redSpeed = -1.5; //爆炸的时候变化颜色
// explodeCell.blueRange = 1.5; //爆炸的时候变化颜色
// explodeCell.greenRange = 1.f; //爆炸的时候变化颜色
// explodeCell.birthRate = 1.0;
// explodeCell.velocity = 0;
// explodeCell.scale = 2.5;
// explodeCell.redSpeed =-1.5;
// explodeCell.blueSpeed =+1.5;
// explodeCell.greenSpeed =+1.0;
// explodeCell.lifetime = 0.35;
explodeCell.contents = (__bridge id _Nullable)[[UIImage imageNamed:#"allStart"] CGImage];
// 火花
// CAEmitterCell * sparkCell = [CAEmitterCell emitterCell];
// sparkCell.name = #"sparkCell";
//
// sparkCell.birthRate = 3.f;
// sparkCell.lifetime = 3.f;
// sparkCell.velocity = 125.f;
//// sparkCell.yAcceleration = 75.f; // 模拟重力影响
// sparkCell.emissionRange = M_PI * 2; // 360度
//
// sparkCell.scale = 1.2f;
// sparkCell.contents = (id)[[UIImage imageNamed:#"star_white_stroke"] CGImage];
// sparkCell.redSpeed = 0.4;
// sparkCell.greenSpeed = -0.1;
// sparkCell.blueSpeed = -0.1;
// sparkCell.alphaSpeed = -0.25;
// explodeCell.emitterCells = #[sparkCell];
return explodeCell;
}

Remove exporting button from HighChart Objective-C

Is there anyway to remove the exporting button from the line chart in iOS ?
Below is my code :
HIChartView *chartView = [[HIChartView alloc] initWithFrame:self.lineGraphView2.bounds];
chartView.tintColor = [UIColor greenColor];
HIColor *color = [[HIColor alloc] initWithHexValue:#"283445"];
HIColor *greeColorHex = [[HIColor alloc] initWithHexValue:#"00B84A"];
HIColor *redColorHex = [[HIColor alloc] initWithHexValue:#"A3001F"];
// color = [color initWithHexValue:#"000000"];
HIChart *chart = [[HIChart alloc] init];
chart.plotBackgroundColor = color;
chart.backgroundColor = color;
HICredits *credits = [[HICredits alloc] init];
credits.enabled = #0;
HIExporting *exporting = [[HIExporting alloc] init];
exporting.enabled = #0;
HIOptions *options = [[HIOptions alloc]init];
options.exporting.enabled = false;
HITitle *title = [[HITitle alloc]init];
title.text = #"";
HISubtitle *subtitle = [[HISubtitle alloc]init];
// subtitle.text = #"Source: thesolarfoundation.com";
HIYAxis *yaxis = [[HIYAxis alloc]init];
yaxis.title = [[HITitle alloc]init];
yaxis.title.text = #"";
yaxis.gridLineColor = color;
yaxis.gridLineWidth = #0;
HILegend *legend = [[HILegend alloc]init];
legend.layout = #"vertical";
legend.align = #"right";
legend.verticalAlign = #"middle";
HIPlotOptions *plotoptions = [[HIPlotOptions alloc] init];
plotoptions.series = [[HISeries alloc] init];
plotoptions.series.label = [[HILabel alloc] init];
plotoptions.series.label.connectorAllowed = [[NSNumber alloc] initWithBool:false];
plotoptions.series.lineWidth = #2;
HILine *line1 = [[HILine alloc]init];
line1.name = #"Shares Price";
line1.data = graphPointsMutableArray;
line1.color = greeColorHex;
line1.threshold = #10;
HIResponsive *responsive = [[HIResponsive alloc] init];
HIRules *rules1 = [[HIRules alloc] init];
rules1.condition = [[HICondition alloc] init];
rules1.chartOptions = #{
#"legend" : #{
#"layout": #"horizontal",
#"align": #"center",
#"verticalAlign": #"bottom"
}
};
responsive.rules = [NSMutableArray arrayWithObjects:rules1, nil];
options.title = title;
options.subtitle = subtitle;
options.yAxis = [NSMutableArray arrayWithObject:yaxis];
options.legend = legend;
options.plotOptions = plotoptions;
options.series = [NSMutableArray arrayWithObjects:line1, nil];
options.responsive = responsive;
options.chart = chart;
options.credits = credits;
options.exporting = exporting;
options.exporting.enabled = #0;
options.labels.enabled = #0;
chartView.options = options;
[self.lineGraphView2 addSubview:chartView];
I have read in the documentation to set exporting.enable = false but it's not working.
in viewForHeaderInSection method set exporting = NO
it will hide 3 bars button. see below screenshot for more details :
Below is the solution I found in Swift. Basically, you have to create a HINavigation object, and a HIButtonOptions object. After setting the button options enabled property to false, you set the navigation's button options property to the button options object, and then set your HIOptions object's navigation object to the navigation object you created. My obj-c isn't good enough to try typing it out in obj-c, so below is the Swift version of my solution:
// init your options object
let options = HIOptions()
// hide hamburger button
let navigation = HINavigation() // init navigation object
let buttonOptions = HIButtonOptions() // init button options object
buttonOptions.enabled = false
navigation.buttonOptions = buttonOptions
options.navigation = navigation
you set the exporting to false a couple of times, change that so it is set only one time like that in swift:
options.exporting = HIExporting()
options.exporting.enabled = NSNumber.init(booleanLiteral: false)

For Loop Freeze Obj-C

So this loop runs in the skscene. It works perfectly in my multiplayer game, however.. In the single player mode it isn't working quite so well..
The problem is, it's meant to iterate through the loop performing fast animations. However, the whole thing just freezes and animates at the end of the loop.
for (int i = 0; i < 7; i++) {
//to loop between players
for (int j = 0; j < 4; j++) {
NSString *imageName = [NSString stringWithFormat:#"back"];
NSString *bundle = [[NSBundle mainBundle] pathForResource:imageName ofType:#"png"];
UIImage *image = [[UIImage alloc] initWithContentsOfFile:bundle];
SKTexture *texture = [SKTexture textureWithImage:image];
cardDisplay = [CardSpriteNode spriteNodeWithTexture:texture];
cardDisplay.size = CGSizeMake(104, 144);
cardDisplay.position = _dealPosition;
cardDisplay.zPosition = zPosCount;
zPosCount++;
cardDisplay.userInteractionEnabled = YES;
cardDisplay.name = #"cardBack";
[self addChild:cardDisplay];
CGPoint moveToPosition;
//change position to deal to
if (j == 0) {
moveToPosition = position1;
}
else if (j == 1) {
moveToPosition = position2;
}
else if (j == 2) {
moveToPosition = position3;
}
else if (j == 3) {
moveToPosition = position4;
}
[cardDisplay runAction:[SKAction moveTo:moveToPosition duration:0.3]];
[cardDisplay runAction:[SKAction fadeOutWithDuration:0.4]];
[NSThread sleepForTimeInterval:0.1];
if (i == 6 && j == 4 - 1) {
SKNode *node = [self childNodeWithName:#"cardBack"];
[node removeAllChildren];
for (int p = 0; p < [playerCards count]; p++) {
addBegin = p * (cardDisplay.size.width / 3.0);
NSString *imageName = [NSString stringWithFormat:#"%#", playerCards[p]];
NSString *bundle = [[NSBundle mainBundle] pathForResource:imageName ofType:#"png"];
UIImage *image = [[UIImage alloc] initWithContentsOfFile:bundle];
SKTexture *texture = [SKTexture textureWithImage:image];
cardDisplay = [CardSpriteNode spriteNodeWithTexture:texture];
cardDisplay.size = CGSizeMake(104, 144);
cardDisplay.anchorPoint = CGPointMake(0.5, 0.5);
cardDisplay.position = CGPointMake(-self.frame.size.width/2.8 + addBegin, -300);
cardDisplay.zPosition = 1;
cardDisplay.userInteractionEnabled = NO;
cardDisplay.name = [NSString stringWithFormat:#"%#", playerCards[p]];
[self addChild:cardDisplay];
CGPoint moveToNewPosition = CGPointMake(-self.frame.size.width/2.8 + addBegin, -218);
[cardDisplay runAction:[SKAction moveTo:moveToNewPosition duration:1]];
[NSThread sleepForTimeInterval:0.2];
}
}
}
}
Now like I say, this works fine in my other skscene, but in this one it doesn't and as far as I can see everything is initialised.
Grand Central Dispatch (GCD)
From Apple's documentation:
Grand Central Dispatch (GCD) comprises language features, runtime libraries, and system enhancements that provide systemic, comprehensive improvements to the support for concurrent code execution on multicore hardware in iOS and OS X.
To use GCD is quite simple. Here's an example of your code being executed on a separate thread using GCD.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
for (int i = 0; i < 7; i++) {
//to loop between players
for (int j = 0; j < 4; j++) {
NSString *imageName = [NSString stringWithFormat:#"back"];
NSString *bundle = [[NSBundle mainBundle] pathForResource:imageName ofType:#"png"];
UIImage *image = [[UIImage alloc] initWithContentsOfFile:bundle];
SKTexture *texture = [SKTexture textureWithImage:image];
cardDisplay = [CardSpriteNode spriteNodeWithTexture:texture];
cardDisplay.size = CGSizeMake(104, 144);
cardDisplay.position = _dealPosition;
cardDisplay.zPosition = zPosCount;
zPosCount++;
cardDisplay.userInteractionEnabled = YES;
cardDisplay.name = #"cardBack";
dispatch_async(dispatch_get_main_queue(), ^(void){
[self addChild:cardDisplay];
});
CGPoint moveToPosition;
//change position to deal to
if (j == 0) {
moveToPosition = position1;
}
else if (j == 1) {
moveToPosition = position2;
}
else if (j == 2) {
moveToPosition = position3;
}
else if (j == 3) {
moveToPosition = position4;
}
[cardDisplay runAction:[SKAction moveTo:moveToPosition duration:0.3]];
[cardDisplay runAction:[SKAction fadeOutWithDuration:0.4]];
[NSThread sleepForTimeInterval:0.1];
if (i == 6 && j == 4 - 1) {
SKNode *node = [self childNodeWithName:#"cardBack"];
[node removeAllChildren];
for (int p = 0; p < [playerCards count]; p++) {
addBegin = p * (cardDisplay.size.width / 3.0);
NSString *imageName = [NSString stringWithFormat:#"%#", playerCards[p]];
NSString *bundle = [[NSBundle mainBundle] pathForResource:imageName ofType:#"png"];
UIImage *image = [[UIImage alloc] initWithContentsOfFile:bundle];
SKTexture *texture = [SKTexture textureWithImage:image];
cardDisplay = [CardSpriteNode spriteNodeWithTexture:texture];
cardDisplay.size = CGSizeMake(104, 144);
cardDisplay.anchorPoint = CGPointMake(0.5, 0.5);
cardDisplay.position = CGPointMake(-self.frame.size.width/2.8 + addBegin, -300);
cardDisplay.zPosition = 1;
cardDisplay.userInteractionEnabled = NO;
cardDisplay.name = [NSString stringWithFormat:#"%#", playerCards[p]];
dispatch_async(dispatch_get_main_queue(), ^(void){
[self addChild:cardDisplay];
});
CGPoint moveToNewPosition = CGPointMake(-self.frame.size.width/2.8 + addBegin, -218);
[cardDisplay runAction:[SKAction moveTo:moveToNewPosition duration:1]];
[NSThread sleepForTimeInterval:0.2];
}
}
}
}
});
You'll notice in some places I used:
dispatch_async(dispatch_get_main_queue(), ^(void){
[self addChild:cardDisplay];
});
This will always contain code that will affect the UI; all UI code must be executed on the main thread.
[self performSelectorInBackground:#selector(dealCards) withObject:self];
Not sure as to why, but it works.
Do not use this answer.

Calling an unusual method in initWithSize

I've found code for making a rope in my Sprite Kit game. I'll post it below. Problem is, the method header is very long & has a syntax that I'm unable to call upon in my initWithSize method. I tried writing [self addRopeJointItems]; but to no avail. Yes. I am new to objective-c. Hope someone can help out.
Code:
+(void)addRopeJointItems:(CGPoint)leftStartPosition countJointElements:(int)countJointElements game:(SKScene*)game
{
int itemJointWidth = 25;
//Left Physics Anchor
SKSpriteNode * leftAnchor = [SKSpriteNode spriteNodeWithColor:[SKColor clearColor] size:CGSizeMake(1, 1)];
leftAnchor.position = CGPointMake(leftStartPosition.x, leftStartPosition.y);
//leftAnchor.size = CGSizeMake(1, 1);
leftAnchor.zPosition = 2;
leftAnchor.physicsBody = [SKPhysicsBody
bodyWithRectangleOfSize:
leftAnchor.size];
leftAnchor.physicsBody.affectedByGravity = false;
leftAnchor.physicsBody.mass = 99999999999;
[game addChild:leftAnchor];
//add RopeElements
for (int i=0; i<countJointElements; i++)
{
SKSpriteNode * item = [SKSpriteNode spriteNodeWithImageNamed:#"rope_ring.png"];
item.name = [NSString stringWithFormat:#"ropeitem_%d", i];
item.position = CGPointMake(leftStartPosition.x + (i*itemJointWidth) + itemJointWidth/2, leftStartPosition.y+60);
item.size = CGSizeMake(itemJointWidth + 5, 5);
item.zPosition = 2;
item.physicsBody = [SKPhysicsBody
bodyWithRectangleOfSize:
item.size];
item.physicsBody.categoryBitMask = kNilOptions;
[game addChild:item];
//Add Joint to the element before
SKPhysicsBody* bodyA;
if (i == 0)
{
bodyA = leftAnchor.physicsBody;
}
else
{
bodyA = [game childNodeWithName:[NSString stringWithFormat:#"ropeitem_%d", i-1]].physicsBody;
}
SKPhysicsJointPin* joint = [SKPhysicsJointPin jointWithBodyA:bodyA bodyB:item.physicsBody anchor:CGPointMake((item.position.x - item.size.width/2) + 5, item.position.y)];
[game.physicsWorld addJoint:joint];
}
//Right Physics Anchor
SKSpriteNode * rightAnchor = [SKSpriteNode spriteNodeWithColor:[SKColor clearColor] size:CGSizeMake(1, 1)];
rightAnchor.position = CGPointMake((leftStartPosition.x + (countJointElements*itemJointWidth)),
leftStartPosition.y+60);
//rightAnchor.size = CGSizeMake(1, 1);
rightAnchor.zPosition = 2;
rightAnchor.physicsBody = [SKPhysicsBody
bodyWithRectangleOfSize:
rightAnchor.size];
rightAnchor.physicsBody.affectedByGravity = false;
rightAnchor.physicsBody.mass = 99999999999;
[game addChild:rightAnchor];
//Add the Last Joint
SKPhysicsJointPin* jointLast = [SKPhysicsJointPin jointWithBodyA:[game childNodeWithName:[NSString stringWithFormat:#"ropeitem_%d", countJointElements - 1]].physicsBody
bodyB:rightAnchor.physicsBody
anchor:rightAnchor.position];
[game.physicsWorld addJoint:jointLast];
}
You can do two things here:-
1) Either change your method to instance method with prefix (-). If you want call as instance method with self
-(void)addRopeJointItems:(CGPoint)leftStartPosition countJointElements:(int)countJointElements game:(SKScene*)game
2)Or follow #Andrey Chernukha comments as
[ClassName addRopeJointItems:leftStartPosition countJointElements:elements game:game];

Box2D/Cocos2D: Errors in CreateFixture

i'm programming a little game. you can shoot little bullets which should disappear when hitting an object. the problem is when i destroy the bodies (directly or first storing them into an array) i get errors within the CreateFixture() function for creating new bullets.
The code:
-(void)tick:(ccTime)deltaTime {
if(canShoot)
[self performPistol];
[self updatePositions:deltaTime];
[self collisionDetection];
}
-(void)updatePositions:(ccTime)deltaTime {
int32 velocityIterations = 8;
int32 positionIterations = 1;
world->Step(deltaTime, velocityIterations, positionIterations);
for(id object in _objectsToDelete) {
b2Body *body = (b2Body*)[object pointerValue];
[self removeChild:((CCSprite*)body->GetUserData()) cleanup:YES];
world->DestroyBody((b2Body*)[object pointerValue]);
}
[_objectsToDelete removeAllObjects];
}
-(void)collisionDetection {
for (b2Contact* c = world->GetContactList(); c; c = c->GetNext()) {
b2Body *a = c->GetFixtureA()->GetBody();
b2Body *b = c->GetFixtureB()->GetBody();
CCSprite *aSprite = (CCSprite*)a->GetUserData();
CCSprite *bSprite = (CCSprite*)b->GetUserData();
if([[aSprite class] isSubclassOfClass:[Bullet class]]) {
if([[bSprite class] isSubclassOfClass:[Zombie class]]) {
Zombie *myZombie = (Zombie*)bSprite;
myZombie.hp -= [(Bullet*)aSprite strength];
if(myZombie.hp <= 0) {
[_objectsToDelete addObject:[NSValue valueWithPointer:b]];
}
}
[_objectsToDelete addObject:[NSValue valueWithPointer:a]];
} else if([[bSprite class] isSubclassOfClass:[Bullet class]]) {
if([[aSprite class] isSubclassOfClass:[Zombie class]]) {
Zombie *myZombie = (Zombie*)aSprite;
myZombie.hp -= [(Bullet*)bSprite strength];
if(myZombie.hp <= 0) {
[_objectsToDelete addObject:[NSValue valueWithPointer:a]];
}
}
[_objectsToDelete addObject:[NSValue valueWithPointer:b]];
}
}
}
-(void)performPistol {
float degreeRadians = _myRotation*(M_PI/180.0);
CGPoint normalVector = ccp(cosf(degreeRadians),sinf(degreeRadians));
Bullet *bullet = [[Bullet alloc] initWithFile:#"bullet_line.png"];
bullet.strength = 1;
bullet.position = ccp(_myPosition.x+(normalVector.x*25.0),_myPosition.y+(normalVector.y*25.0));
bullet.rotation = _myRotation*(-1);
b2BodyDef bodyDef;
bodyDef.type = b2_dynamicBody;
bodyDef.bullet = true;
bodyDef.position.Set(bullet.position.x/PTM_RATIO, bullet.position.y/PTM_RATIO);
bodyDef.userData = bullet;
b2Body *body = world->CreateBody(&bodyDef);
// Define another box shape for our dynamic body.
b2PolygonShape box;
box.SetAsBox(6.25/PTM_RATIO, 0.5/PTM_RATIO);
// Define the dynamic body fixture.
b2FixtureDef fixtureDef;
fixtureDef.shape = &box;
fixtureDef.density = 1.0f;
fixtureDef.friction = 0.3f;
fixtureDef.filter.categoryBits = MASK_PLAYER;
fixtureDef.filter.maskBits = MASK_ENEMY | MASK_WALL;
body->CreateFixture(&fixtureDef);
body->SetLinearVelocity(b2Vec2(normalVector.x*50.0,normalVector.y*50.0));
body->SetTransform(body->GetPosition(), CC_DEGREES_TO_RADIANS(-bullet.rotation));
[self addChild:bullet];
}
Why are there errors in the CreateFixture() function. end not always the same sometimes an assert error sometimes an exc_bad_access?
thanks