Changing State for an object in Cocos2d - cocos2d-iphone

firstly i would like to apologise for being a complete novice but I have researched the web and can not find a solution to my current problem.
I have 3 objects (sprites) that i have set up individually with switch statements and want to use my main gameplay layer to change their states randomly to an animation that i have already defined in the objects individual header and implementation files.
I have set up a self schedule updater and arc4random method that works but it will not change the state of the object, as it only calls the CCLOG that I have also included in the statement.
I have listed to code below and i know it is a bit of a mess but still very much in my first steps of being a beginner, if anyone can point me in the right direction (that's if i have explained this in a way you can understand!) I would be very grateful.
Thanks in advance for even looking at this question.
//-------------------below is my gameplaylayer header file---------//
// GamePlayLayer.h
#import <Foundation/Foundation.h>
#import "cocos2d.h"
#import "CCLayer.h"
#import "SneakyJoystick.h"
#import "SneakyButton.h"
#import "SneakyButtonSkinnedBase.h"
#import "SneakyJoystickSkinnedBase.h"
#import "Constants.h"
#import "CommonProtocols.h"
#import "TBT.h"
#import "MBT.h"
#import "BBT.h"
#import "BC.h"
#import "GameCharacter.h"
#import <stdlib.h>
#interface GamePlayLayer : CCLayer <GamePlayLayerDelegate> {
CCSprite *vikingSprite;
SneakyJoystick *leftJoystick;
SneakyButton *jumpButton;
SneakyButton *attackButton;
CCSpriteBatchNode *sceneSpriteBatchNode;
}
#property (readwrite) CharacterStates characterState;
-(void)changeState:(CharacterStates)newState;
-(void)addEnemy;
#end
//---------------------Below is my gameplaylayer implementation file-------------//
// GamePlayLayer.m
#import "GamePlayLayer.h"
#implementation GamePlayLayer
#synthesize characterState;
-(void) dealloc {
[leftJoystick release];
[jumpButton release];
[attackButton release];
[super dealloc];
}
-(void)initJoystickAndButtons {
CGSize screenSize = [CCDirector sharedDirector].winSize;
//---DELETED MOST OF THE ABOVE METHOD AS NOT NEEDED FOR THIS QUESTION----//
-(void) update:(ccTime)deltaTime {
CCArray *listOfGameObjects =
[sceneSpriteBatchNode children];
for (GameCharacter *tempChar in listOfGameObjects) {
[tempChar updateStateWithDeltaTime:deltaTime andListOfGameObjects:listOfGameObjects];
}
}
-(void) createObjectOfType: (GameObjectType)objectType
withHealth:(int)initialHealth atLocation:(CGPoint)spawnLocation withZValue:(int)ZValue {
if (objectType == kEnemyType1BT) {
CCLOG(#"creating the 1BT");
TBT *tBT = [[TBT alloc] initWithSpriteFrameName:#"BT_anim_1.png"];
[tBT setCharacterHealth:initialHealth];
[tBT setPosition:spawnLocation];
[sceneSpriteBatchNode addChild:tBT
z:ZValue
tag:k1BTtagValue];
[tBT release];}
if (objectType == kEnemyType3BT){
CCLOG(#"creating the radar enemy");
BBT *bBT = [[BBT alloc] initWithSpriteFrameName:#"BT_anim_1.png"];
[bBT setCharacterHealth:initialHealth];
[bBT setPosition:spawnLocation];
[sceneSpriteBatchNode addChild:bBT
z:ZValue
tag:k3BTtagValue];
[bBT release];
}
if (objectType == kEnemyType2BT){
CCLOG(#"creating the radar enemy");
MBT *mBT = [[MBT alloc] initWithSpriteFrameName:#"BT_anim_1.png"];
[mBT setCharacterHealth:initialHealth];
[mBT setPosition:spawnLocation];
[sceneSpriteBatchNode addChild:mBT
z:ZValue
tag:k2BTtagValue];
[mBT release];
}
}
//--PROBLEM I HAVE IS BELOW--//
-(void)addEnemy {
int x = (arc4random() % 3);
TBT *tBT = (TBT*)
[sceneSpriteBatchNode getChildByTag:kEnemyType1BT];
//--Just using one object(sprite) to begin with--//
if (x>0) {
CCLOG(#"RANDOM KSTATETEST!!!!!!");
[tBT changeState:kStatetest]; <---it is not changing state to kStatetest
}
-(id)init {
self = [super init];
if (self !=nil) {
CGSize screenSize = [CCDirector sharedDirector]. winSize;
self.TouchEnabled = YES;
srandom(time(NULL));
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
[[CCSpriteFrameCache sharedSpriteFrameCache]
addSpriteFramesWithFile:#"scene1atlas.plist"]; // 1
sceneSpriteBatchNode =
[CCSpriteBatchNode batchNodeWithFile:#"scene1atlas.png"]; // 2
} else {
[[CCSpriteFrameCache sharedSpriteFrameCache]
addSpriteFramesWithFile:#"scene1atlasiPhone.plist"]; // 1
sceneSpriteBatchNode =
[CCSpriteBatchNode batchNodeWithFile:#"scene1atlasiPhone.png"];// 2
}
[self addChild:sceneSpriteBatchNode z:0]; // 3
[self initJoystickAndButtons]; // 4
BC *viking = [[BC alloc]
initWithSpriteFrame:[[CCSpriteFrameCache
sharedSpriteFrameCache]
spriteFrameByName:#"BCmoving_anim_1.png"]];
//[viking setJoystick:leftJoystick];
[viking setJumpButton:jumpButton];
[viking setAttackButton:attackButton];
[viking setPosition:ccp(screenSize.width * 0.19f,
screenSize.height * 0.19f)];
[viking setCharacterHealth:3];
[sceneSpriteBatchNode
addChild:viking
z:kVikingSpriteZValue
tag:kVikingSpriteTagValue]; heatlh is set to 100
[self schedule:#selector(addEnemy) interval:1.0f];
[self createObjectOfType:kEnemyType1BT withHealth:3 atLocation:ccp(screenSize.width * 0.0439f, screenSize.height * 0.822f) withZValue:10];
[self createObjectOfType:kEnemyType3BT withHealth:3 atLocation:ccp(screenSize.width * 0.0439f, screenSize.height * 0.45f) withZValue:10];
[self createObjectOfType:kEnemyType2BT withHealth:3 atLocation:ccp(screenSize.width * 0.0439f, screenSize.height * 0.638f) withZValue:10];
//Sets up the schedular call that will fire the update method in GamePlayLayer.m every frame.
[self scheduleUpdate];
}
return self;
}
#end
//----------------- below is one of my objects header files--------------//
#import <Foundation/Foundation.h>
#import "GameCharacter.h"
#interface TBT : GameCharacter{
CCAnimation *tiltingAnim;
CCAnimation *transmittingAnim;
CCAnimation *loseLifeAnim;
CCAnimation *throwingAnim;
CCAnimation *afterThrowingAnim;
CCAnimation *shootPhaserAnim;
GameCharacter *vikingCharacter;
id <GamePlayLayerDelegate> delegate;
}
#property (nonatomic,assign) id <GamePlayLayerDelegate> delegate;
#property (nonatomic, retain) CCAnimation *tiltingAnim;
#property (nonatomic, retain) CCAnimation *transmittingAnim;
//#property (nonatomic, retain) CCAnimation *takingAHitAnim;
#property (nonatomic, retain) CCAnimation *loseLifeAnim;
#property (nonatomic, retain) CCAnimation *throwingAnim;
#property (nonatomic,retain) CCAnimation *afterThrowingAnim;
#property (nonatomic,retain) CCAnimation *shootPhaserAnim;
-(void)initAnimations;
#end
//-----------------below is the .m file for one of my objects--------------//
#import "TBT.h"
#implementation TBT
#synthesize delegate;
#synthesize tiltingAnim;
#synthesize transmittingAnim;
#synthesize loseLifeAnim;
#synthesize throwingAnim;
#synthesize afterThrowingAnim;
#synthesize shootPhaserAnim;
-(void) dealloc {
delegate = nil;
[tiltingAnim release];
[transmittingAnim release];
[loseLifeAnim release];
[throwingAnim release];
[afterThrowingAnim release];
[shootPhaserAnim release];
[super dealloc];
}
-(void)shootPhaser {
CGPoint phaserFiringPosition;
PhaserDirection phaserDir;
CGRect boundingBox = [self boundingBox];
CGPoint position = [self position];
float xPosition = position.x + boundingBox.size.width * 0.542f;
float yPosition = position.y + boundingBox.size.height * 0.25f;
if ([self flipX]) {
CCLOG(#"TBT Facing right, Firing to the right");
phaserDir = kDirectionRight;
} else {
CCLOG(#"TBT Facing left, Firing to the left");
xPosition = xPosition * -1.0f;
phaserDir = kDirectionLeft;
}
phaserFiringPosition = ccp(xPosition, yPosition);
[delegate createPhaserWithDirection:phaserDir andPosition:phaserFiringPosition];
}
-(void)changeState:(CharacterStates)newState {
[self stopAllActions];
id action = nil;
[self setCharacterState:newState];
switch (newState) {
case kStatespawning:
CCLOG(#"TBT->Changing State to Spwaning");
[self setDisplayFrame:
[[CCSpriteFrameCache sharedSpriteFrameCache]
spriteFrameByName:#"BT_anim_1.png"]];
break;
case kStateIdle:
CCLOG(#"TBT->schaning state to idle");
[self setDisplayFrame:
[[CCSpriteFrameCache sharedSpriteFrameCache]
spriteFrameByName:#"BT_anim_1.png"]];
break;
case kStatetest:
CCLOG(#"TBT->Changing State to test");
action = [CCSequence actions : [CCDelayTime actionWithDuration:1.5f],[CCAnimate actionWithAnimation:transmittingAnim], nil];
break;
default:
CCLOG(#"unhandled state %d in TBT", newState);
break;
}
if (action !=nil) {
[self runAction:action];
}
}
-(void)updateStateWithDeltaTime: (ccTime)deltaTime andListOfGameObjects:(CCArray*)listOfGameObjects {
if (characterState == kStateDead)
return;
if ((([self numberOfRunningActions] == 0) && (characterState != kStateDead)) ) {
CCLOG(#"TBT Going to Idle");
[self changeState:kStateIdle];
return;
}
}
-(void)initAnimations {
[self setTiltingAnim:[self loadPlistForAnimationWithName:#"tiltingAnim" andClassName:NSStringFromClass([self class])]];
[self setTransmittingAnim:[self loadPlistForAnimationWithName:#"transmittingAnim" andClassName:NSStringFromClass([self class])]];
}
-(id) initWithSpriteFrameName:(NSString*)frameName{
if ((self=[super init])) {
if ((self = [super initWithSpriteFrameName:frameName])) {
CCLOG(#"### TBT initialized");
[self initAnimations];
characterHealth = 3.0f;
gameObjectType = kEnemyType1BT;
[self changeState:kStatespawning];
}}
return self;
}
#end

Finally found out that all I needed was to add the following code to my TBT gameCharacters-(void)updateStateWithDeltaTime: method...
if (characterState == kStateTest) {
if (characterState != kStateTest) {
[self changeState:kStateTest];
return;
}
now it works fine.
Thanks again to Mikael for trying to help me.

Related

Cocos2d: Controller calling method of a CCNode

My GameController.m calls a method of CCNode class. It seems to call it as I can see NSLog but the method is not either operate or not result in view. In other words, screen does not change when calling the method from GameController. (method operates itself in its own class)
How should I change my code to fix it?
Summary:
GameController -> calls -> GoalPost.GoalKeeper.method.
Code:
GameController.m, GoalPost.m and GoalKeeper.m
GameController.m
#import "GameController.h"
#import "cocos2d-ui.h"
#import "GoalPost.h"
#import "Ball.h"
#import "Field.h"
#interface GameController()
#property Field* field;
//#property Ball* ball;
#property GoalPost* post;
#end
#implementation GameController
- (instancetype)init
{
self = [super init];
if (self) {
self.field = [Field node];
// self.ball = [Ball node];
self.post = [GoalPost node];
}
return self;
}
//control computer.
-(void)kickerTurn{
NSLog(#"Player kick");
//random location generation
//call keeper.
int randomKeeperX = arc4random() % (int)self.post.contentSize.width;
int randomKeeperY = arc4random() % (int)self.post.contentSize.height;
CGPoint keeperLoc = ccp(randomKeeperX, randomKeeperY);
[self.post.keeper keeperLocation:keeperLoc];
}
#end
GoalPost.h
#import "GoalKeeper.h"
#interface GoalPost : CCNodeColor { }
#property GoalKeeper* keeper;
#end
GoalPost.m
#import "GoalPost.h"
#import "GoalKeeper.h"
#interface GoalPost ()
#property NSArray* post;
#end
#implementation GoalPost
- (instancetype)init
{
self = [super initWithColor:[CCColor lightGrayColor]];
if (self) {
....
[self addChild:aPost];
}
//Call goal keeper and add.
//for touch to run goal keeper.
[self setUserInteractionEnabled:true];
self.keeper = [GoalKeeper node];
//Put it in front of goal post.
self.keeper.position = ccp(self.contentSize.width/2, 0);
[self addChild:self.keeper];
}
return self;
}
-(void)touchBegan:(UITouch *)touch withEvent:(UIEvent *)event{
CGPoint touchLoc = [touch locationInNode:self];
NSLog(#"Goal touched: %f %f", touchLoc.x, touchLoc.y);
//Goal keeper call
[self.keeper keeperLocation:touchLoc];
}
#end
Finally, GoalKeeper.m
.h
#import "cocos2d.h"
#interface GoalKeeper : CCNodeColor { }
-(void)keeperLocation:(CGPoint)location;
#end
.m
#import "GoalKeeper.h"
#interface GoalKeeper()
#property CGPoint touchLoc;
#end
#implementation GoalKeeper
- (instancetype)init
{
self = [super initWithColor:[CCColor blueColor]];
if (self) {
[self setUserInteractionEnabled:TRUE];
[self setContentSize:CGSizeMake(30, 70)];
}
return self;
}
-(void)keeperLocation:(CGPoint)location {
CGPoint offset = ccpSub(location, self.position);
int targetX = self.position.x + offset.x;
int targetY = self.position.y + offset.y;
CGPoint targetPosition = ccp(targetX, targetY);
CCActionMoveBy *actionMoveBy = [CCActionMoveBy actionWithDuration:0.5f position:offset];
[self runAction:actionMoveBy];
}
#end

EXC_BAD_ACCESS when using NSKeyedUnarchiver to load saved state

I have subclassed a CCSprite to make an object that can be encoded and decoded. I want to save sprites state and load it again at particular positions. Everything seems to be okay apart from decoding with NSKeyedUnarchiver (see loadIconSpriteState below) which gives an EXC_BAD_ACCESS Below is the code:
HelloWorldLayer.h
#interface CCIconSprite : CCSprite {
NSString *iconName;
float iconXPos;
float iconYPos;
}
#property (nonatomic, retain) NSString *iconName;
#property (nonatomic, assign) float iconXPos;
#property (nonatomic, assign) float iconYPos;
+ (id)iconWithType:(NSString*)imageName;
- (id)initWithIconType:(NSString*)imageName;
#end
#interface HelloWorldLayer : CCLayer < NSCoding>
{
CCIconSprite* testSprite;
BOOL savedState;
CGSize size;
CCMoveTo* moveTo;
NSMutableArray* saveSpriteArray;
NSData* savedSpriteData;
}
+(CCScene *) scene;
#end
HelloWorldLayer.m:
CCIconSprite implementation:
#implementation CCIconSprite
#synthesize iconXPos;
#synthesize iconYPos;
#synthesize iconName;
+ (id)iconWithType:(NSString*)imageName
{
return [[[[self class] alloc] initWithIconType:imageName] autorelease];
}
- (id)initWithIconType:(NSString*)imageName
{
self = [super initWithFile:imageName];
if (!self) return nil;
iconName = imageName;
self.position = ccp(iconXPos, iconYPos);
return self;
}
Encoding and decoding:
- (id)initWithCoder:(NSCoder *)decoder {
NSString* imageFileName = [decoder decodeObjectForKey:#"imageFileName"];
self = [self initWithIconType:imageFileName];
if (!self) return nil;
self.iconXPos = [decoder decodeFloatForKey:#"iconXPos"];
self.iconYPos = [decoder decodeFloatForKey:#"iconYPos"];
return self;
}
- (void)encodeWithCoder:(NSCoder *)encoder
{
[encoder encodeObject:iconName forKey:#"imageFileName"];
[encoder encodeFloat:self.iconXPos forKey:#"iconXPos"];
[encoder encodeFloat:self.iconYPos forKey:#"iconYPos"];
}
#end
HelloWorldLayer implementation:
#implementation HelloWorldLayer
+(CCScene *) scene
{
CCScene *scene = [CCScene node];
HelloWorldLayer *layer = [HelloWorldLayer node];
[scene addChild: layer];
return scene;
}
-(id) init
{
if( (self=[super init]) ) {
self.scale = 0.5;
savedState = NO;
size = [[CCDirector sharedDirector] winSize];
testSprite = [CCIconSprite spriteWithFile:#"Icon.png"];
testSprite.position = ccp(size.width/4, size.width/4);
testSprite.anchorPoint = ccp(0,0);
[self addChild:testSprite];
moveTo = [CCMoveTo actionWithDuration:3 position:ccp(3*size.width/4, 3*size.width/4)];
[testSprite runAction:moveTo];
[self schedule:#selector(saveAndLoadSpriteState)];
}
return self;
}
Saving and loading state:
-(void)saveIconSpriteState {
saveSpriteArray = [[NSMutableArray alloc] init];
[saveSpriteArray addObject:testSprite];
savedSpriteData = [NSKeyedArchiver archivedDataWithRootObject:saveSpriteArray];
}
-(void)loadIconSpriteState {
[NSKeyedUnarchiver unarchiveObjectWithData:savedSpriteData];
}
-(void)saveAndLoadSpriteState {
if ((testSprite.position.x > size.width/2) && !savedState) {
savedState = YES;
[self saveIconSpriteState];
}
else if ((testSprite.position.x == 3*size.width/4) && savedState) {
savedState = NO;
[self loadIconSpriteState];
[testSprite runAction:moveTo];
}
}
#end
EDIT
After setting an exception break point I got the following error
Assertion failure in -[CCIconSprite initWithFile:]
pointing to the in line:
NSAssert(filename != nil, #"Invalid filename for sprite");
in the
-(id) initWithFile:(NSString*)filename
method of the CCSprite.m class.
Just a hunch but maybe that's it. When decoding a string, you should copy it because you don't own it at this point, nor are you assigning it to a strong or copy property.
- (id)initWithCoder:(NSCoder *)decoder {
NSString* imageFileName = [[decoder decodeObjectForKey:#"imageFileName"] copy];
self = [self initWithIconType:imageFileName];
if (!self) return nil;
...
}
If that's not it, set a breakpoint and verify that the string is indeed correct when encoding and when decoding.

cocos2d add layers on scene

I know that my question might be stupid but I searched and I can't find why it's not working.
I create a CCLayer class BackgroundLayer with implementation below:
#import "BackgroundLayer.h"
#implementation BackgroundLayer
- (id)init {
if (self != nil) {
CCSprite *background = [CCSprite spriteWithFile:#"menu.png"];
background.anchorPoint = ccp(0, 0);
[self addChild:background z:-1];
NSLog(#"test");
}
return self;
}
#end
and I want to add it on main menu scene and I have:
#import "MainMenuScene.h"
#import "BackgroundLayer.h"
#implementation MainMenuScene
+ (id)scene {
CCScene *scene = [CCScene node];
BackgroundLayer *backgroundLayer = [BackgroundLayer node];
[scene addChild:backgroundLayer];
return scene;
}
- (id)init {
self = [super init];
if (self != nil) {
}
return self;
}
#end
My problem is that NSLog test appears but the background doesn't load. If I add the background on the init method of MainMenuScene it works... Shouldn't I suppose that the layer works this way?
Not sure if related but you forgot self = [super init]; in BackgroundLayer.
Try commenting out the anchor point line to see if the image shows up then.

UITableView is not reloading

here is the situation:
I have a "UITableViewController" which loads objects with RestKits "RKFetchedResultsTableController". After clicking on a cell I switch to a detail UITableViewController also driven by a "RKFetchedResultsTableController" which gives me a corresponding answer text for the selected object.
The problem is now, if I go back to the first "UITableViewController" and select another object in the table the old answer text from the previous selected object is in the detail table. If I use the "pullToRefresh" function the table gets refreshed and the correct answer is loading.
Why is the old answer from the previous object still in the tableView and not the correct answer for the new selected Object even if I tell [tableController loadTable] in the viewWillAppear method.
AppDelegate:
#
interface AppDelegate ()
#property (nonatomic, strong, readwrite) RKObjectManager *objectManager;
#property (nonatomic, strong, readwrite) RKManagedObjectStore *objectStore;
#end;
#implementation AppDelegate
#synthesize window = _window, isAuthenticated;
#synthesize objectManager;
#synthesize objectStore;
- (void)initializeRestKit
{
//self.objectManager = [RKObjectManager managerWithBaseURLString:#"http://falling-ocean-1302.herokuapp.com"];
self.objectManager = [RKObjectManager managerWithBaseURLString:#"http://falling-ocean-1302.herokuapp.com"];
self.objectManager.serializationMIMEType = RKMIMETypeJSON;
self.objectManager.acceptMIMEType = RKMIMETypeJSON;
self.objectStore = [RKManagedObjectStore objectStoreWithStoreFilename:#"MMmtvzme.sqlite"];
self.objectManager.objectStore = self.objectStore;
self.objectManager.mappingProvider = [MMMappingProvider mappingProviderWithObjectStore:self.objectStore];
self.objectManager.client.cachePolicy = RKRequestCachePolicyNone;
RKLogConfigureByName("RestKit", RKLogLevelTrace);
RKLogConfigureByName("RestKit/Network", RKLogLevelTrace);
RKLogConfigureByName("RestKit/ObjectMapping", RKLogLevelTrace);
RKLogConfigureByName("RestKit/Network/Queue", RKLogLevelTrace);
// Enable automatic network activity indicator management
objectManager.client.requestQueue.showsNetworkActivityIndicatorWhenBusy = YES;
[objectManager.router routeClass:[MMRequest class] toResourcePath:#"/requests" forMethod:RKRequestMethodPOST];
[objectManager.router routeClass:[MMRequest class] toResourcePath:#"/requests" forMethod:RKRequestMethodDELETE];
[objectManager.router routeClass:[MMAnswer class] toResourcePath:#"/requests/:request_id/answers" forMethod:RKRequestMethodPOST];
}
Ok this is the code from the first UITableViewController
#interface MMMyRequestList ()
#property (nonatomic, strong) RKFetchedResultsTableController *tableController;
#end
#implementation MMMyRequestList
#synthesize tableController;
- (void)viewDidLoad
{
[super viewDidLoad];
[self configureRKTableController];
[self configureCellMapping];
[self useCustomNib];
}
- (void)configureRKTableController{
self.tableController = [[RKObjectManager sharedManager] fetchedResultsTableControllerForTableViewController:self];
self.tableController.autoRefreshFromNetwork = YES;
self.tableController.pullToRefreshEnabled = YES;
self.tableController.resourcePath = #"/requests";
self.tableController.variableHeightRows = YES;
NSSortDescriptor *descriptor = [NSSortDescriptor sortDescriptorWithKey:#"request_id" ascending:NO];
self.tableController.sortDescriptors = [NSArray arrayWithObject:descriptor];
tableController.canEditRows = YES;
}
- (void)configureCellMapping{
RKTableViewCellMapping *cellMapping = [RKTableViewCellMapping cellMapping];
cellMapping.cellClassName = #"MMRequestCell";
cellMapping.reuseIdentifier = #"MMRequest";
cellMapping.rowHeight = 100.0;
[cellMapping mapKeyPath:#"title" toAttribute:#"requestLabel.text"];
[cellMapping mapKeyPath:#"user.first_name" toAttribute:#"userLabel.text"];
cellMapping.onSelectCellForObjectAtIndexPath = ^(UITableViewCell *cell, id object, NSIndexPath* indexPath)
{
MMMyRequestListAnswer * uic = [self.storyboard instantiateViewControllerWithIdentifier:#"MMMyRequestListAnswer"];
MMRequest *request = [self.tableController objectForRowAtIndexPath:indexPath];
if ([uic respondsToSelector:#selector(setRequest:)]) {
[uic setRequest:request];
}
[self.navigationController pushViewController:uic animated:YES];
};
[tableController mapObjectsWithClass:[MMRequest class] toTableCellsWithMapping:cellMapping];
}
- (void)useCustomNib{
[self.tableView registerNib:[UINib nibWithNibName:#"MMRequestCell" bundle:nil] forCellReuseIdentifier:#"MMRequest"];
}
- (void)objectLoader:(RKObjectLoader*)objectLoader didFailWithError:(NSError*)error {
UIAlertView* alert = [[UIAlertView alloc] initWithTitle:#"Error"
message:[error localizedDescription]
delegate:nil
cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alert show];
NSLog(#"Hit error: %#", error);
}
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
/**
Load the table view!
*/
[tableController loadTable];
}
After clicking on a cell the Detail UIViewController come into action
interface MMMyRequestListAnswer ()
#property (nonatomic, strong) RKFetchedResultsTableController *tableController;
#end
#implementation MMMyRequestListAnswer
#synthesize tableHeaderView, requestTextLabel;
#synthesize request;
#synthesize tableController;
- (void)viewDidLoad
{
[super viewDidLoad];
[self configureRKTableController];
[self configureCellMapping];
[self useCustomNib];
}
- (void)configureRKTableController{
self.tableController = [[RKObjectManager sharedManager] fetchedResultsTableControllerForTableViewController:self];
self.tableController.autoRefreshFromNetwork = YES;
self.tableController.pullToRefreshEnabled = YES;
self.tableController.resourcePath = [NSString stringWithFormat:#"/requests/%i/answers", [self.request.request_id intValue]];
self.tableController.variableHeightRows = YES;
NSSortDescriptor *descriptor = [NSSortDescriptor sortDescriptorWithKey:#"answer_id" ascending:NO];
self.tableController.sortDescriptors = [NSArray arrayWithObject:descriptor];
}
- (void)configureCellMapping{
RKTableViewCellMapping *cellMapping = [RKTableViewCellMapping cellMapping];
cellMapping.cellClassName = #"MMRequestAnswerCell";
cellMapping.reuseIdentifier = #"MMAnswer";
cellMapping.rowHeight = 80.0;
[cellMapping mapKeyPath:#"text" toAttribute:#"answerLabel.text"];
[cellMapping mapKeyPath:#"user.first_name" toAttribute:#"userLabel.text"];
[tableController mapObjectsWithClass:[MMAnswer class] toTableCellsWithMapping:cellMapping];
}
- (void)useCustomNib{
[self.tableView registerNib:[UINib nibWithNibName:#"MMRequestAnswerCell" bundle:nil] forCellReuseIdentifier:#"MMAnswer"];
}
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
/**
Load the table view!
*/
[tableController loadTable];
}
The Object Mapping is handled in this Class:
#implementation MMMappingProvider
#synthesize objectStore;
+ (id)mappingProviderWithObjectStore:(RKManagedObjectStore *)objectStore {
return [[self alloc] initWithObjectStore:objectStore];
}
- (id)initWithObjectStore:(RKManagedObjectStore *)theObjectStore {
self = [super init];
if (self) {
self.objectStore = theObjectStore;
[self setObjectMapping:[self requestObjectMapping] forResourcePathPattern:#"/requests" withFetchRequestBlock:^NSFetchRequest *(NSString *resourcePath) {
NSFetchRequest *fetchRequest = [MMRequest fetchRequest];
return fetchRequest;
}];
[self setObjectMapping:[self answerObjectMapping] forResourcePathPattern:#"/requests/:request_id/answers" withFetchRequestBlock:^NSFetchRequest *(NSString *resourcePath) {
NSFetchRequest *fetchRequest = [MMAnswer fetchRequest];
fetchRequest.sortDescriptors = [NSArray arrayWithObject:[NSSortDescriptor sortDescriptorWithKey:#"answer_id" ascending:YES]];
return fetchRequest;
}];
[self setSerializationMapping:[self.requestObjectMapping inverseMapping] forClass:[MMRequest class]];
[self setSerializationMapping:[self.answerObjectMapping inverseMapping] forClass:[MMAnswer class]];
[self setSerializationMapping:[self.userObjectMapping inverseMapping] forClass:[MMUser class]];
}
return self;
}
- (RKManagedObjectMapping *)userObjectMapping {
RKManagedObjectMapping *mapping = [RKManagedObjectMapping mappingForEntityWithName:#"MMUser" inManagedObjectStore:self.objectStore];
mapping.primaryKeyAttribute = #"user_id";
[mapping mapAttributes:#"first_name", nil];
[mapping mapKeyPathsToAttributes:
#"id", #"user_id",
nil];
return mapping;
}
- (RKManagedObjectMapping *)answerObjectMapping {
RKManagedObjectMapping *mapping = [RKManagedObjectMapping mappingForEntityWithName:#"MMAnswer" inManagedObjectStore:self.objectStore];
mapping.primaryKeyAttribute = #"answer_id";
[mapping mapAttributes:#"text",#"request_id",#"user_id", nil];
[mapping mapKeyPathsToAttributes:
#"id", #"answer_id",
nil];
[mapping mapKeyPath:#"user" toRelationship:#"user" withMapping:[self userObjectMapping]];
[mapping mapKeyPath:#"request" toRelationship:#"request" withMapping:[self requestObjectMapping]];
return mapping;
}
- (RKManagedObjectMapping *)requestObjectMapping {
RKManagedObjectMapping *mapping = [RKManagedObjectMapping mappingForEntityWithName:#"MMRequest" inManagedObjectStore:self.objectStore];
mapping.primaryKeyAttribute = #"request_id";
[mapping mapAttributes:#"title",#"user_id", nil];
[mapping mapKeyPathsToAttributes:
#"id", #"request_id",
nil];
[mapping mapKeyPath:#"user" toRelationship:#"user" withMapping:[self userObjectMapping]];
return mapping;
}
OK Figured it out!!! Some digging revealed that I was loading my UITableviewcontroller BEFORE the mapping provider.
The fix was, to take [self initialiserestkit] method in - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
and put it before any of the code in this method (i.e. make [self initialiserestkit] the first line of the didfinishlaunchingwithoptions method.
Issue solved. Now the tableview is loaded AFTER the mappings so everything works as it should.

Cocos2d: CGRect, UITouch - Object/Class not detecting a location within its bounds

I'm creating a CGRect within a class (Path). I've verified that the the class is creating the rectangle. Now, I've built a method into the class that should, in theory, return true when asked if a touch location is within the rectangle. Problem is, it always returns false. I've verified that the method is getting the touch, as needed. Relevant code below:
Path.h
#import <Foundation/Foundation.h>
#import "cocos2d.h"
#interface Path : CCSprite {
CGPoint startP;
CGPoint endP;
CGRect pathRect;
CGPoint touchP;
}
-(id)initWithPoints:(CGPoint)sP :(CGPoint)eP;
-(bool)touchWithinBounds:(CGPoint)touch;
#property (nonatomic, assign) CGPoint startP;
#property (nonatomic, assign) CGPoint endP;
#property (nonatomic, assign) CGRect pathRect;
#end
Path.mm
#import "Path.h"
#implementation Path
#synthesize startP;
#synthesize endP;
#synthesize pathRect;
-(id) initWithPoints:(CGPoint)sP :(CGPoint)eP {
if ((self = [super init])) {
startP = sP;
endP = eP;
pathRect = CGRectMake(startP.x-2, endP.y, 5, 480);
}
return self;
}
-(bool)touchWithinBounds:(CGPoint)touch {
touchP = touch;
if(CGRectContainsPoint([self pathRect], touch)) {
return true;
} else {
return false;
}
}
-(void) draw {
glColor4f(1.0f,1.0f,1.0f,1.0f);
glLineWidth(5.0f);
ccDrawLine(startP, endP);
}
-(void) dealloc {
[super dealloc];
}
#end
In my main game scene, I initialize a path and add it to a mutable array:
paths = [[NSMutableArray alloc] init];
Path *path1 = [[[Path alloc] initWithPoints:ccp(winSize.width/3, 0.0) :ccp(winSize.width/3, winSize.height)] autorelease];
[self addChild:path1 z:0];
[paths addObject:path1];
And then in ccTouchesBegan, I send the touch location to touchWithinBounds. But instead of reporting true when the rectangle is touched, it always reports false:
UITouch *touch = [[event allTouches] anyObject];
CGPoint location = [touch locationInView: [touch view]];
location = [[CCDirector sharedDirector] convertToGL: [touch locationInView:touch.view ]];
for (Path *path in paths) {
CCLOG(#"%d", [path touchWithinBounds:location]);
Is there some kind of connection I'm missing between the pieces, or am I misunderstanding how the interaction works all-together?
Thanks
Figured it out. I had the points I was originating my rectangle at wrong.