Using the vertical bar chart sample as a start, I created a chart whose y values are 0..1, x values 1..n but the x label index supplied for CPTBarPlotFieldBarLocation cell of my data source doesn't appear; I don't use y-axis labels.
I suspect I'm clipping them. Is there a way, like in the old IB, to draw the various graph region's bounding rect?
The x-axis plot labels are a non-numeric string as in the example. What did I break? Here's my setup
//
// InfoBarView.m
#import "InfoBarView.h"
// Item index to color mapping for legend symbols not item related
static NSUInteger fldMapping[] = { 5, 6, 7, 0 };
static const BOOL kUseHorizontalBars = NO;
static NSArray <__kindof NSString *> const* kTargets = nil;
static NSArray <__kindof NSString *> const* kGetters = nil;
#interface BarChart()
#property (nonatomic, readwrite, strong, nullable) CPTPlotSpaceAnnotation * symbolTextAnnotation;
#end
#implementation BarChart
#synthesize symbolTextAnnotation;
#synthesize plotData;
+ (void)initialize
{
kTargets = [#[ #"grpA" , #"grpB", #"grpC", #"grpD" ] retain];
kGetters = [#[ #"fldA", #"fldB", #"fldC", #"fldD" ] retain];
}
- (void)awakeFromNib
{
// Get our orig scaling
[super awakeFromNib];
}
- (void)killGraph
{
if ( self.graphs.count )
{
CPTGraph * graph = self.defaultGraph;
CPTPlotSpaceAnnotation *annotation = self.symbolTextAnnotation;
if ( annotation )
{
[graph.plotAreaFrame.plotArea removeAnnotation:annotation];
self.symbolTextAnnotation = nil;
}
}
[super killGraph];
}
- (void)generateData
{
InfoBarView * barView = (id)[[self defaultLayerHostingView] superview];
InfoController * controller = barView.controller;
NSUInteger rndx = controller.barDataRanking;
NSArray * rankings = #[ #"Rank", #"Runs" ];
GroupItem * group = controller.group;
CPTGraph * graph = [self defaultGraph];
CPTPlotSpaceAnnotation * annotation = self.symbolTextAnnotation;
if ( annotation )
{
if (graph)
{
[graph.plotAreaFrame.plotArea removeAnnotation:annotation];
self.symbolTextAnnotation = nil;
}
}
// Update X title with new controller index
if (graph)
{
graph.title = [NSString stringWithFormat:#"Past Performances by %#", rankings[rndx]];
}
// Figure out our rank selector
NSString * rankSelectorName = [NSString stringWithFormat:#"%#%#Compare:",
kTargets[controller.barDataIndex],
rankings[rndx]];
SEL dataRanking = NSSelectorFromString(rankSelectorName);
self.plotData = (id)[group.items sortedArrayUsingSelector:dataRanking];
}
- (void)renderInGraphHostingView:(nonnull CPTGraphHostingView *)hostingView
withTheme:(nullable CPTTheme *)theme
animated:(BOOL)animated
{
#if TARGET_OS_SIMULATOR || TARGET_OS_IPHONE
CGRect bounds = hostingView.bounds;
#else
CGRect bounds = NSRectToCGRect(hostingView.bounds);
#endif
InfoController * controller = ((InfoBarView *)hostingView.superview).controller;
CPTGraph * graph = [[[CPTXYGraph alloc] initWithFrame:bounds] autorelease];
NSString * titles = #"fldA fldB fldC fldD";
GroupItem * group = controller.group;
CPTBarPlot * barPlot;
// Initially we default by rank
self.title = #"Past Performances by Rank";
[self addGraph:graph toHostingView:hostingView];
graph.plotAreaFrame.masksToBorder = NO;
if ( kUseHorizontalBars )
{
graph.plotAreaFrame.paddingBottom += self.titleSize;
}
else
{
graph.plotAreaFrame.paddingLeft += self.titleSize;
}
// Add plot space for bar charts
CPTXYPlotSpace * barPlotSpace = (CPTXYPlotSpace *)graph.defaultPlotSpace;
[barPlotSpace setScaleType:CPTScaleTypeCategory forCoordinate:CPTCoordinateX];
if ( kUseHorizontalBars )
{
barPlotSpace.xRange = [CPTPlotRange plotRangeWithLocation:#(-10.0) length:#120.0];
barPlotSpace.yRange = [CPTPlotRange plotRangeWithLocation:#(-1.0) length:#11.0];
}
else
{
barPlotSpace.xRange = [CPTPlotRange plotRangeWithLocation:#(-0.5) length:#(group.itemCount)];
barPlotSpace.yRange = [CPTPlotRange plotRangeWithLocation:#(-0.05) length:#1.0];
}
barPlotSpace.allowsUserInteraction = YES;
[graph addPlotSpace:barPlotSpace];
barPlotSpace.delegate = self;
// Create grid line styles
CPTMutableLineStyle * majorGridLineStyle = [CPTMutableLineStyle lineStyle];
majorGridLineStyle.lineWidth = 1.0;
majorGridLineStyle.lineColor = [[CPTColor grayColor] colorWithAlphaComponent:0.75];
CPTMutableLineStyle * minorGridLineStyle = [CPTMutableLineStyle lineStyle];
minorGridLineStyle.lineWidth = 1.0;
minorGridLineStyle.lineColor = [[CPTColor whiteColor] colorWithAlphaComponent:0.25];
// Create axes
CPTXYAxisSet * axisSet = (CPTXYAxisSet *)graph.axisSet;
CPTXYAxis * x = axisSet.xAxis;
{
x.majorIntervalLength = (kUseHorizontalBars ? #10.0 : #1.0);
x.minorTicksPerInterval = (kUseHorizontalBars ? 9 : 0);
x.orthogonalPosition = (kUseHorizontalBars ? #(-0.5) : #0.0);
x.majorGridLineStyle = majorGridLineStyle;
x.minorGridLineStyle = minorGridLineStyle;
x.axisLineStyle = nil;
x.majorTickLineStyle = nil;
x.minorTickLineStyle = nil;
x.labelOffset = self.titleSize * CPTFloat(2.5);
if ( kUseHorizontalBars )
{
x.visibleRange = [CPTPlotRange plotRangeWithLocation:#0.0 length:#10.0];
x.gridLinesRange = [CPTPlotRange plotRangeWithLocation:#(-0.5) length:#(group.itemCount)];
}
else
{
x.visibleRange = [CPTPlotRange plotRangeWithLocation:#(-0.5) length:#(group.itemCount)];
x.gridLinesRange = [CPTPlotRange plotRangeWithLocation:#0.0 length:#(1.0)];
}
x.plotSpace = barPlotSpace;
}
CPTXYAxis * y = axisSet.yAxis;
{
y.majorIntervalLength = (kUseHorizontalBars ? #1.0 : #10.0);
y.minorTicksPerInterval = (kUseHorizontalBars ? 0 : 9);
y.orthogonalPosition = (kUseHorizontalBars ? #0.0 : #(-0.5) );
y.preferredNumberOfMajorTicks = 8;
y.majorGridLineStyle = majorGridLineStyle;
y.minorGridLineStyle = minorGridLineStyle;
y.axisLineStyle = nil;
y.majorTickLineStyle = nil;
y.minorTickLineStyle = nil;
y.labelOffset = self.titleSize * CPTFloat(0.175);
y.titleLocation = (kUseHorizontalBars ? #55.0 : #(group.itemCount-1));
if ( kUseHorizontalBars )
{
y.visibleRange = [CPTPlotRange plotRangeWithLocation:#(-0.5) length:#10.0];
y.gridLinesRange = [CPTPlotRange plotRangeWithLocation:#0.0 length:#100.0];
}
else
{
y.visibleRange = [CPTPlotRange plotRangeWithLocation:#(-0.5) length:#(group.itemCount)];
y.gridLinesRange = [CPTPlotRange plotRangeWithLocation:#(-0.5) length:#(group.itemCount)];
}
y.title = titles;
y.titleOffset = self.titleSize * CPTFloat(0.25);
[barPlotSpace addCategory:title[seg] forCoordinate:CPTCoordinateY];
y.plotSpace = barPlotSpace;
}
// Set axes
graph.axisSet.axes = #[x, y];
// Create a shared bar line style
CPTMutableLineStyle * barLineStyle = [[[CPTMutableLineStyle alloc] init] autorelease];
barLineStyle.lineWidth = 1.0;
barLineStyle.lineColor = [CPTColor whiteColor];
// Marshall Y axis into individual plot identifiers
NSArray * title = [titles componentsSeparatedByString:#" "];
CPTMutableTextStyle * blackTextStyle = [CPTMutableTextStyle textStyle];
blackTextStyle.color = [CPTColor blackColor];
// Create bar plot(s)
for (int seg=0; seg<title.count; seg++)
{
barPlot = [[[CPTBarPlot alloc] init] autorelease];
barPlot.lineStyle = barLineStyle;
barPlot.fill = [CPTFill fillWithColor:[CPTColor colorAtIndex:seg]];
barPlot.barBasesVary = YES;
barPlot.barCornerRadius = 4.0;
barPlot.barWidth = #0.5;
barPlot.barsAreHorizontal = kUseHorizontalBars;
barPlot.dataSource = self;
barPlot.delegate = self;
barPlot.identifier = [NSString stringWithFormat:#"%#,%d",title[seg],seg],
barPlot.labelTextStyle = blackTextStyle;
barPlot.labelOffset = 0.0;
[graph addPlot:barPlot toPlotSpace:barPlotSpace];
NSLog(#"render:%#", barPlot.identifier);
}
// Add X category per slot
for (Item * item in plotData)
{
[barPlotSpace addCategory:item.numb forCoordinate:CPTCoordinateX];
}
}
#pragma mark -
#pragma mark Plot Delegate
- (void)Plot:(nonnull CPTPlot *)plot dataLabelWasSelectedAtRecordIndex:(NSUInteger)index
{
// NSString * barID = (NSString *)[[(id)plot.identifier componentsSeparatedByString:#","] lastObject];
NSLog(#"Data label for '%#' was selected at record %d.", plot.identifier, (int)index);
}
- (CPTLayer *)dataLabelForPlot:(CPTPlot *)plot recordIndex:(NSUInteger)index;
{
InfoBarView * barView = (id)[[self defaultLayerHostingView] superview];
InfoController * controller = barView.controller;
GroupItem * group = controller.group;
int sndx = index % group.itemCount;
Item * item = (Item *)[self.plotData objectAtIndex:sndx];
CPTMutableTextStyle * textStyle = [CPTMutableTextStyle textStyle];
textStyle.color = [CPTColor colorAtIndex:item.foreRGB];
textStyle.textAlignment = CPTTextAlignmentCenter;
textStyle.fontSize = 24;
plot.labelOffset = 0;
CPTMutableShadow * shadow = [CPTMutableShadow shadow];
shadow.shadowColor = [CPTColor blackColor];//colorAtIndex:item.backRGB];
shadow.shadowOffset = CGSizeMake(1,-1);
shadow.shadowBlurRadius = 2.0f;
plot.labelShadow = shadow;
CPTTextLayer * textLayer = [[CPTTextLayer alloc] initWithText:item.numb.squish style:textStyle];
return [textLayer autorelease];
}
- (void)barPlot:(CPTBarPlot *)plot barWasSelectedAtRecordIndex:(NSUInteger)index
{
CGFloat floor = [[self valueForPlot:plot field:CPTBarPlotFieldBarBase recordIndex:index] doubleValue];
CGFloat value = [[self valueForPlot:plot field:CPTBarPlotFieldBarTip recordIndex:index] doubleValue];
CGFloat runs = 0;
NSString * barID = (NSString *)[[(id)plot.identifier
componentsSeparatedByString:#","] lastObject];
InfoBarView * barView = (id)[[self defaultLayerHostingView] superview];
InfoController * controller = barView.controller;
GroupItem * group = controller.group;
int fndx = [barID intValue];
int sndx = index % group.itemCount;
Item * item = (Item *)[self.plotData objectAtIndex:sndx];
SEL dataItem = NSSelectorFromString(kTargets[controller.barDataIndex]);
DataItem * data = [item performSelector:dataItem];
runs = [[data fldD] doubleValue];
NSLog(#"BarSelected %# %# record:%lu. base:%.2f value:%.2f",
plot.identifier, data.name, index, floor, value);
CPTGraph * graph = [self defaultGraph];
CPTPlotSpaceAnnotation * annotation = self.symbolTextAnnotation;
if ( annotation )
{
[graph.plotAreaFrame.plotArea removeAnnotation:annotation];
self.symbolTextAnnotation = nil;
}
// Setup a style for the annotation
CPTMutableTextStyle * hitAnnotationTextStyle = [CPTMutableTextStyle textStyle];
hitAnnotationTextStyle.color = [CPTColor colorAtIndex:fldMapping[fndx]];
hitAnnotationTextStyle.fontSize = 16.0;
hitAnnotationTextStyle.fontName = #"Helvetica-Bold";
// Determine point of symbol in plot coordinates
NSNumber * x = #(index);
NSNumber * y = #(0.03 + (floor / runs));
CPTNumberArray * anchorPoint = (kUseHorizontalBars ? #[y, x] : #[x, y]);
// Add annotation
// First make a string for the y value
NSString * yString = [[NSNumberFormatter withFormat:#"#,###"] stringFromNumber:#(value)];
// Now add the annotation to the plot area
CPTPlotSpace * space = plot.plotSpace;
if ( space )
{
CPTTextLayer * textLayer = [[CPTTextLayer alloc] initWithText:yString style:hitAnnotationTextStyle];
annotation = [[CPTPlotSpaceAnnotation alloc] initWithPlotSpace:space anchorPlotPoint:anchorPoint];
annotation.contentLayer = [textLayer autorelease];
annotation.displacement = CGPointMake(0.0, 0.0);
self.symbolTextAnnotation = annotation;
[graph.plotAreaFrame.plotArea addAnnotation:[annotation autorelease]];
}
}
#pragma mark Plot DataSource
- (NSUInteger)numberOfRecordsForPlot:(nonnull CPTPlot *)plot
{
InfoBarView * barView = (id)[[self defaultLayerHostingView] superview];
InfoController * controller = barView.controller;
GroupItem * group = controller.group;
return group.itemCount;
}
- (nullable id)numberForPlot:(nonnull CPTPlot *)plot field:(NSUInteger)fieldEnum recordIndex:(NSUInteger)index
{
NSString * barID = (NSString *)[[(id)plot.identifier componentsSeparatedByString:#","] lastObject];
InfoBarView * barView = (id)[[self defaultLayerHostingView] superview];
InfoController * controller = barView.controller;
GroupItem * group = controller.group;
int fndx = [barID intValue];
int sndx = index % group.itemCount;
Item * item = (Item *)[self.plotData objectAtIndex:sndx];
SEL dataItem = NSSelectorFromString(kTargets[controller.barDataIndex]);
NSString * getName = kGetters[fndx];
SEL getter = NSSelectorFromString(getName);
SEL fldD = #selector(fldD);
CGFloat runs, base=0, value=0;
DataItem * data;
id num=nil;
// First get which data data item we're after
data = [item performSelector:dataItem];
runs = [[data performSelector:fldD] floatValue];
// Now fetch its getter
switch ( fieldEnum )
{
case CPTBarPlotFieldBarLocation:
num = item.numb;
break;
case CPTBarPlotFieldBarTip:
// Build base for this tip
for (int seg=0; seg < fndx; seg++)
{
value += [[data performSelector:NSSelectorFromString(kGetters[seg])] floatValue];
}
// Add this 'tip' value unless it's the total
if (fndx == 3)
num = #(1.0f);
else
{
value += [[data performSelector:getter] floatValue];
num = #(value/runs);
}
break;
case CPTBarPlotFieldBarBase:
// Calc base by sum prior fields
for (int seg=0; seg < fndx; seg++)
{
base += [[data performSelector:NSSelectorFromString(kGetters[seg])] floatValue];
}
num = #(base/runs);
}
return num;
}
- (nullable id)valueForPlot:(nonnull CPTPlot *)plot field:(NSUInteger)fieldEnum recordIndex:(NSUInteger)index
{
NSString * barID = (NSString *)[[(id)plot.identifier componentsSeparatedByString:#","] lastObject];
InfoBarView * barView = (id)[[self defaultLayerHostingView] superview];
InfoController * controller = barView.controller;
GroupItem * group = controller.group;
int fndx = [barID intValue];
int sndx = index % group.itemCount;
Item * item = (Item *)[self.plotData objectAtIndex:sndx];
SEL dataItem = NSSelectorFromString(kTargets[controller.barDataIndex]);
NSString * getName = kGetters[fndx];
SEL getter = NSSelectorFromString(getName);
SEL fldD = #selector(fldD);
CGFloat runs, value=0;
DataItem * data;
id num=nil;
// First get which data block we're after
data = [item performSelector:dataItem];
runs = [[data performSelector:fldD] floatValue];
// Now fetch its getter
switch ( fieldEnum )
{
case CPTBarPlotFieldBarLocation:
num = item.numb.squish;
break;
case CPTBarPlotFieldBarTip:
value = [[data performSelector:getter] floatValue];
num = #(value);
break;
case CPTBarPlotFieldBarBase:
// Calc base by sum prior fields
for (int seg=0; seg < fndx; seg++)
{
value += [[data performSelector:NSSelectorFromString(kGetters[seg])] floatValue];
}
num = #(value);
}
return num;
}
- (nullable NSString *)legendTitleForBarPlot:(nonnull CPTBarPlot *)plot recordIndex:(NSUInteger)index
{
NSString * barID = (NSString *)[[(id)plot.identifier componentsSeparatedByString:#","] lastObject];
int fndx = [barID intValue];
return kGetters[fndx];
}
#pragma mark Plot Legend Delegate
- (void)legend:(CPTLegend *)legend legendEntryForPlot:(CPTPlot *)plot wasSelectedAtIndex:(NSUInteger)index
{
NSLog(#"legend:%# index:%lu", plot.identifier, index);
}
#pragma mark Plot Space Delegate
#pragma mark Plot Space Delegate
- (CPTPlotRange *)plotSpace:(CPTPlotSpace *)space
willChangePlotRangeTo:(CPTPlotRange *)newRange
forCoordinate:(CPTCoordinate)coordinate
{
CGFloat newLocation = newRange.location.floatValue;
// CGFloat newLength = newRange.length.floatValue;
// Range change to +2 point on data boundary
if (CPTCoordinateX == coordinate)
{
if (newLocation < -0.5)
{
return [CPTPlotRange plotRangeWithLocation:#(-0.5) length:newRange.length];
}
else
if (newLocation > (0.3))
{
return [CPTPlotRange plotRangeWithLocation:#(0.3) length:newRange.length];
}
}
if (CPTCoordinateY == coordinate)
{
if (newLocation < (-0.1))
{
return [CPTPlotRange plotRangeWithLocation:#(-0.1) length:newRange.length];
}
else
if (newLocation > (0.1))
{
return [CPTPlotRange plotRangeWithLocation:#(0.1) length:newRange.length];
}
}
// CGRect chartBounds = self.defaultGraph.bounds;
// NSLog(#"old:%#", NSStringFromRect(chartBounds));
// NSLog(#"new:%# %#", (coordinate == CPTCoordinateX ? #"X" : #"Y"),[newRange description]);
return newRange;
}
#end
#implementation InfoBarView
#synthesize barChart;
#synthesize x_title;
- (void)awakeFromNib
{
// Get our orig scaling
[super awakeFromNib];
self.barChart = [[[BarChart alloc] init] autorelease];
}
- (void)drawRect:(NSRect)clip
{
CGContextRef context = [[NSGraphicsContext currentContext] graphicsPort];
NSImage * webImage = controller.group.track.webImage;
GroupItem * group = controller.group;
NSRect rect = [self frame];
// Save state so we can restore later
CGContextSaveGState(context);
// Draw track image as our view's background
if (webImage)
{
[webImage drawInRect:rect fromRect:[webImage alignmentRect]
operation:NSCompositeSourceOver fraction:0.25];
}
if (group && !barChart.graphs.count)
{
[barChart renderInView:self withTheme:nil animated:YES];
}
CGContextRestoreGState(context);
}
#end
If there were visible clues - drawn bounding rects, I think a lot of us could benefit from them (I miss those from IB circa v3).
The statement x.labelFormatter = nil; eliminates the automatic axis labels. If you supply a label formatter and label text style, the axis will create ticks and labels automatically based on the labeling policy.
Related
I have a very crowded xy graph and I'm trying to display the x-axis labels vertically instead of the default horizontal. I can't find documentation on how to do this. Can anyone explain how to do this or point me to the right documentation? I have adjusted the x.labelrotation but it does rotate the x axis label
thanks.
#pragma mark - Chart behavior
-(void)initPlotThree {
[self configureHostThree];
[self configureGraphThree];
[self configurePlotsThree];
[self configureAxesThree];
}
-(void)configureHostThree {
self.hostView = [(CPTGraphHostingView *) [CPTGraphHostingView alloc] initWithFrame:self.view.bounds];
self.hostView.allowPinchScaling = YES;
[self.myViewThree addSubview:self.hostView];
CPTGraphHostingView *BarGraphView = [[CPTGraphHostingView alloc] init];
self.hostView.frame = CGRectMake(self.myViewThree.bounds.origin.x, self.myViewThree.bounds.origin.y, self.myViewThree.bounds.size.width, self.myViewThree.bounds.size.height);
[self.hostView addSubview:BarGraphView];
}
-(void)configureGraphThree {
// 1 - Create the graph
CPTGraph *graph = [[CPTXYGraph alloc] initWithFrame:self.hostView.bounds];
// [graph applyTheme:[CPTTheme themeNamed:kCPTSlateTheme]];
[graph applyTheme:[CPTTheme themeNamed:kCPTPlainWhiteTheme]];
self.hostView.hostedGraph = graph;
// 2 - Set graph title
NSString *title = #"Tremor";
graph.title = title;
// 3 - Create and set text style
CPTMutableTextStyle *titleStyle = [CPTMutableTextStyle textStyle];
titleStyle.color = [CPTColor blackColor];
titleStyle.fontName = #"Helvetica-Bold";
titleStyle.fontSize = 12.0f;
graph.titleTextStyle = titleStyle;
graph.titlePlotAreaFrameAnchor = CPTRectAnchorTop;
graph.titleDisplacement = CGPointMake(0.0f, 17.0f);
// 4 - Set padding for plot area
[graph.plotAreaFrame setPaddingLeft:1.0f];
[graph.plotAreaFrame setPaddingBottom:1.0f];
// 5 - Enable user interactions for plot space
CPTXYPlotSpace *plotSpace = (CPTXYPlotSpace *) graph.defaultPlotSpace;
plotSpace.allowsUserInteraction = YES;
}
-(void)configurePlotsThree {
// 1 - Get graph and plot space
CPTGraph *graph = self.hostView.hostedGraph;
CPTXYPlotSpace *plotSpace = (CPTXYPlotSpace *) graph.defaultPlotSpace;
// 2 - Create the plots
CPTScatterPlot *tremorPlot = [[CPTScatterPlot alloc] init];
tremorPlot.dataSource = self;
tremorPlot.identifier = tremorSCORE;
CPTColor *tremorColor = [CPTColor blueColor];
[graph addPlot:tremorPlot toPlotSpace:plotSpace];
// 3 - Set up plot space
[plotSpace scaleToFitPlots:[NSArray arrayWithObjects:tremorPlot, nil]];
CPTMutablePlotRange *xRange = [plotSpace.xRange mutableCopy];
[xRange expandRangeByFactor:CPTDecimalFromCGFloat(1.1f)];
plotSpace.xRange = xRange;
CPTMutablePlotRange *yRange = [plotSpace.yRange mutableCopy];
[yRange expandRangeByFactor:CPTDecimalFromCGFloat(1.2f)];
plotSpace.yRange = yRange;
// 4 - Create styles and symbols
CPTMutableLineStyle *tremorLineStyle = [tremorPlot.dataLineStyle mutableCopy];
tremorLineStyle.lineWidth = 2.0;
tremorLineStyle.lineColor = tremorColor;
tremorPlot.dataLineStyle = tremorLineStyle;
CPTMutableLineStyle *tremorSymbolLineStyle = [CPTMutableLineStyle lineStyle];
tremorSymbolLineStyle.lineColor = tremorColor;}
-(void)configureAxesThree {
// 1 - Create styles
CPTMutableTextStyle *axisTitleStyle = [CPTMutableTextStyle textStyle];
axisTitleStyle.color = [CPTColor blackColor];
axisTitleStyle.fontName = #"Helvetica-Bold";
axisTitleStyle.fontSize = 10.0f;
CPTMutableLineStyle *axisLineStyle = [CPTMutableLineStyle lineStyle];
axisLineStyle.lineWidth = .01f;
axisLineStyle.lineColor = [CPTColor blackColor];
CPTMutableTextStyle *axisTextStyle = [[CPTMutableTextStyle alloc] init];
axisTextStyle.color = [CPTColor blackColor];
axisTextStyle.fontName = #"Helvetica-Bold";
axisTextStyle.fontSize = 9.0f;
CPTMutableLineStyle *tickLineStyle = [CPTMutableLineStyle lineStyle];
tickLineStyle.lineColor = [CPTColor blackColor];
tickLineStyle.lineWidth = 1.0f;
CPTMutableLineStyle *gridLineStyle = [CPTMutableLineStyle lineStyle];
tickLineStyle.lineColor = [CPTColor blackColor];
tickLineStyle.lineWidth = 1.0f;
// 2 - Get axis set
CPTXYAxisSet *axisSet = (CPTXYAxisSet *) self.hostView.hostedGraph.axisSet;
// 3 - Configure x-axis
CPTAxis *x = axisSet.xAxis;
x.title = #"";
x.titleTextStyle = axisTitleStyle;
x.titleOffset = 20.0f;
x.axisLineStyle = axisLineStyle;
x.labelingPolicy = CPTAxisLabelingPolicyNone;
x.labelTextStyle = axisTextStyle;
x.majorTickLineStyle = axisLineStyle;
x.majorTickLength = 4.0f;
x.tickDirection = CPTSignNegative;
x.labelRotation = .6;
x.labelOffset = 15;
CGFloat dateCount = [self.dates count];
NSMutableSet *xLabels = [NSMutableSet setWithCapacity:dateCount];
NSMutableSet *xLocations = [NSMutableSet setWithCapacity:dateCount];
NSInteger i = 0;
for (NSString *date in self.dates) {
CPTAxisLabel *label = [[CPTAxisLabel alloc] initWithText:date textStyle:x.labelTextStyle];
CGFloat location = i++;
label.tickLocation = CPTDecimalFromCGFloat(location);
label.offset = x.majorTickLength;
if (label) {
[xLabels addObject:label];
[xLocations addObject:[NSNumber numberWithFloat:location]];
}
}
x.axisLabels = xLabels;
x.majorTickLocations = xLocations;
// CPTXYAxisSet *axisSet = (CPTXYAxisSet *)graph.axisSet;
axisSet.xAxis.axisConstraints = [CPTConstraints constraintWithLowerOffset:15.0]; // 8-22
// 4 - Configure y-axis
CPTAxis *y = axisSet.yAxis;
y.title = #"";
y.titleTextStyle = axisTitleStyle;
y.titleOffset = -40.0f;
y.axisLineStyle = axisLineStyle;
y.majorGridLineStyle = nil;
y.labelingPolicy = CPTAxisLabelingPolicyNone;
y.labelTextStyle = nil;
y.labelOffset = 16.0f;
y.majorTickLineStyle = nil;
y.majorTickLength = 4.0f;
y.minorTickLength = 1.0f;
y.tickDirection = CPTSignPositive;
NSInteger majorIncrement = 2;
NSInteger minorIncrement = 1;
CGFloat yMax = 700.0f; // should determine dynamically based on max price
NSMutableSet *yLabels = [NSMutableSet set];
NSMutableSet *yMajorLocations = [NSMutableSet set];
NSMutableSet *yMinorLocations = [NSMutableSet set];
for (NSInteger j = minorIncrement; j <= yMax; j += minorIncrement) {
NSUInteger mod = j % majorIncrement;
if (mod == 0) {
CPTAxisLabel *label = [[CPTAxisLabel alloc] initWithText:[NSString stringWithFormat:#"%li", (long)j] textStyle:y.labelTextStyle];
NSDecimal location = CPTDecimalFromInteger(j);
label.tickLocation = location;
label.offset = -y.majorTickLength - y.labelOffset;
if (label) {
[yLabels addObject:label];
}
[yMajorLocations addObject:[NSDecimalNumber decimalNumberWithDecimal:location]];
[yMajorLocations addObject:[NSDecimalNumber decimalNumberWithDecimal:location]];
} else {
[yMinorLocations addObject:[NSDecimalNumber decimalNumberWithDecimal:CPTDecimalFromInteger(j)]];
[yMinorLocations addObject:[NSDecimalNumber decimalNumberWithDecimal:CPTDecimalFromInteger(j)]];
}
}
y.axisLabels = yLabels;
y.majorTickLocations = yMajorLocations;
y.minorTickLocations = yMinorLocations;
}
Set the labelRotation on the x-axis to rotate the labels when using one of the automatic labelling policies. When creating custom labels, you need to set the rotation on each label directly.
The code below takes a string, adds each letter to an array and shuffles that array and shows the end result in a label. That works well. But I'd like for each character to contain a single character of the shuffled string. Right now it almost works, but it always repeats the characters. Like instead of having a series of 6 buttons with their titles: L e a g u e, the code generates repeated characters like: Leaauu.
My code is this:
- (IBAction)shuffleButttonTitles:(id)sender {
// The mutable array must be created here to create a new instance each time the button is tapped
letters = [[NSMutableArray alloc] init];
str = #"League";
length = str.length;
NSString *letter;
UIButton *button;
// First loop through the string and add each letter to an array
for (int i = 0; i < length; i++) {
letter = [NSString stringWithFormat:#"%c", [str characterAtIndex:i]];
[letters addObject:letter];
}
// Shuffle the string for the label/buttons
for (int i = 0; i < length; i++) {
int value = arc4random() % (length - 1);
[letters exchangeObjectAtIndex:i withObjectAtIndex:value];
//Create the button and shuffle the letters for their titles
button = [[UIButton alloc] initWithFrame:CGRectMake(50 * i, 350, 44, 44)];
// HERE THE CODE REPEATS THE CHARACTERS
[button setTitle:[letters objectAtIndex:i] forState:UIControlStateNormal];
//Store the button in our array
[myButtons addObject:button];
NSLog(#"Letters in Array: %lu", letters.count);
}
for (UIButton *button in myButtons){
[button setBackgroundColor:[UIColor redColor]];
[self.view addSubview:button];
}
// Now we set the randomized title to the label
NSString *results = [letters componentsJoinedByString:#""];
string.text = results;
}
After some searching on the web I've figured it out. I post the complete code for others. This code takes a random string from the Characters.txt file and shuffles that string. Then it rotates the tiles slighty. You can enter the correct word when you have figured out the anagram, which then shows an alert view if you got it or didn't get it.
#define kTileSpacing 20
#define randomf(minX,maxX) ((float)(arc4random() % (maxX - minX + 1)) + (float)minX)
#interface ViewController ()
#end
#implementation ViewController
{
}
#synthesize progressView;
- (void)viewDidLoad {
[super viewDidLoad];
NSString *path = [[NSBundle mainBundle] pathForResource:#"Anagrams" ofType:#"plist"];
dictionary = [[NSMutableArray alloc] initWithContentsOfFile:path];
NSString *quotesFile = [[NSBundle mainBundle] pathForResource:#"Characters" ofType:#"txt"];
fileContents = [NSString stringWithContentsOfFile:quotesFile encoding:NSUTF8StringEncoding error:NULL];
// [txtField becomeFirstResponder];
//[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(checkWord:) name:nil object:nil];
}
- (IBAction)clear:(id)sender {
quoteArray = [fileContents componentsSeparatedByString:#"\n"];
NSString *quoteToDisplay;
currentQuestion = arc4random() % quoteArray.count;
quoteToDisplay = [quoteArray objectAtIndex: currentQuestion];
welldone.text = quoteToDisplay;
txtField.text = nil;
[txtField becomeFirstResponder];
for (UILabel *lbl in myButtons) {
[lbl removeFromSuperview];
}
}
- (IBAction)ShuffleString:(id)sender {
[self clear:nil];
// The mutable array must be created here to create a new instance each time the button is tapped
charactersArray = [[NSMutableArray alloc] init];
indexArray = [[NSMutableArray alloc] init];
myButtons = [[NSMutableArray alloc] init];
// 1. Shuffle the plist with the words to form anagrams from
currentQuestion = arc4random() % quoteArray.count;
str = [quoteArray objectAtIndex: currentQuestion]; //[[dictionary objectAtIndex:currentQuestion] objectForKey:#"Anagram"];
length = str.length;
NSString *letter;
// 2. Loop throught the chosen word and break it down into its letters and add them to an array
for (int i = 0; i < str.length; i++) {
// [charactersArray removeObjectAtIndex:i];
letter = [NSString stringWithFormat:#"%c", [str characterAtIndex:i]];
[charactersArray addObject:letter];
// NSLog(#"Number of letters: %#", charactersArray);
}
while ([charactersArray count]) {
int randomizing = arc4random() % [charactersArray count];
[indexArray addObject:[charactersArray objectAtIndex:randomizing]];
[charactersArray removeObjectAtIndex:randomizing];
// NSLog(#"NO REPEAT SHUFFLE: %lu", (unsigned long)indexArray.count);
}
/***************/
CGFloat staticY = self.view.bounds.size.height / 9 * 1; // Static X for all buttons.
CGFloat staticWidth = 46; // Static Width for all Buttons.
CGFloat staticHeight = 46; // Static Height for all buttons.
CGFloat staticPadding = 10; // Padding to add between each button.
float tileSize = ceilf( self.view.bounds.size.width / str.length );
NSLog(#"size %f", tileSize);
CGFloat xOffset = (self.view.bounds.size.width - str.length * (44+staticPadding));
NSLog(#"xOffset %f", tileSize);
xOffset = tileSize/ 2;
for (int i = 0; i < str.length; i++) {
singleCharacterLabel = [[UILabel alloc] init];
singleCharacterLabel.textAlignment = NSTextAlignmentCenter;
singleCharacterLabel.font = [UIFont fontWithName:#"Verdana-Bold" size:21];
singleCharacterLabel.frame = CGRectMake((staticPadding + (i * (staticHeight + staticPadding))), staticY, staticWidth, staticHeight);
// NSLog(#"X: %f", (staticPadding + (i * (staticHeight + staticPadding))));
//singleCharacterLabel.center = CGPointMake(i * 50 + self.view.bounds.origin.x + self.view.bounds.size.width /3, 80); // i * int +self... int = space between labels. Here it is '50'
// singleCharacterLabel.center = CGPointMake(self.view.bounds.size.width * i, self.view.bounds.size.height / 5 * 1); // 1/4th down from the top
singleCharacterLabel.layer.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:#"Tile.png"]].CGColor;
NSString *anagramString = [indexArray objectAtIndex:i];
singleCharacterLabel.text = anagramString;
[myButtons addObject:singleCharacterLabel];
//1
//set random rotation of the tile
//anywhere between -0.2 and 0.3 radians
float rotation = randomf(0,50) / (float)100 - 0.2;
singleCharacterLabel.transform = CGAffineTransformMakeRotation( rotation );
//2
//move randomly upwards
int yOffset = (arc4random() % 10) - 10;
singleCharacterLabel.center = CGPointMake(singleCharacterLabel.center.x, singleCharacterLabel.center.y + yOffset);
[self.view addSubview:singleCharacterLabel];
//NSLog(#"LOOP: %#", anagramString);
}
}
- (IBAction)checkWord:(id)sender {
if (([txtField.text isEqual:str])) {
alertCorrect = [[UIAlertView alloc] initWithTitle:#"" message:#"Well done!" delegate:self cancelButtonTitle:nil otherButtonTitles:#"Next", nil];
[alertCorrect show];
} else {
alertWrong = [[UIAlertView alloc] initWithTitle:#"" message:#"Sorry, try again." delegate:self cancelButtonTitle:nil otherButtonTitles:#"OK", nil];
[alertWrong show];
}
// NSLog(#"String is: %lu", str.length);
}
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
if (alertView == alertCorrect) {
if (buttonIndex == 0) {
[self ShuffleString:nil];
NSLog(#"next");
}
}
if (alertView == alertWrong) {
if (buttonIndex == 1) {
// Wrong answer. Close view and let user try again
}
}
}
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
if (txtField.text.length == length) {
[self checkWord:nil];
NSLog(#"You entered %lu characters", length);
}
return YES;
}
in one part of my project I need to create some UI objects programmatically, can I just customize my UI Objects like labels,... visually in storyboard then simply copy/paste generated code relevant to that object?
I searched in xcode menu but I couldn't find this but once I saw it in a tutorial in youtube.
Thanks in Advance
Yes you can customize the UI Classes or any other class, Like I have customize UILabel Class as UILabelExtended
UILabelExtended.h
#import <Foundation/Foundation.h>
/* **********************************************************************************************
This class inherit the class UILabel and extend the features of UILabel.
********************************************************************************************** */
#interface UILabelExtended : UILabel {
__unsafe_unretained id customDelegate;
id objectInfo;
SEL selector;
}
#property (nonatomic,assign) SEL selector;;
#property (nonatomic,assign) id customDelegate;
#property (nonatomic,retain) id objectInfo;
#end
#interface UILabel(UILabelCategory)
- (void)setHeightOfLabel;
- (void)setWidthOfLabel;
- (void)setHeightOfLabelWithMaxHeight:(float)maxHeight;
- (void)setWidthOfLabelWithMaxWidth:(float)maxWidth ;
#end
UILabelExtended.m
#import "UILabelExtended.h"
#implementation UILabelExtended
#synthesize selector,customDelegate, objectInfo;
- (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
if(self.selector)
if([self.customDelegate respondsToSelector:self.selector]) {
[self.customDelegate performSelector:self.selector withObject:self];
return;
}
}
- (void)dealloc {
self.customDelegate = nil;
self.selector = NULL;
self.objectInfo = nil;
}
#end
#implementation UILabel(UILabelCategory)
- (void)setHeightOfLabel {
UILabel* label = self;
//get the height of label content
CGFloat height = [label.text sizeWithFont:label.font constrainedToSize:CGSizeMake(label.bounds.size.width, 99999) lineBreakMode:NSLineBreakByWordWrapping].height;
//set the frame according to calculated height
CGRect frame = label.frame;
if([label.text length] > 0) {
frame.size.height = height;
}
else {
frame.size.height = 0;
}
label.frame = frame;
}
- (void)setWidthOfLabel {
UILabel* label = self;
//get the height of label content
CGFloat width = [label.text sizeWithFont:label.font constrainedToSize:CGSizeMake(99999, label.bounds.size.height) lineBreakMode:NSLineBreakByWordWrapping].width;
//set the frame according to calculated height
CGRect frame = label.frame;
if([label.text length] > 0) {
frame.size.width = width+5;
}
else {
frame.size.width = 0;
}
label.frame = frame;
}
- (void)setHeightOfLabelWithMaxHeight:(float)maxHeight {
UILabel* label = self;
//get the height of label content
CGFloat height = [label.text sizeWithFont:label.font constrainedToSize:CGSizeMake(label.bounds.size.width, maxHeight) lineBreakMode:NSLineBreakByWordWrapping].height;
//set the frame according to calculated height
CGRect frame = label.frame;
if([label.text length] > 0) {
if (height > maxHeight) {
frame.size.height = maxHeight;
}
else {
frame.size.height = height;
}
}
else {
frame.size.height = 0;
}
label.frame = frame;
}
- (void)setWidthOfLabelWithMaxWidth:(float)maxWidth {
UILabel* label = self;
//get the height of label content
CGFloat width = [label.text sizeWithFont:label.font constrainedToSize:CGSizeMake(99999, label.bounds.size.height) lineBreakMode:NSLineBreakByWordWrapping].width;
//set the frame according to calculated height
CGRect frame = label.frame;
if([label.text length] > 0) {
if (width > maxWidth) {
frame.size.width = maxWidth;
}
else {
frame.size.width = width;
}
}
else {
frame.size.width = 0;
}
label.frame = frame;
}
#end
So I have it set up so when the characters health is < 100 (for testing purposes) it stop the scene and goes to the game over scene.
if (playerDataManager.playerHealth < 100) {
[[CCDirector sharedDirector] replaceScene:[CCTransitionFade transitionWithDuration:3 scene: [GameLogic scene]]];
}
However when the players health drops below 100, it goes to the new scene, but the FPS drops dramatically from 60 to 5.
I get a list of OpenGL error 0x0503 in -[EAGLView swapBuffers] then it stays frozen like that for about 40 seconds, then the FPS unfreeze and goes back out to 60 and I get a list of 2012-07-13 10:37:50.234 Tilegame[93513:10a03] cocos2d: removeChildByTag: child not found!
Then I can continue with the app like normal, going back to the main menu, starting a new game, then recreate the error.
#import "HelloWorldLayer.h"
#import "Menu.h"
#import "SimpleAudioEngine.h"
#import "LogCabinMap.h"
#import "LogShedMap.h"
#import "SaveData.h"
#import "pauseM.h"
#import "Player.h"
#import "GameLogic.h"
CCSprite *player;
CGPoint newPos;
int joyDegrees;
// HelloWorldLayer implementation
#implementation HelloWorldLayer
#synthesize tileMap = _tileMap;
#synthesize background = _background;
#synthesize buildings = _buildings;
#synthesize meta = _meta;
#synthesize player = _player;
#synthesize foreground = _foreground;
#synthesize numCollected = _numCollected;
#synthesize hud = _hud;
-(void) animateEnemy:(CCSprite*)enemy {
//speed of the enemy
ccTime actualDuration = .2;
id actionMove;
int distanceFromPlayer = ccpDistance(player.position, enemy.position);
if (distanceFromPlayer < 200) { //Check whether enemy can "see" Ninja before moving towards him.
//rotate to face the player
CGPoint diff = ccpSub(player.position,enemy.position);
float angleRadians = atanf((float)diff.y / (float)diff.x);
float angleDegrees = CC_RADIANS_TO_DEGREES(angleRadians);
float cocosAngle = -1 * angleDegrees;
if (diff.x < 0) {
cocosAngle += 180;
}
enemy.rotation = cocosAngle;
actionMove = [CCMoveBy actionWithDuration:actualDuration
position:ccpMult(ccpNormalize(ccpSub(player.position,enemy.position)),10)];
} else {
actionMove = [CCMoveBy actionWithDuration:actualDuration
position:ccpMult(ccpNormalize(ccpSub(player.position,enemy.position)),0)];
}
id actionMoveDone = [CCCallFuncN actionWithTarget:self
selector:#selector(enemyMoveFinished:)];
[enemy runAction:[CCSequence actions:actionMove, actionMoveDone, nil]];
}
// callback. starts another iteration of enemy movement.
- (void) enemyMoveFinished:(id)sender {
CCSprite *enemy = (CCSprite *)sender;
[self animateEnemy: enemy];
}
-(void)addEnemyAtX:(int)x y:(int)y {
CCSprite *enemy = [CCSprite spriteWithFile:#"enemy1.png"];
enemy.position = ccp(x, y);
[self addChild:enemy];
[self animateEnemy:enemy];
}
-(void)setViewpointCenter:(CGPoint) position {
CGSize winSize = [[CCDirector sharedDirector] winSize];
int x = MAX(position.x, winSize.width / 2);
int y = MAX(position.y, winSize.height / 2);
x = MIN(x, (_tileMap.mapSize.width * _tileMap.tileSize.width)
- winSize.width / 2);
y = MIN(y, (_tileMap.mapSize.height * _tileMap.tileSize.height)
- winSize.height/2);
CGPoint actualPosition = ccp(x, y);
CGPoint centerOfView = ccp(winSize.width/2, winSize.height/2);
CGPoint viewPoint = ccpSub(centerOfView, actualPosition);
self.position = viewPoint;
}
-(id) init
{
if( (self=[super init] )) {
[[SimpleAudioEngine sharedEngine] preloadEffect:#"pickup.caf"];
[[SimpleAudioEngine sharedEngine] preloadEffect:#"hit.caf"];
[[SimpleAudioEngine sharedEngine] preloadEffect:#"move.caf"];
//[[SimpleAudioEngine sharedEngine] playBackgroundMusic:#"TileMap.caf"];
self.isTouchEnabled = YES;
self.tileMap = [CCTMXTiledMap tiledMapWithTMXFile:#"TileMap.tmx"];
self.background = [_tileMap layerNamed:#"Background"];
self.foreground = [_tileMap layerNamed:#"Foreground"];
self.buildings = [_tileMap layerNamed:#"Buildings"];
self.meta = [_tileMap layerNamed:#"Meta"];
_meta.visible = NO;
CCTMXObjectGroup *objects = [_tileMap objectGroupNamed:#"Objects"];
NSAssert(objects != nil, #"'Objects' object group not found");
//NSMutableDictionary * padPoints = [objects objectNamed:#"pad"];
NSMutableDictionary * padPoints;
SaveData * SaveDataManager = [SaveData sharedSaveDataManager];
for (int i = 0; i < 20; i ++) {
for (padPoints in [objects objects]) {
if ([[SaveDataManager.padArray objectAtIndex: i] intValue] == 1 ){
if ([[padPoints valueForKey:#"pad"] intValue] == i){
int x = [[padPoints valueForKey:#"x"] intValue];
int y = [[padPoints valueForKey:#"y"] intValue];
self.player = [CCSprite spriteWithFile:#"man.png"];
_player.position = ccp(x+16,y+16);
//[self addChild:_player];
}
}
}
}
// iterate through objects, finding all enemy spawn points
// create an enemy for each one
NSMutableDictionary * spawnPoints;
for (spawnPoints in [objects objects]) {
if ([[spawnPoints valueForKey:#"Enemy"] intValue] == 2){
int x = [[spawnPoints valueForKey:#"x"] intValue];
int y = [[spawnPoints valueForKey:#"y"] intValue];
[self addEnemyAtX:x+=16 y:y+=64];
}
}
player = [CCSprite spriteWithFile:#"man.png"];
player.position= _player.position;
[_tileMap addChild:player z: 0];
// [self addChild:player z:10];
[self setViewpointCenter:player.position];
[self addChild:_tileMap z:-1];
[self scheduleUpdate];
}
return self;
}
- (CGPoint)tileCoordForPosition:(CGPoint)position {
int x = position.x / _tileMap.tileSize.width;
int y = ((_tileMap.mapSize.height * _tileMap.tileSize.height) - position.y) / _tileMap.tileSize.height;
return ccp(x, y);
}
-(void)setPlayerPosition:(CGPoint)position {
Player * playerDataManager = [Player playerSaveDataManager];
CGPoint tileCoord = [self tileCoordForPosition:position];
int tileGid = [_meta tileGIDAt:tileCoord];
int x = player.position.x;
int y = player.position.y;
if (tileGid) {
NSDictionary *properties = [_tileMap propertiesForGID:tileGid];
if (properties) {
NSString *collision = [properties valueForKey:#"Collidable"];
if (collision && [collision compare:#"True"] == NSOrderedSame) {
//[[SimpleAudioEngine sharedEngine] playEffect:#"hit.caf"];
if (joyDegrees > 45 && joyDegrees < 135){
player.position = ccp(x,y-1);
}
if (joyDegrees > 135 && joyDegrees < 225){
player.position = ccp(x+1,y);
}
if (joyDegrees > 225 && joyDegrees < 315){
player.position = ccp(x,y+1);
}
if ((joyDegrees > 315 && joyDegrees < 360) || (joyDegrees > -1 && joyDegrees < 45)){
player.position = ccp(x-1,y);
}
return;
}
NSString *collectable = [properties valueForKey:#"Collectable"];
if (collectable && [collectable compare:#"True"] == NSOrderedSame) {
[[SimpleAudioEngine sharedEngine] playEffect:#"pickup.caf"];
[_meta removeTileAt:tileCoord];
[_foreground removeTileAt:tileCoord];
self.numCollected += 1;
[_hud numCollectedChanged:_numCollected];
playerDataManager.playerHealth -= 10;
}
NSString *Gate = [properties valueForKey:#"Gate"];
if (Gate && [Gate compare:#"1"] == NSOrderedSame) {
SaveData * SaveDataManager = [SaveData sharedSaveDataManager];
//[SaveDataManager.padArray removeAllObjects];
for (int i = 0; i < 20; i ++) {
[SaveDataManager.padArray replaceObjectAtIndex:i withObject:[NSNumber numberWithInt:0]];
}
[SaveDataManager.padArray replaceObjectAtIndex:1 withObject:[NSNumber numberWithInt:1]];
//[[CCDirector sharedDirector] replaceScene:[LogCabinMap scene]];
[[CCDirector sharedDirector] pushScene:[LogCabinMap scene]];
}
if (Gate && [Gate compare:#"2"] == NSOrderedSame) {
SaveData * SaveDataManager = [SaveData sharedSaveDataManager];
//[SaveDataManager.padArray removeAllObjects];
for (int i = 0; i < 20; i ++) {
[SaveDataManager.padArray replaceObjectAtIndex:i withObject:[NSNumber numberWithInt:0]];
}
[SaveDataManager.padArray replaceObjectAtIndex:1 withObject:[NSNumber numberWithInt:1]];
//[[CCDirector sharedDirector] replaceScene:[LogShedMap scene]];
[[CCDirector sharedDirector] pushScene:[LogShedMap scene]];
}
}
}
//[[SimpleAudioEngine sharedEngine] playEffect:#"move.caf"];
player.position = position;
}
-(BOOL) ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event
{
return YES;
}
-(void) update:(ccTime)deltaTime {
[self setPlayerPosition:newPos];
[self setViewpointCenter:player.position];
}
// on "dealloc" you need to release all your retained objects
- (void) dealloc
{
// in case you have something to dealloc, do it in this method
// in this particular example nothing needs to be released.
// cocos2d will automatically release all the children (Label)
self.tileMap = nil;
self.background = nil;
self.foreground = nil;
self.buildings = nil;
self.meta =nil;
self.player = nil;
player = nil;
self.hud = nil;
// don't forget to call "super dealloc"
[super dealloc];
}
#end
#implementation HelloWorldHud
#synthesize background;
#synthesize background2;
#synthesize health;
#synthesize baseScaleFactor;
+(CCScene *) scene
{
// 'scene' is an autorelease object.
CCScene *scene = [CCScene node];
// 'layer' is an autorelease object.
HelloWorldHud *layer = [HelloWorldHud node];
// add layer as a child to scene
[scene addChild: layer z:2];
HelloWorldLayer *hud = [HelloWorldLayer node];
[scene addChild: hud z:1];
//layer.hud = hud;
// return the scene
return scene;
}
-(void)initJoystick {
SneakyJoystickSkinnedBase *joystickBase = [[[SneakyJoystickSkinnedBase alloc] init] autorelease];
joystickBase.backgroundSprite = [CCSprite spriteWithFile:#"JoyB.png"];
joystickBase.thumbSprite = [CCSprite spriteWithFile:#"JoyS.png"];
joystickBase.joystick = [[SneakyJoystick alloc] initWithRect: CGRectMake(0, 0, 128, 128)];
joystickBase.position = ccp(55, 55);
[self addChild:joystickBase];
leftJoystick = [[joystickBase.joystick retain] autorelease];
}
-(void) update:(ccTime)deltaTime {
Player *playerDataManager = [Player playerSaveDataManager];
CGPoint scaledVelocity = ccpMult(leftJoystick.velocity, 100);
CGPoint newPosition = ccp(player.position.x + scaledVelocity.x * deltaTime, player.position.y + scaledVelocity.y * deltaTime);
if (leftJoystick.velocity.x == 0 && leftJoystick.velocity.y == 0 ){
if (!playerDataManager.standStill) {
[player stopAllActions];
playerDataManager.walkUp = FALSE;
playerDataManager.walkDown = FALSE;
playerDataManager.walkRight = FALSE;
playerDataManager.walkLeft = FALSE;
playerDataManager.standStill = TRUE;
[player runAction:playerDataManager.standAction];
}
}
if (leftJoystick.degrees > 45 && leftJoystick.degrees < 135){
if (!playerDataManager.walkUp) {
[player stopAllActions];
playerDataManager.walkUp = TRUE;
playerDataManager.walkDown = FALSE;
playerDataManager.walkRight = FALSE;
playerDataManager.walkLeft = FALSE;
playerDataManager.standStill = FALSE;
[player runAction:playerDataManager.walkUpAction];
}
}
if (leftJoystick.degrees > 135 && leftJoystick.degrees < 225){
if (!playerDataManager.walkLeft) {
[player stopAllActions];
playerDataManager.walkUp = FALSE;
playerDataManager.walkDown = FALSE;
playerDataManager.walkRight = FALSE;
playerDataManager.walkLeft = TRUE;
playerDataManager.standStill = FALSE;
[player runAction:playerDataManager.walkLeftAction];
}
}
if (leftJoystick.degrees > 225 && leftJoystick.degrees < 315){
if (!playerDataManager.walkDown) {
[player stopAllActions];
playerDataManager.walkUp = FALSE;
playerDataManager.walkDown = TRUE;
playerDataManager.walkRight = FALSE;
playerDataManager.walkLeft = FALSE;
playerDataManager.standStill = FALSE;
[player runAction:playerDataManager.walkDownAction];
}
}
if (((leftJoystick.degrees > 315 && leftJoystick.degrees < 360) && (leftJoystick.velocity.x != 0 && leftJoystick.velocity.y != 0 )) || ((leftJoystick.degrees > -1 && leftJoystick.degrees < 45) && (leftJoystick.velocity.x != 0 && leftJoystick.velocity.y != 0 ))){
if (!playerDataManager.walkRight) {
[player stopAllActions];
playerDataManager.walkUp = FALSE;
playerDataManager.walkDown = FALSE;
playerDataManager.walkRight = TRUE;
playerDataManager.walkLeft = FALSE;
playerDataManager.standStill = FALSE;
[player runAction:playerDataManager.walkRightAction];
}
}
float scaleFactor = playerDataManager.playerHealth/baseScaleFactor;
health.scaleX = playerDataManager.playerHealth/1;
newPos = newPosition;
joyDegrees = leftJoystick.degrees;
if (playerDataManager.playerHealth < 100) {
[[CCDirector sharedDirector] replaceScene:[CCTransitionFade transitionWithDuration:3 scene: [GameLogic scene]]];
[[CCDirector sharedDirector] replaceScene: [GameLogic scene]];
}
}
-(void) scroll:(ccTime)dt
{
//move 30*dt px vertically
if (background.position.y<background2.position.y){
background.position = ccp(background.contentSize.width/2, background.position.y - 225*dt);
background2.position = ccp(background2.contentSize.width/2, background.position.y+background.contentSize.height);
}else{
background2.position = ccp(background2.contentSize.width/2, background2.position.y- 225*dt);
background.position = ccp(background.contentSize.width/2, background2.position.y+background2.contentSize.height);
}
//reset offscreen position
if (background.position.y <-background.contentSize.height/2)
{
background.position = ccp(background.contentSize.height/2,background2.position.y+background2.contentSize.height);
}else if (background2.position.y < -background2.contentSize.height/2)
{
background2.position = ccp(background2.contentSize.height/2, background.position.y+background.contentSize.height);
}
}
-(id) init
{
if ((self = [super init])) {
CGSize size = [CCDirector sharedDirector].winSize;
background = [CCSprite spriteWithFile:#"rain.png"];
background2 = [CCSprite spriteWithFile:#"rain.png"];
[background.texture setAliasTexParameters];
[background2.texture setAliasTexParameters];
//position background sprites
background.position = ccp(background.contentSize.height/2,background.contentSize.width/2);
background2.position = ccp(size.width,0);
//schedule to move background sprites
//[self schedule:#selector(scroll:)];
//adding them to the main layer
//[self addChild:background z:-1];
//[self addChild:background2 z:-1];
[[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:#"GUI.plist"];
CCSpriteBatchNode *GUISpriteSheet = [CCSpriteBatchNode batchNodeWithFile:#"GUI.png"];
[self addChild:GUISpriteSheet];
CCSprite * healthBar = [CCSprite spriteWithSpriteFrameName:#"bar.png"];
CCSprite * cap = [CCSprite spriteWithSpriteFrameName:#"cap.png"];
CCSprite * endCap = [CCSprite spriteWithSpriteFrameName:#"endcap.png"];
health = [CCSprite spriteWithSpriteFrameName:#"red.png"];
healthBar.anchorPoint = ccp(0,1);
health.anchorPoint = ccp(0,1);
cap.anchorPoint = ccp(0,1);
endCap.anchorPoint = ccp(0,1);
healthBar.position = ccp(1 , size.height);
healthBar.scaleX = 25;
cap.position = ccp(0 , size.height);
int width = [healthBar boundingBox].size.width;
endCap.position = ccp(width , size.height);
health.position = ccp(1, size.height-2);
baseScaleFactor = width;
health.scaleX = baseScaleFactor;
[self addChild:healthBar];
[self addChild:cap];
[self addChild:endCap];
[self addChild:health];
CGSize winSize = [[CCDirector sharedDirector] winSize];
label = [CCLabelTTF labelWithString:#"0" dimensions:CGSizeMake(50, 20)
alignment:UITextAlignmentRight fontName:#"Verdana-Bold"
fontSize:18.0];
label.color = ccc3(0,0,0);
int margin = 10;
label.position = ccp(winSize.width - (label.contentSize.width/2)
- margin, label.contentSize.height/2 + margin);
[self addChild:label];
CCMenuItemFont * pause = [CCMenuItemFont itemFromString:#"Pause" target:self selector:#selector(pause:)];
CCMenu *menu = [CCMenu menuWithItems: pause, nil];
pause.position = ccp(206,142);
[self addChild:menu];
CCSprite *pix = [CCSprite spriteWithFile:#"pix.png"];
pix.position = ccp(size.width/2, size.height/2);
//pix.scale = 50000;
[self addChild:pix z:1];
//[pix runAction:[CCTintTo actionWithDuration:10 red:255 green:0 blue:0]];
//[pix runAction:[CCScaleTo actionWithDuration:15 scale:500]];
pix.color = ccc3(255, 255, 255);
[self scheduleUpdate];
[self initJoystick];
}
return self;
}
- (void)numCollectedChanged:(int)numCollected {
[label setString:[NSString stringWithFormat:#"%d", numCollected]];
// [label setString:[NSString stringWithFormat:#"%d", score]];
}
- (void) pause: (id) sender
{
[[CCDirector sharedDirector] pushScene:[pauseM scene]];
}
- (void) dealloc
{
self.background = nil;
self.background2 = nil;
self.health = nil;
self.meta =nil;
player = nil;
// don't forget to call "super dealloc"
[super dealloc];
}
#end
Above is the .m scene that is running when the problem occurs and below is the GameLogic.m
#import "GameLogic.h"
#import "Player.h"
#import "Menu.h"
#implementation GameLogic
+(id) scene
{
CCScene *scene = [CCScene node];
GameLogic *layer = [GameLogic node];
[scene addChild: layer];
return scene;
}
+(id) gameLogicSaveDataManager {
static id gameLogicSaveDataManager = nil;
if (gameLogicSaveDataManager == nil) {
gameLogicSaveDataManager = [[self alloc] init];
}
return gameLogicSaveDataManager;
}
-(id) init
{
if( (self=[super init] )) {
CCSprite *bg = [CCSprite spriteWithFile:#"bg.jpg"];
bg.anchorPoint = ccp(0,0);
id fadeIn = [CCFadeIn actionWithDuration:3];
[self addChild:bg];
[bg runAction: fadeIn];
CCLayer *menuLayer = [[[CCLayer alloc] init] autorelease];
[self addChild:menuLayer];
CCMenuItemImage *home = [CCMenuItemImage
itemFromNormalImage:#"bg.jpg"
selectedImage:#"bg.jpg"
target:self
selector:#selector(home:)];
CCMenu *menu = [CCMenu menuWithItems: home, nil];
home.position = ccp(0,0);
[menuLayer addChild: menu];
}
return self;
}
- (void) home: (id) sender
{
[[CCDirector sharedDirector] replaceScene:[Menu scene]];
}
- (void) dealloc
{
[super dealloc];
}
#end
OpenGL error 0x503 means GL_STACK_OVERFLOW, it means you are pushing too many things onto the opengl stack.
I see several instances of pushScene in your code, but no instances of pop anything anywhere. You cannot just keep pushing things indefinitely without popping them, or you will get this error.
We need to what is currently running in your scene, how it has been allocated and how it is released. We also need to know the same information for the new loaded scene GameLogic. Edit your question and add these data.
ok i am new to coding and cocos2d
i have this shooting code that will fire a projectile and when i try to fire on the left side of the screen it the projectile is fired down and right from the position of the ball?
heres my GamePlay.m
#import "GamePlay.h"
CCSprite *player;
CCSprite *grass;
CCSprite *gameBg;
#implementation GamePlay
+(CCScene *) scene
{
// 'scene' is an autorelease object.
CCScene *scene = [CCScene node];
// 'layer' is an autorelease object.
GamePlay *layer = [GamePlay node];
// add layer as a child to scene
[scene addChild: layer];
// return the scene
return scene;
}
-(id) init
{
// always call "super" init
// Apple recommends to re-assign "self" with the "super" return value
if( (self=[super init]))
{
self.isTouchEnabled = YES;
gameBg = [CCSprite spriteWithFile:#"backgroundGame1.png"];
gameBg.position = ccp(240,160);
[self addChild:gameBg];
grass = [CCSprite spriteWithFile:#"grass.jpg"];
grass.position = ccp(240,25);
[self addChild:grass];
player = [CCSprite spriteWithFile:#"ball.png"];
player.position = ccp(27,95);
[self addChild:player];
x = 5;
y = 5;
}
return self;
}
- (void)ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *myTouch = [touches anyObject];
CGPoint point = [myTouch locationInView:[myTouch view]];
point = [[CCDirector sharedDirector] convertToGL:point];
if (point.x > 240 && point.y < 150)
{
[self unschedule:#selector(moveLeft)];
[self schedule:#selector(moveRight) interval:.01];
}
if (point.x < 240 && point.y < 150)
{
[self unschedule:#selector(moveRight)];
[self schedule:#selector(moveLeft) interval:.01];
}
NSLog(#"Touch Began");
// Choose one of the touches to work with
if (point.y > 150)
{
UITouch *touch = [touches anyObject];
CGPoint location = [touch locationInView:[touch view]];
location = [[CCDirector sharedDirector] convertToGL:location];
CGSize winSize = [[CCDirector sharedDirector]winSize];
CCSprite *projectile = [CCSprite spriteWithFile:#"projectile.png"];
projectile.position = ccp(player.position.x,player.position.y);
int offX = location.x - projectile.position.x;
int offY = location.y - projectile.position.y;
[self addChild:projectile];
int realX = winSize.width + (projectile.contentSize.width/2);
float ratio = (float) offY / (float) offX;
int realY = (realX *ratio) + projectile.position.y;
CGPoint realDest = ccp(realX, realY);
int offRealX = realX - projectile.position.x;
int offRealY = realY - projectile.position.y;
float length = sqrtf((offRealX*offRealX)+(offRealY*offRealY));
float velocity = 480/1;
float realMoveDuration = length/velocity;
[projectile runAction:[CCMoveTo actionWithDuration:realMoveDuration position:realDest]];
NSLog(#"Shoot!");
}
}
-(void)ccTouchesEnded:(NSSet *) touches withEvent:(UIEvent *)event
{
UITouch *myTouch = [touches anyObject];
CGPoint point = [myTouch locationInView:[myTouch view]];
point = [[CCDirector sharedDirector] convertToGL:point];
[self unschedule:#selector(moveLeft)];
[self unschedule:#selector(moveRight)];
NSLog(#"Touch Ended");
}
-(void) spriteMoveFinished: (id) sender
{
}
-(void)moveLeft
{
player.position = ccp(player.position.x - x, player.position.y);
if (player.position.x < 15)
{
player.position = ccp(16,player.position.y);
}
}
-(void)moveRight
{
player.position = ccp(player.position.x + x, player.position.y);
if (player.position.x > 465)
{
player.position = ccp(464,player.position.y);
}
}
#end
this is the shooting method (i think it has something to do with the x & y offset?)
if (point.y > 150)
{
UITouch *touch = [touches anyObject];
CGPoint location = [touch locationInView:[touch view]];
location = [[CCDirector sharedDirector] convertToGL:location];
CGSize winSize = [[CCDirector sharedDirector]winSize];
CCSprite *projectile = [CCSprite spriteWithFile:#"projectile.png"];
projectile.position = ccp(player.position.x,player.position.y);
int offX = location.x - projectile.position.x;
int offY = location.y - projectile.position.y;
[self addChild:projectile];
int realX = winSize.width + (projectile.contentSize.width/2);
float ratio = (float) offY / (float) offX;
int realY = (realX *ratio) + projectile.position.y;
CGPoint realDest = ccp(realX, realY);
int offRealX = realX - projectile.position.x;
int offRealY = realY - projectile.position.y;
float length = sqrtf((offRealX*offRealX)+(offRealY*offRealY));
float velocity = 480/1;
float realMoveDuration = length/velocity;
[projectile runAction:[CCMoveTo actionWithDuration:realMoveDuration position:realDest]];
NSLog(#"Shoot!");
}
The best resource is here
Just give it a try.
Cheers
I found the answer here Projectiles/Bullets direction Cocos2d
you needed to do this,
// After adding the projectile:
[self addChild:projectile];
// Add a scalar float:
float scalarX = 1.0f;
// And make it negative if the touch is left of the character:
if (offX < 0.0f) scalar = -1.0f;
// Then just multiply the realX by this scalar to make it point the correct way
int realX = scalar * (winSize.width + (projectile.contentSize.width/2));