I'm doing the challenge exercises in Aaron Hillegass' book Cocoa Programming for Mac.
What I'm trying to do is have a window resize to twice the height of the width. Here is my code so far.
#import "AppController.h"
#implementation AppController
-(id) init
{
[super init];
NSLog(#"init");
[window setDelegate:self];
return self;
}
-(NSSize) windowWillResize:(NSWindow*) sender
toSize:(NSSize)frameSize
{
int x;
NSSize mySize;
mySize.width = x;
mySize.height = 2*x;
NSLog(#"mySize is %f wide and %f tall",mySize.width,mySize.height);
return mySize;
}
This does not work as intended I'm sure I'm not using the NSSize type correctly. I don't know a lot of C so using the struct is where I think I'm making my mistake.
ADDENDUM: I changed the above code to the following.I know that I'm being passed an NSSize so there is no reason to create another one (i.e. mySize).However, I don't understand why this works. Can someone explain.
#import "AppController.h"
#implementation AppController
-(id) init
{
[super init];
NSLog(#"init");
[window setDelegate:self];
return self;
}
-(NSSize) windowWillResize:(NSWindow*) sender
toSize:(NSSize)frameSize
{
//float x = 100;
//NSSize mySize;
//mySize.width = x;
//mySize.height = x * 2;
//NSLog(#"mySize is %f wide and %f tall",mySize.width,mySize.height);
NSLog(#"mySize is %f wide and %f tall",frameSize.width,frameSize.height);
return NSMakeSize(frameSize.width, frameSize.width * 2);
}
#end
Let's think about what you want mySize to be.
You want its width to be the same as frameSize.width
You want its height to be frameSize.width * 2.
Now let's look at what you do with x:
You set mySize.width to be equal to it
You set mySize.height to be x * 2
From this we can conclude:
You want to set x to frameSize.width.
Alternatively, the entire method could just be return NSMakeSize(frameSize.width, frameSize.width * 2).
You should assign an initial value to x:
int x = 100;
Otherwise, outcome is undefined.
Related
I was wondering if there is any way to get a more accurate version of the contentOffset, or estimate/calculate the contentOffset or (preferably) the first derivative of contentOffset of a UIScrollView. I am trying to perform an action when the rate of change of the contentOffset of my UIScrollView is very small, but 0.5f isn't quite precise enough.
Any help is greatly appreciated.
You can't get better precision than the one provided by contentOffset. You could calculate velocity using regular ds/dt equation:
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
static CGFloat prevPos = 0.0; //you can store those in iVars
static NSTimeInterval prevTime = 0.0;
CGFloat newPos = scrollView.contentOffset.y;
NSTimeInterval newTime = [NSDate timeIntervalSinceReferenceDate];
double v = (newPos - prevPos)/(newTime - prevTime);
prevPos = newPos;
prevTime = newTime;
}
However, if you are feeling extremely hacky, and you want you code to be unsafe, you can peek into UIScrollView's velocity iVars directly by using this category
#interface UIScrollView(UnsafeVelocity)
- (double) unsafeVerticalVelocty;
#end
#implementation UIScrollView(UnsafeVelocity)
- (double) unsafeVerticalVelocty
{
double returnValue = 0.0;
id verticalVel = nil;
#try {
verticalVel = [self valueForKey:#"_verticalVelocity"];
}
#catch (NSException *exception) {
NSLog(#"KVC peek failed!");
}
#finally {
if ([verticalVel isKindOfClass:[NSNumber class]]) {
returnValue = [verticalVel doubleValue];
}
}
return returnValue;
}
#end
To get horizontal velocity replace _verticalVelocity with _horizontalVelocity. Notice, that the values you will get seem to be scaled differently. I repeat once more: while this is (probably) the best value of velocity you can get, it is very fragile and not future-proof.
I'm new to programming and objective-c (so i could be way off here) and i'm working my way through programming in objective c 4th edition text book and have become stuck on one of the exercises.
Can anyone tell what's wrong with the method below? In my program there is a rectangle class which has methods to set it's width, height and it's origin (from a class called XYPoint).
The containsPoint method checks to see if a rectangle's origin is within another rectangle. When i test this method it always returns 'No' even when the rectangle does contain the point.
The intersects method takes a rectangle as an argument (aRect) and uses the containsPoint method in an if statement to check if it intersects with the reciever and if it does, return a rectangle with an origin at the intersect and the correct width and height.
-(BOOL) containsPoint:(XYPoint *) aPoint
{
//create two variables to be used within the method
float upperX, upperY;
//assign them values, add the height and width to the origin values to range which the XYPoint must fall into
upperX = origin.x + height;
upperY = origin.y + width;
//if the value of aPoint's x and y points fall between the object's origin and the upperX or upperY values then the rectangle must contain the XYPoint and a message is sent to NSLog
if ((aPoint.x >= origin.x) && (aPoint.x <= upperX) && (aPoint.y >= origin.y) && (aPoint.y <= upperY) )
{
NSLog(#"Contains point");
return YES;
}
else
{
NSLog(#"Does not contain point");
return NO;
}
}
-(Rectangle *) intersects: (Rectangle *) aRect
{
//create new variables, Rectangle and XYPoint objects to use within the method
Rectangle *intersectRect = [[Rectangle alloc] init];
XYPoint *aRectOrigin = [[XYPoint alloc] init];
float wi, he; //create some variables
if ([self containsPoint:aRect.origin]) { //send the containsPoint method to self to test if the intersect
[aRectOrigin setX:aRect.origin.x andY:origin.y]; //set the origin for the new intersecting rectangle
[intersectRect setOrigin:aRectOrigin];
wi = (origin.x + width) - aRect.origin.x; //determine the width of the intersecting rectangle
he = (origin.y + height) - aRect.origin.y; //determine the height of the intersecting rectangle
[intersectRect setWidth:wi andHeight:he]; //set the rectangle's width and height
NSLog(#"The shapes intersect");
return intersectRect;
}
//if the test returned NO then send back these values
else {
[intersectRect setWidth:0. andHeight:0.];
[aRectOrigin setX:0. andY:0.];
[intersectRect setOrigin:aRectOrigin];
NSLog(#"The shapes do not intersect");
return intersectRect;
}
}
when i test with the following code
int main (int argc, char * argv [])
{
#autoreleasepool {
Rectangle *aRectangle = [[Rectangle alloc] init];
Rectangle *bRectangle = [[Rectangle alloc] init];
Rectangle *intersectRectangle = [[Rectangle alloc] init];
XYPoint *aPoint = [[XYPoint alloc] init];
XYPoint *bPoint = [[XYPoint alloc] init];
[aPoint setX:200.0 andY:420.00];
[bPoint setX:400.0 andY:300.0];
[aRectangle setWidth:250.00 andHeight:75.00];
[aRectangle setOrigin:aPoint];
[bRectangle setWidth:100.00 andHeight:180.00];
[bRectangle setOrigin:bPoint];
printf("Are the points within the rectangle's borders? ");
[aRectangle containsPoint: bPoint] ? printf("YES\n") : printf("NO\n");
intersectRectangle = [aRectangle intersects:bRectangle];
}
return 0;
}
i get the following output
Contains point
The origin is at 0.000000,0.000000, the width is 250.000000 and the height is 75.000000
Here is the code (I'm currently using "Programming in Objective-C 5th edition by Stephen Kochan) and judging by your variables and syntax, it looks like you are too.
// Use Floats for XYPoint and Rectangular exercise 8.4 on pg. 166
import "Rectangle.h"
import "XYPoint.h"
int main(int argc, const char * argv[])
{
#autoreleasepool {
Rectangle *myRect = [[Rectangle alloc] init];
Rectangle *yourRect = [[Rectangle alloc] init];
XYPoint *myPoint = [[XYPoint alloc] init];
XYPoint *yourPoint = [[XYPoint alloc] init];
// For first Rectangle set w, h, origin
[myRect setWidth:250 andHeight:75];
[myPoint setX:200 andY:420];
myRect.origin = myPoint;
// Second Rectangle
[yourRect setWidth:100 andHeight:180];
[yourPoint setX:400 andY:300];
yourRect.origin = yourPoint;
// Find Points of intersection
float x1, x2, y1, y2;
x1 = MAX(myRect.origin.x, yourRect.origin.x);
x2 = MIN(myRect.origin.x + myRect.width, yourRect.origin.x + yourRect.width);
y1 = MAX(myRect.origin.y, yourRect.origin.y);
y2 = MIN(myRect.origin.y + myRect.height, yourRect.origin.y + yourRect.height);
// Make Intersecting Rectangle
Rectangle *intrRect = [[Rectangle alloc] init];
[intrRect setWidth: abs(x2 - x1) andHeight: abs(y2 - y1)];
// Print Intersecting Rectangle's infor for a check
NSLog(#"Width = %g, Height = %g, Bottom point = (%g, %g), Top point = (%g, %g)", intrRect.width, intrRect.height, x1, y1, x2, y2);
}
return 0;
}
Why not just use the included functions for determining intersection and/or containment:
if (CGRectContainsPoint(CGRect rect, CGPoint point))
{
// Contains point...
}
or
if (CGRectIntersectsRect(CGRect rectOne, CGRect rectTwo))
{
// Rects intersect...
}
or
if (CGRectContainsRect(CGRect rectOne, CGRect rectTwo))
{
// RectOne contains rectTwo...
}
You have made a number of errors, both in geometry and Objective-C, but this is how you learn!
Geometry: for two rectangles to intersect the origin of one does not need to be within the area of the other. Your two rectangles intersect but the intersection does not contain either origin. So your containsPoint: will return NO.
You only allocate objects if you create them, not if code which you call creates and returns them. So your allocation in Rectangle *intersectRectangle = [[Rectangle alloc] init]; creates an object which is then discarded by your assignment intersectRectangle = [aRectangle intersects:bRectangle];
For simple classes such as these it is usual to create init methods which set the properties, as creating an object without setting the properties is not useful. E.g. for your XYPoint class you would normally have an initialisation method - (id) initWithX:(float)x andY:(float)y;. You then use [[XYPoint alloc] initWithX:200.0 andY:420.0]] to create and initialise in one go.
As you are experimenting this is not important, but in real code for very simple and small classes which have value semantics - which means they behave much like integers and floats - it is common to use structures (struct) and functions and not objects and methods. Look up the definitions of NSRect and NSPoint as examples.
HTH
//intersect function
-(Rectangle *)intersect:(Rectangle *)secondRec
{
int intersectRectWidth;
int intersectRectHeight;
int intersectRectOriginX;
int intersectRectOriginY;
Rectangle * intersectRec =[[Rectangle alloc]init];
intersectRectOriginX = MAX(self.origin.x,secondRec.origin.x);
intersectRectOriginY = MAX((self.origin.y) , (secondRec.origin.y));
int myWidth=self.width+self.origin.x;
int secondRecWidth=secondRec.width+secondRec.origin.x;
int tempWidth=secondRecWidth - myWidth;
if (tempWidth > 0) {
intersectRectWidth=secondRec.width - tempWidth;
}
else
{
tempWidth=abs(tempWidth);
intersectRectWidth = self.width - tempWidth;
}
//height
int myHeight=self.height+self.origin.y;
int secondRecHeight=secondRec.height +secondRec.origin.y;
int tempHeight=secondRecHeight - myHeight;
if (tempHeight > 0) {
intersectRectHeight=secondRec.height - tempHeight;
}
else
{
tempHeight=abs(tempHeight);
intersectRectHeight = self.height - tempHeight;
}
intersectRec.width=intersectRectWidth;
intersectRec.height=intersectRectHeight;
XYPoint * intersectOrigin =[[XYPoint alloc]init];
[intersectOrigin setX:intersectRectOriginX andY:intersectRectOriginY];
[intersectRec setOrigin:intersectOrigin];
return intersectRec;
}
//main
XYPoint * org1=[[XYPoint alloc]init];
XYPoint * org2=[[XYPoint alloc]init];
Rectangle * firstRec=[[Rectangle alloc]init];
Rectangle * secondRec=[[Rectangle alloc]init];
Rectangle * intersectRec=[[Rectangle alloc]init];
[org1 setX:400 andY:300];
[org2 setX:200 andY:420];
[firstRec setOrigin:org1];
[secondRec setOrigin:org2];
[firstRec setWidth:100 andHeight:180];
[secondRec setWidth:250 andHeight:75];
intersectRec=[firstRec intersect:secondRec];
NSLog(#"intersect rectangle origin.x= %i origin.y=%i width=%i height=%i",intersectRec.origin.x,intersectRec.origin.y,intersectRec.width,intersectRec.height);
First of all, I'm an Objective-C novice. So I'm not very familiar with OS X or iOS development. My experience is mostly in Java.
I'm creating an agent-based modeling-framework. I'd like to display the simulations and to do that I'm writing a little application. First, a little bit about the framework. The framework has a World class, in which there is a start method, which iterates over all agents and has them perform their tasks. At the end of one "step" of the world (i.e., after all the agents have done their thing), the start method calls the intercept method of an object that implements InterceptorProtocol. This object was previously passed in via the constructor. Using the interceptor, anyone can get a hook into the state of the world. This is useful for logging, or in the scenario that I'm trying to accomplish: displaying the information in a graphical manner. The call to intercept is synchronous.
Now as far as the GUI app is concerned, it is pretty simple. I have a controller that initializes a custom view. This custom view also implements InterceptorProtocol so that it can listen in, to what happens in the world. I create a World object and pass in the view as an interceptor. The view maintains a reference to the world through a private property and so once I have initialized the world, I set the view's world property to the world I have just created (I realize that this creates a cycle, but I need a reference to the world in the drawRect method of the view and the only way I can have it is if I maintain a reference to it from the class).
Since the world's start method is synchronous, I don't start the world up immediately. In the drawRect method I check to see if the world is running. If it is not, I start it up in a background thread. If it is, I examine the world and display all the graphics that I need to.
In the intercept method (which gets called from start running on the background thread), I set setNeedsToDisplay to YES. Since the start method of the world is running in a separate thread, I also have a lock object that I use to synchronize so that I'm not working on the World object while it's being mutated (this part is kind of janky and it's probably not working the way I expect it to - there are more than a few rough spots and I'm simply trying to get a little bit working; I plan to clean up later).
My problem is that the view renders some stuff, and then it pretty much locks up. I can see that the NSLog statements are being called and so the code is running, but nothing is getting updated on the view.
Here's some of the pertinent code:
MasterViewController
#import "MasterViewController.h"
#import "World.h"
#import "InfectableBug.h"
#interface MasterViewController ()
#end
#implementation MasterViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
_worldView = [[WorldView alloc] init];
World* world = [[World alloc] initWithName: #"Bhumi"
rows: 100
columns: 100
iterations: 2000
snapshotInterval: 1
interceptor: _worldView];
for(int i = 0; i < 999; i++) {
NSMutableString* name = [NSMutableString stringWithString: #"HealthyBug"];
[name appendString: [[NSNumber numberWithInt: i] stringValue]];
[world addBug: [[InfectableBug alloc] initWithWorld: world
name: name
layer: #"FirstLayer"
infected: NO
infectionRadius: 1
incubationPeriod: 10
infectionStartIteration: 0]];
}
NSLog(#"Added all bugs. Going to add infected");
[world addBug: [[InfectableBug alloc] initWithWorld: world
name: #"InfectedBug"
layer: #"FirstLayer"
infected: YES
infectionRadius: 1
incubationPeriod: 10
infectionStartIteration: 0]];
[_worldView setWorld: world];
//[world start];
}
return self;
}
- (NSView*) view {
return self.worldView;
}
#end
WorldView
#import "WorldView.h"
#import "World.h"
#import "InfectableBug.h"
#implementation WorldView
#synthesize world;
- (id) initWithFrame:(NSRect) frame {
self = [super initWithFrame:frame];
if (self) {
// Initialization code here.
}
return self;
}
- (void) drawRect:(NSRect) dirtyRect {
CGContextRef myContext = [[NSGraphicsContext currentContext] graphicsPort];
CGContextClearRect(myContext, CGRectMake(0, 0, 1024, 768));
NSUInteger rows = [world rows];
NSUInteger columns = [world columns];
NSUInteger cellWidth = 1024 / columns;
NSUInteger cellHeight = 768 / rows;
if([world running]) {
#synchronized (_lock) {
//Ideally we would need layers, but for now let's just get this to display
NSArray* bugs = [world bugs];
NSEnumerator* enumerator = [bugs objectEnumerator];
InfectableBug* bug;
while ((bug = [enumerator nextObject])) {
if([bug infected] == YES) {
CGContextSetRGBFillColor(myContext, 128, 0, 0, 1);
} else {
CGContextSetRGBFillColor(myContext, 0, 0, 128, 1);
}
NSLog(#"Drawing bug %# at %lu, %lu with width %lu and height %lu", [bug name], [bug x] * cellWidth, [bug y] * cellHeight, cellWidth, cellHeight);
CGContextFillRect(myContext, CGRectMake([bug x] * cellWidth, [bug y] * cellHeight, cellWidth, cellHeight));
}
}
} else {
[world performSelectorInBackground: #selector(start) withObject: nil];
}
}
- (BOOL) isFlipped {
return YES;
}
- (void) intercept: (World *) aWorld {
struct timespec time;
time.tv_sec = 0;
time.tv_nsec = 500000000L;
//nanosleep(&time, NULL);
#synchronized (_lock) {
[self setNeedsDisplay: YES];
}
}
#end
start method in World.m:
- (void) start {
running = YES;
while(currentIteration < iterations) {
#autoreleasepool {
[bugs shuffle];
NSEnumerator* bugEnumerator = [bugs objectEnumerator];
Bug* bug;
while((bug = [bugEnumerator nextObject])) {
NSString* originalLayer = [bug layer];
NSUInteger originalX = [bug x];
NSUInteger originalY = [bug y];
//NSLog(#"Bug %# is going to act and location %i:%i is %#", [bug name], [bug x], [bug y], [self isOccupied: [bug layer] x: [bug x] y: [bug y]] ? #"occupied" : #"not occupied");
[bug act];
//NSLog(#"Bug has acted");
if(![originalLayer isEqualToString: [bug layer]] || originalX != [bug x] || originalY != [bug y]) {
//NSLog(#"Bug has moved");
[self moveBugFrom: originalLayer atX: originalX atY: originalY toLayer: [bug layer] atX: [bug x] atY: [bug y]];
//NSLog(#"Updated bug position");
}
}
if(currentIteration % snapshotInterval == 0) {
[interceptor intercept: self];
}
currentIteration++;
}
}
//NSLog(#"Done.");
}
Please let me know if you'd like to see any other code. I realize that the code is not pretty; I was just trying to get stuff to work and I plan on cleaning it up later. Also, if I'm violating an Objective-C best practices, please let me know!
Stepping out for a bit; sorry if I don't respond immediately!
Whew, quiet a question for probably a simple answer: ;)
UI updates have to be performed on the main thread
If I read your code correctly, you call the start method on a background thread. The start method contains stuff like moveBugFrom:... and also the intercept: method. The intercept method thus calls setNeedsDisplay: on a background thread.
Have all UI related stuff perform on the main thread. Your best bet is to use Grand Central Dispatch, unless you need to support iOS < 4 or OS X < 10.6 (or was it 10.7?), like this:
dispatch_async(dispatch_get_main_queue(), ^{
// perform UI updates
});
I've just started with the sparrow framework, and have been following "The Big Sparrow Tutorial" by Gamua themselves. I'm on the first part of the tutorial, using the AppScaffold 1.3 but when I try to compile my basic code it hangs at the loading screen and gives me a SIGABRT error.
I put an exception breakpoint, and it stopped here, in GameController.m (seen at bottom) of the AppScaffold:
mGame = [[Game alloc] initWithWidth:gameWidth height:gameHeight];
This was also my only output:
2012-07-30 07:19:54.787 AppScaffold[1682:10a03] -[Game initWithWidth:height:]: unrecognized selector sent to instance 0x7553980
(lldb)
I am using the stock AppScaffold, the only thing I changed was the Game.m.
This is my Game.m:
#interface Game : SPSprite
#end
#implementation Game
{
#private
SPImage *mBackground;
SPImage *mBasket;
NSMutableArray *mEggs;
}
- (id)init
{
if((self = [super init]))
{
//load the background image first, add it to the display tree
//and keep it for later use
mBackground = [[SPImage alloc] initWithContentsOfFile:#"background.png"];
[self addChild:mBackground];
//load the image of the basket, add it to the display tree
//and keep it for later use
mBasket = [[SPImage alloc] initWithContentsOfFile:#"basket.png"];
[self addChild:mBasket];
//create a list that will hold the eggs,
//which we will add and remove repeatedly during the game
mEggs = [[NSMutableArray alloc] init];
}
return self;
}
- (void)dealloc
{
[mBackground release];
[mBasket release];
[mEggs release];
[super dealloc];
}
#end
I've tried my best to use my basic troubleshooting tactics, but I'm very new to Obj-C and Sparrow and could use a hand :)
Thanks
EDIT: I've addded the GameController.m contents here for clarity:
//
// GameController.m
// AppScaffold
//
#import <OpenGLES/ES1/gl.h>
#import "GameController.h"
#interface GameController ()
- (UIInterfaceOrientation)initialInterfaceOrientation;
#end
#implementation GameController
- (id)initWithWidth:(float)width height:(float)height
{
if ((self = [super initWithWidth:width height:height]))
{
float gameWidth = width;
float gameHeight = height;
// if we start up in landscape mode, width and height are swapped.
UIInterfaceOrientation orientation = [self initialInterfaceOrientation];
if (UIInterfaceOrientationIsLandscape(orientation)) SP_SWAP(gameWidth, gameHeight, float);
mGame = [[Game alloc] initWithWidth:gameWidth height:gameHeight];
mGame.pivotX = gameWidth / 2;
mGame.pivotY = gameHeight / 2;
mGame.x = width / 2;
mGame.y = height / 2;
[self rotateToInterfaceOrientation:orientation animationTime:0];
[self addChild:mGame];
}
return self;
}
- (void)dealloc
{
[mGame release];
[super dealloc];
}
- (UIInterfaceOrientation)initialInterfaceOrientation
{
// In an iPhone app, the 'statusBarOrientation' has the correct value on Startup;
// unfortunately, that's not the case for an iPad app (for whatever reason). Thus, we read the
// value from the app's plist file.
NSDictionary *bundleInfo = [[NSBundle mainBundle] infoDictionary];
NSString *initialOrientation = [bundleInfo objectForKey:#"UIInterfaceOrientation"];
if (initialOrientation)
{
if ([initialOrientation isEqualToString:#"UIInterfaceOrientationPortrait"])
return UIInterfaceOrientationPortrait;
else if ([initialOrientation isEqualToString:#"UIInterfaceOrientationPortraitUpsideDown"])
return UIInterfaceOrientationPortraitUpsideDown;
else if ([initialOrientation isEqualToString:#"UIInterfaceOrientationLandscapeLeft"])
return UIInterfaceOrientationLandscapeLeft;
else
return UIInterfaceOrientationLandscapeRight;
}
else
{
return [[UIApplication sharedApplication] statusBarOrientation];
}
}
- (void)rotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
animationTime:(double)animationTime
{
float angles[] = {0.0f, 0.0f, -PI, PI_HALF, -PI_HALF};
float oldAngle = mGame.rotation;
float newAngle = angles[(int)interfaceOrientation];
// make sure that rotation is always carried out via the minimal angle
while (oldAngle - newAngle > PI) newAngle += TWO_PI;
while (oldAngle - newAngle < -PI) newAngle -= TWO_PI;
// rotate game
if (animationTime)
{
SPTween *tween = [SPTween tweenWithTarget:mGame time:animationTime
transition:SP_TRANSITION_EASE_IN_OUT];
[tween animateProperty:#"rotation" targetValue:newAngle];
[[SPStage mainStage].juggler removeObjectsWithTarget:mGame];
[[SPStage mainStage].juggler addObject:tween];
}
else
{
mGame.rotation = newAngle;
}
// inform all display objects about the new game size
BOOL isPortrait = UIInterfaceOrientationIsPortrait(interfaceOrientation);
float newWidth = isPortrait ? MIN(mGame.gameWidth, mGame.gameHeight) :
MAX(mGame.gameWidth, mGame.gameHeight);
float newHeight = isPortrait ? MAX(mGame.gameWidth, mGame.gameHeight) :
MIN(mGame.gameWidth, mGame.gameHeight);
if (newWidth != mGame.gameWidth)
{
mGame.gameWidth = newWidth;
mGame.gameHeight = newHeight;
SPEvent *resizeEvent = [[SPResizeEvent alloc] initWithType:SP_EVENT_TYPE_RESIZE
width:newWidth height:newHeight animationTime:animationTime];
[mGame broadcastEvent:resizeEvent];
[resizeEvent release];
}
}
// Enable this method for the simplest possible universal app support: it will display a black
// border around the iPhone (640x960) game when it is started on the iPad (768x1024); no need to
// modify any coordinates.
/*
- (void)render:(SPRenderSupport *)support
{
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
{
glEnable(GL_SCISSOR_TEST);
glScissor(64, 32, 640, 960);
[super render:support];
glDisable(GL_SCISSOR_TEST);
}
else
[super render:support];
}
*/
#end
Here is my Xcode project: http://cl.ly/2e3g02260N47
You are calling a
initWithWidth:height:
method, while none is defined in your class.
From your edit, it seems that the initWithWidth method is declared in the class GameController, not in Game.
So, it seems that the
In which context are you calling initWithWidth:height: method is declared in Game.h but you define it in GameController.m.
This explains both why you get the SIGABRT and the errors when compiling.
The fix is calling
mGame = [[GameController alloc] init];
from GameController initWithWidth...
- (id)initWithWidth:(float)width height:(float)height
{
if ((self = [super initWithWidth:width height:height]))
{
float gameWidth = width;
float gameHeight = height;
// if we start up in landscape mode, width and height are swapped.
UIInterfaceOrientation orientation = [self initialInterfaceOrientation];
if (UIInterfaceOrientationIsLandscape(orientation)) SP_SWAP(gameWidth, gameHeight, float);
mGame = [[Game alloc] init];
mGame.pivotX = gameWidth / 2;
mGame.pivotY = gameHeight / 2;
mGame.x = width / 2;
mGame.y = height / 2;
[self rotateToInterfaceOrientation:orientation animationTime:0];
[self addChild:mGame];
}
return self;
}
The tutorial was very old and was incompatible with the latest scaffold;
I did this:
- (id)init
{
if((self = [super init]))
{
when I should've done this:
- (id)initWithWidth:(float)width height:(float)height
{
if ((self = [super initWithWidth:width height:height]))
{
thanks, though sergio!
(There are much better sparrow tutorials and I'm even making my own video tutorials :P)
SOLUTION:
Simply separating the method call
Tile *tile = [[Tile alloc] initWithX:x Y:y];
into two separate lines such as:
Tile *tile = [Tile alloc];
[tile initWithX:x Y:y];
caused the method to stop receiving the ints as memory pointers. I'm baffled as to why this occurred but it fixed the problems. Any explanations as to why this happened would be appreciated. Thanks to all for the help!
ORIGINAL POST:
This is a bit of a weird question as I've run into this problem while doing a tutorial at: http://www.iphonegametutorials.com/2010/09/23/cocos2d-game-tutorial-building-a-slide-image-game/.
The program I have typed out works except for the switching of tiles, and I have looked in the XCode debugger and it seems that my x and y values for the Tile class are being set way to absurdly high values. The weird thing is, when the values are passed to the method (initWithX:Y:) from the original method (initWithSize:imgSize:) they are what they should be, but when they arrive at the method they are huge (for example: in one instance an x passed as '1' becomes '1065353216' when it arrives at the method.)
I have a feeling that it may be pointing to the memory location of the passed int, but I don't see any reason why it should be in my code. See below.
-(id)initWithSize:(CGSize)aSize imgSize:(int)aImgValue {
self = [super init];
imgValue = aImgValue;
size = aSize;
OutBorderTile = [[Tile alloc] initWithX:-1 Y:-1];
content = [NSMutableArray arrayWithCapacity:size.height];
readyToRemoveTiles = [NSMutableSet setWithCapacity:50];
for(int y = 0; y < size.height; y++) {
NSMutableArray *rowContent = [NSMutableArray arrayWithCapacity:size.width];
for (int x = 0; x < size.width; x++) {
Tile *tile = [[Tile alloc] initWithX:x Y:y];
[rowContent addObject:tile];
[readyToRemoveTiles addObject:tile];
[tile release];
}
[content addObject:rowContent];
[content retain];
}
[readyToRemoveTiles retain];
return self;
}
-(id)initWithX:(int)posX Y:(int)posY {
self = [super init];
x = posX;
y = posY;
return self;
}
Everything should be the same as in the linked tutorial, but I can't see anybody else complaining of the same problem.
I have also noted that if I go into the debugger and manually change the posX and posY values in the initWithX method that the tile switching code works, so my problem definitely lies with the really large int values forming in that method.
Edit for Jim: Hopefully this shows a more complete picture of the layout I have for the Tile object.
#interface Tile : NSObject {
int x, y, value;
CCSprite *sprite;
}
#property(nonatomic, readonly) int x, y;
#property(nonatomic) int value;
#property(nonatomic, retain) CCSprite *sprite;
#end
#implementation Tile
#synthesize x, y, value, sprite;
// Code is logged in below.
-(id)initWithX:(int)posX Y:(int)posY {
self = [super init];
x = posX;
y = posY;
return self;
}
#end
Somewhere, the x and/or y value are being assigned to a pointer. One thing I would check is to make sure you aren't declaring your ints as pointers to ints. I.e. int *x, etc.