I create a class category of UITouch this my code :
- (id)initInView:(UIView *)view;
{
CGRect frame = view.frame;
CGPoint centerPoint = CGPointMake(frame.size.width * 0.5f, frame.size.height * 0.5f);
return [self initAtPoint:centerPoint inView:view];
}
- (id)initAtPoint:(CGPoint)point inWindow:(UIWindow *)window;
{
self = [super init];
if (self == nil) {
return nil;
}
// Create a fake tap touch
_tapCount = 1;
_locationInWindow = point;
_previousLocationInWindow = _locationInWindow;
UIView *hitTestView = [window hitTest:_locationInWindow withEvent:nil];
_window = [window retain];
_view = [hitTestView retain];
if ([self respondsToSelector:#selector(setGestureView:)]) {
[self setGestureView:hitTestView];
}
_phase = UITouchPhaseBegan;
_touchFlags._firstTouchForView = 1;
_touchFlags._isTap = 1;
_timestamp = [[NSProcessInfo processInfo] systemUptime];
return self;
}
- (id)initAtPoint:(CGPoint)point inView:(UIView *)view;
{
return [self initAtPoint:[view.window convertPoint:point fromView:view] inWindow:view.window];
}
- (void)setPhase:(UITouchPhase)phase;
{
_phase = phase;
_timestamp = [[NSProcessInfo processInfo] systemUptime];
}
but when I call it I get this crash -[UITouch initAtPoint:inView:]: unrecognized selector sent to instance
How can I fix that?
You say you created a category, but did not include the definition of your category.
It should look something like this:
//UITouch+customInitMethods.h
#interface UITouch (customInitMethods)
- (id)initInView:(UIView *)view;
- (id)initAtPoint:(CGPoint)point inWindow:(UIWindow *)window;
- (id)initAtPoint:(CGPoint)point inView:(UIView *)view;
#end
And then your implementation:
#import "UITouch+customInitMethods.h"
#implementation UITouch (customInitMethod)
//Your method implementations go here.
#end
Make sure that the target checkbox on the .m file of your category file is set to include the category in your application target.
Then you would need to #import UITouch+customInitMethods.h in any file that wanted to use your custom init methods.
Related
this is custom sprite class named BackGround
#import "BackGround.h"
// -----------------------------------------------------------------
id move02;
double roadX;
#implementation BackGround
+ (instancetype)initWithPicture: (NSString *) pic
{
return [[self alloc] init:pic];
}
-(id) init: (NSString *) pic
{
if(self = [super init])
{
CCSpriteFrameCache* spriteFrameCache = [CCSpriteFrameCache sharedSpriteFrameCache];
CCSpriteFrame * bgSpriteFrame = [spriteFrameCache spriteFrameByName:pic];
self = [BackGround spriteWithSpriteFrame:bgSpriteFrame];
self.anchorPoint = ccp(0, 0);
roadX = -(self.contentSize.width-1)*2;
self.position = ccp((-roadX/2), 0);
id move01 = [CCActionMoveBy actionWithDuration:10.0f position:ccp(roadX,0.0)];
move02 = [CCActionRepeatForever actionWithAction:move01];
[self runAction:move02];
}
return self;
}
-(void)bgWhenRun
{
[self stopAllActions];
id move = [CCActionSpeed actionWithAction:move02 speed:2];
[self runAction:move];
}
-(void)bgWhenWalk
{
[self stopAllActions];
[self runAction:move02];
}
// -----------------------------------------------------------------
#end
this is scene class code
#import "_256Deathes.h"
#import "IntroScene.h"
#import "BackGround.h"
#import "cocos2d.h"
#import "Person.h"
// -----------------------------------------------------------------
Person * personA;
#implementation _256Deathes
{
}
- (instancetype)init
{
if ((self = [super init]))
{
NSAssert(self, #"Whoops");
self.userInteractionEnabled = YES;
CCSpriteFrameCache* spriteFrameCache = [CCSpriteFrameCache sharedSpriteFrameCache];
[spriteFrameCache addSpriteFramesWithFile:#"256Deathes.plist"];
BackGround * bgSprite01 = [BackGround initWithPicture:#"earthA.png"];
bgSprite01.position = ccp(0, 0);
[self addChild:bgSprite01 z:0 name:#"bgSpriteA"];
BackGround * bgSprite02 = [BackGround initWithPicture:#"earthA.png"];
[self addChild:bgSprite02 z:1 name:#"bgSpriteB"];
}
return self;
}
- (void)onEnter
{
// always call super onEnter first
[super onEnter];
[self schedule:#selector(updateSprite) interval:0.02];
}
-(void)touchBegan:(CCTouch *)touch withEvent:(CCTouchEvent *)event
{
BackGround *spriteA = (BackGround *)[self getChildByName:#"bgSpriteA" recursively:NO];
BackGround *spriteB = (BackGround *)[self getChildByName:#"bgSpriteB" recursively:NO];
[spriteA bgWhenRun];
[spriteB bgWhenRun];
}
-(void)touchEnded:(CCTouch *)touch withEvent:(CCTouchEvent *)event
{
BackGround *sprite;
for(sprite in [self children])
{
if([sprite.name containsString:#"bgSprite"])
{
[sprite bgWhenWalk];
}
}
}
-(void) updateSprite
{
[self updateBackGround01];
}
-(void) updateBackGround01
{
BackGround *sprite;
for(sprite in [self children])
{
if([sprite.name containsString:#"bgSprite"])
{
double nextX = sprite.contentSize.width-3;
if(sprite.position.x <= (-nextX))
{
sprite.position = ccp(nextX, 0);
}
}
}
}
// -----------------------------------------------------------------
#end
when i touch begin or touch end, spriteA will stop moving, after i tried some times, i found [self stopAllActions] in methods named bgWhenRun and bgWhenWalk can make spriteA and spriteB effect each other.
anyone can find out the mistakes in the code then tell me?i have tried many times,now i really have no idea. thank you!
These two sprites effect each other because both are using same instance of variables id move02 and double roadX as being global ones. Declare them within scope of BackGround class i.e. as member variables of that class.
I'm completely new to developing apps with XCode and Objective-C. I'm trying to create a simple iOS application that creates a rectangle at the position of your finger when you tap the screen. I'm having an issue where the rectangle (the class is called Ball) isn't correctly positioned. On tap, it is positioned off the left of the screen and slightly above your finger. I'm not sure how to fix this, but I feel like it is a problem with my init function. Can anyone help?
Thanks.
GameScene.m
#import "GameScene.h"
#import "Ball.h"
#implementation GameScene
double SCREEN_WIDTH, SCREEN_HEIGHT;
NSMutableArray *screenObjects;
SKView *mainView;
- (void) didMoveToView:(SKView*)view {
mainView = view;
SCREEN_WIDTH = self.view.frame.size.width;
SCREEN_HEIGHT = self.view.frame.size.height;
screenObjects = [[NSMutableArray alloc] init];
[Ball setDefaultView: self];
[Ball setRightBounds: SCREEN_WIDTH];
[Ball setLeftBounds: 0];
[Ball setBottomBounds: SCREEN_HEIGHT];
[Ball setTopBounds: 0];
}
- (void) touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event {
for (UITouch *touch in touches) {
double x = [touch locationInView: mainView].x;
double y = [touch locationInView: mainView].y;
Ball *object = [[Ball alloc] init];
[object setPosition: CGPointMake(x, y)];
[screenObjects addObject: object];
NSLog(#"%f %f", x, y);
}
}
- (void) update:(CFTimeInterval)currentTime {
for (int i = 0; i < screenObjects.count; i++) {
[screenObjects[i] applyVelocity];
[screenObjects[i] dealWithWallCollisions];
}
}
#end
Ball.h
#ifndef IndependentStudyPrototype_Ball_h
#define IndependentStudyPrototype_Ball_h
#import "GameScene.h"
#interface Ball : NSObject
#property double width;
#property double height;
#property double x;
#property double y;
#property double velocity;
+ (void) setDefaultView:(GameScene*)view;
+ (void) setTopBounds:(double)bounds;
+ (void) setBottomBounds:(double)bounds;
+ (void) setLeftBounds:(double)bounds;
+ (void) setRightBounds:(double)bounds;
- (void) setPosition:(CGPoint)point;
- (void) updatePosition;
- (void) dealWithWallCollisions;
- (void) applyVelocity;
#end
#endif
Ball.m
#import <Foundation/Foundation.h>
#import "Ball.h"
#import "GameScene.h"
static GameScene *defaultView;
static double leftBound, rightBound, topBound, bottomBound;
#implementation Ball {
SKSpriteNode *rectangle;
double stepX, stepY;
}
+ (void) setDefaultView:(GameScene*)view {
defaultView = view;
}
+ (void) setBottomBounds:(double)bounds {
bottomBound = bounds;
}
+ (void) setTopBounds:(double)bounds {
topBound = bounds;
}
+ (void) setLeftBounds:(double)bounds {
leftBound = bounds;
}
+ (void) setRightBounds:(double)bounds {
rightBound = bounds;
}
- (void) updatePosition {
self->rectangle.position = CGPointMake(self.x, self.y);
}
- (void) setPosition:(CGPoint)point {
self.x = point.x;
self.y = point.y;
[self updatePosition];
}
- (void) applyVelocity {
self.x += self->stepX;
self.y += self->stepY;
[self updatePosition];
}
- (void) dealWithWallCollisions {
if (self.x > leftBound) {
self->stepX = -self.velocity;
} else if (self.x < rightBound) {
self->stepX = self.velocity;
}
if (self.y > bottomBound) {
self->stepY = -self.velocity;
} else if (self.y < topBound) {
self->stepY = self.velocity;
}
}
- (id)init {
self = [super init];
self->rectangle = [[SKSpriteNode alloc] initWithColor: [UIColor blueColor] size: CGSizeMake(50, 50)];
self.velocity = 1;
self->stepX = self.velocity;
self->stepY = self.velocity;
[defaultView addChild: self->rectangle];
return self;
}
#end
If you are just looking to fine tune the position, you can do something like this:
[object setPosition: CGPointMake(x+20, y-10)];
Inside touchesBegan use locationInNode instead of locationInView to get your touch point.
The touch location in an SKScene should be calculated using locationInNode not locationInView. This is because the origin of SKScene is at the bottom left corner and origin of UIView is at the top left corner.
- (void) touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event {
for (UITouch *touch in touches) {
CGPoint point = [touch locationInNode:self]; // Changed
Ball *object = [[Ball alloc] init];
[object setPosition: CGPointMake(point.x, point.y)]; // Changed
[screenObjects addObject: object];
}
}
I am trying to stop audio effect using simpleaudioengine in Cocos2d 2.0.
I have the following situation;
Farm Scene with two sky layers day/night. These are placed sprites, created within the layer in the scene.
I also have sprite classes for other characters (using Ray Wenderlichs Space Viking code) that are placed.
Upon touching the sky I have the day change to night, and vice versa, and I can start and stop the night crickets sound effect using ALuint ID in the Farm Layer (PollitosLayer.m) .
touching the sun sprite (class) has it's own ALuint reference I can start. But what I want is to STOP it when touching the Sky Sprite.
Is there a way to reference the ALuint of the Sun Class when touching the simple NON-CLASS Sky Sprite in the same PollitosLayer.m?
My code excerpts below.
#import "Sun.h"
#import "PollitosLayer.h"
#implementation Sun
#synthesize sunAnim;
#synthesize settingAnim;
-(void) dealloc {
}
-(void)playSunSound {
sunSound = PLAYSOUNDEFFECT(SUN_SPIN);
}
-(void)changeState:(CharacterStates)newState {
[self stopAllActions];
id action = nil;
characterState = newState;
switch (newState) {
case kStateGlowing:
CCLOG(#"Sun->Changing State to glowing");
[self setDisplayFrame:
[[CCSpriteFrameCache sharedSpriteFrameCache]
spriteFrameByName:#"sun_1.png"]];
action = [CCSpawn actions:[CCRepeatForever actionWithAction:
[CCAnimate actionWithAnimation:sunAnim]],nil];
//[self playSunSound];
break;
case kStateSetting:
CCLOG(#"Sun->Changing State to Setting");
[self setDisplayFrame:
[[CCSpriteFrameCache sharedSpriteFrameCache]
spriteFrameByName:#"sun_1.png"]];
action = [CCMoveBy actionWithDuration:3.0f
position:CGPointMake(0.0f,-400.0f)];
[[SimpleAudioEngine sharedEngine] stopEffect:sunSound];
break;
default:
CCLOG(#"Sun -> Unknown CharState %d",
characterState);
break;
}
if (action != nil)
[self runAction:action];
}
#pragma mark -
-(id) init {
if( (self=[super init]) ) {
//CGSize screenSize = [[CCDirector sharedDirector] winSize];
[self initAnimations];
[[[CCDirector sharedDirector] touchDispatcher] addTargetedDelegate:self priority:-1 swallowsTouches:YES];
}
return self;
}
-(void) cleanup
{
// Must manually remove this class as touch input receiver!
[[CCDirector sharedDirector].touchDispatcher removeDelegate:self];
[super cleanup];
}
#pragma mark -
#pragma mark initAnimations
-(void)initAnimations {
[self setSunAnim:
[self loadPlistForAnimationWithName:#"sunAnim"
andClassName:NSStringFromClass([self class])]];
}
-(void) update:(ccTime)delta
{
}
-(void) registerWithTouchDispatcher
{
[[[CCDirector sharedDirector] touchDispatcher] addTargetedDelegate:self priority:-1 swallowsTouches:YES];
}
-(BOOL) ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event
{
CGPoint touchLocation = [PollitosLayer locationFromTouch:touch];
// Check if this touch is on the sun's sprite.
BOOL isTouchHandled = CGRectContainsPoint([self boundingBox], touchLocation);
if (isTouchHandled)
{
[self changeState:kStateGlowing];
[self runAction:[CCRotateBy actionWithDuration:1.0f angle:360]];
}
return isTouchHandled;
}
-(void) ccTouchEnded:(UITouch *)touch withEvent:(UIEvent *)event {
[self playSunSound];
}
#end
farm layer below PollitosLayer.m
#import <Foundation/Foundation.h>
#import "cocos2d.h"
#import "Constants.h"
#import "GameManager.h"
#import "PollitosLayer.h"
#import "Pollito.h"
#import "GameObject.h"
#import "Owl.h"
#import "Sun.h"
#import "Chicks.h"
#import "MainScene.h"
#implementation PollitosLayer
#synthesize backbuttonsprite;
#synthesize henNightSprite;
#synthesize henDaySprite;
#synthesize skyDay;
#synthesize skyNight;
#synthesize moon;
ALuint nightcrickets;
ALuint sunSoundLayer;
ALuint sunSound;
ALuint pollitoSound;
+(CGPoint) locationFromTouch:(UITouch*)touch
{
CGPoint touchLocation = [touch locationInView: [touch view]];
return [[CCDirector sharedDirector] convertToGL:touchLocation];
}
+(CGPoint) locationFromTouches:(NSSet*)touches
{
return [self locationFromTouch:[touches anyObject]];
}
-(void)playNightSound {
nightcrickets = PLAYSOUNDEFFECT(NIGHT_CRICKETS);
}
-(void)playSunSoundLayer {
sunSoundLayer = PLAYSOUNDEFFECT(SUN_SPIN);
}
-(void)playPollitoSound {
pollitoSound = PLAYSOUNDEFFECT(POLLITOS_CHIRP);
}
-(id)init {
self = [super init];
if (self != nil) {
CGSize screenSize = [CCDirector sharedDirector].winSize;
// enable touches
self.isTouchEnabled = YES;
srandom(time(NULL)); // Seeds the random number generator
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
[[CCSpriteFrameCache sharedSpriteFrameCache]
addSpriteFramesWithFile:#"sceneatlas1_default.plist"]; // 1
sceneSpriteBatchNode =
[CCSpriteBatchNode batchNodeWithFile:#"sceneatlas1_default.png"]; // 2
} else {
[[CCSpriteFrameCache sharedSpriteFrameCache]
addSpriteFramesWithFile:#"sceneatlas1_default.plist"]; // 1
sceneSpriteBatchNode =
[CCSpriteBatchNode batchNodeWithFile:#"sceneatlas1_default.png"];// 2
}
[self addChild:sceneSpriteBatchNode z:70 tag:100];
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
[[CCSpriteFrameCache sharedSpriteFrameCache]
addSpriteFramesWithFile:#"sunsheet_default.plist"]; // 1
sunSpriteBatchNode =
[CCSpriteBatchNode batchNodeWithFile:#"sunsheet_default.png"]; // 2
} else {
[[CCSpriteFrameCache sharedSpriteFrameCache]
addSpriteFramesWithFile:#"sunsheet_default.plist"]; // 1
sunSpriteBatchNode =
[CCSpriteBatchNode batchNodeWithFile:#"sunsheet_default.png"];// 2
}
[self addChild:sunSpriteBatchNode z:6 tag:101];
[self createObjectOfType:kSun
//withHealth:100
atLocation:ccp(screenSize.width * 0.18f,
screenSize.height * 0.79f)
withZValue:10];
CCSprite *backgroundImage;
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
// Indicates game is running on iPad
backgroundImage =
[CCSprite spriteWithFile:#"pollitosbackground.png"];
} else {
backgroundImage =
[CCSprite spriteWithFile:#"pollitosbackground.png"];
}
[backgroundImage setPosition:ccp(screenSize.width/2.0f,
screenSize.height/2.0f)];
[self addChild:backgroundImage z:20 tag:69];
}
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
// Indicates game is running on iPad
skyDay =
[CCSprite spriteWithFile:#"SkyDay.png"];
} else {
skyDay =
[CCSprite spriteWithFile:#"SkyDay.png"];
}
CGSize screenSize = [CCDirector sharedDirector].winSize;
[skyDay setPosition:ccp(screenSize.width * 0.5f,
screenSize.height* 0.75f)];
[self addChild:skyDay z:0 tag:59]; //skyDay.visible=YES;
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
// Indicates game is running on iPad
skyNight =
[CCSprite spriteWithFile:#"SkyNight.png"];
} else {
skyNight =
[CCSprite spriteWithFile:#"SkyNight.png"];
}
[skyNight setPosition:ccp(screenSize.width * 0.5f,
screenSize.height * 0.75f)];
[self addChild:skyNight z:2 tag:51]; skyNight.visible = NO;
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
// Indicates game is running on iPad
moon =
[CCSprite spriteWithFile:#"Moon.png"];
} else {
moon =
[CCSprite spriteWithFile:#"Moon.png"];
}
[moon setPosition:ccp(screenSize.width * 0.87f,
screenSize.height * 0.51f)];
[self addChild:moon z:5 tag:52];
backbuttonsprite =[CCSprite spriteWithFile:#"back.png"];
[backbuttonsprite setPosition:ccp(screenSize.width * 0.88f,
screenSize.height * 0.95f)];
[self addChild:backbuttonsprite z:75 tag:75];
henDaySprite =[CCSprite spriteWithFile:#"henDay.png"];
[henDaySprite setPosition:ccp(screenSize.width * 0.70f,
screenSize.height * 0.37f)];
[self addChild:henDaySprite z:60 tag:60];
henNightSprite =[CCSprite spriteWithFile:#"henNight.png"];
[henNightSprite setPosition:ccp(screenSize.width * 0.70f,
screenSize.height * 0.37f)];
[self addChild:henNightSprite z:61 tag:61];
henNightSprite.visible = NO;
[self createObjectOfType:kPollito
atLocation:ccp(screenSize.width * 0.378f,
screenSize.height * 0.13f)
withZValue:21];
[self createObjectOfType:kPollito2
atLocation:ccp(screenSize.width * 0.578f,
screenSize.height * 0.18f)
withZValue:22];
[self createObjectOfType:kPollito3
atLocation:ccp(screenSize.width * 0.450f,
screenSize.height * 0.20f)
withZValue:23];
[self createObjectOfType:kPollito4
atLocation:ccp(screenSize.width * 0.3f,
screenSize.height * 0.43f)
withZValue:24];
[self createObjectOfType:kPollito5
atLocation:ccp(screenSize.width * 0.10f,
screenSize.height * 0.27f)
withZValue:25];
[self createObjectOfType:kPollito6
atLocation:ccp(screenSize.width * 0.25f,
screenSize.height * 0.19f)
withZValue:26];
[self createObjectOfType:kPollito7
atLocation:ccp(screenSize.width * 0.77f,
screenSize.height * 0.12f)
withZValue:27];
[self createObjectOfType:kPollito8
atLocation:ccp(screenSize.width * 0.17f,
screenSize.height * 0.42f)
withZValue:28];
[self createObjectOfType:kChicks
atLocation:ccp(screenSize.width * 0.73f,
screenSize.height * 0.25f)
withZValue:75];
[self createObjectOfType:kOwl
atLocation:ccp(screenSize.width * 0.897f,
screenSize.height * 0.727f)
withZValue:29];
return self;
}
#pragma mark -
-(void)createObjectOfType:(GameObjectType)objectType
atLocation:(CGPoint)spawnLocation
withZValue:(int)ZValue {
if (objectType == kPollito) {
CCLOG(#"Creating the Pollito1");
Pollito *pollito = [[[Pollito alloc] init] initWithSpriteFrameName:#"pollito_1.png"];
[pollito setPosition:spawnLocation];
[sceneSpriteBatchNode addChild:pollito z:ZValue tag:1];
[pollito changeState:kStatePecking1];
} else if (objectType == kPollito2) {
CCLOG(#"Creating the Pollito2");
Pollito *pollito2 = [[[Pollito alloc]init ]initWithSpriteFrameName:#"pollito_1.png"];
[pollito2 setPosition:spawnLocation];
[sceneSpriteBatchNode addChild:pollito2 z:ZValue tag:2];
[pollito2 changeState:kStatePecking2];
}else if (objectType == kPollito3) {
CCLOG(#"Creating the Pollito3");
Pollito *pollito3 = [[[Pollito alloc] init ]initWithSpriteFrameName:#"pollito_1.png"];
[pollito3 setPosition:spawnLocation];
[sceneSpriteBatchNode addChild:pollito3 z:ZValue tag:3];
[pollito3 changeState:kStatePecking3];
}else if (objectType == kPollito4) {
CCLOG(#"Creating the Pollito4");
Pollito *pollito4 = [[[Pollito alloc] init ]initWithSpriteFrameName:#"pollito_1.png"];
[pollito4 setPosition:spawnLocation];
[sceneSpriteBatchNode addChild:pollito4 z:ZValue tag:4];
[pollito4 changeState:kStatePecking4];
[pollito4 setScale:0.8f];
}else if (objectType == kPollito5) {
CCLOG(#"Creating the Pollito5");
Pollito *pollito5 = [[[Pollito alloc] init ]initWithSpriteFrameName:#"pollito_1.png"];
[pollito5 setPosition:spawnLocation];
[sceneSpriteBatchNode addChild:pollito5 z:ZValue tag:5];
[pollito5 changeState:kStatePecking5];
}else if (objectType == kPollito6) {
CCLOG(#"Creating the Pollito6");
Pollito *pollito6 = [[[Pollito alloc] init] initWithSpriteFrameName:#"pollito_1.png"];
[pollito6 setPosition:spawnLocation];
[sceneSpriteBatchNode addChild:pollito6 z:ZValue tag:6];
[pollito6 changeState:kStatePecking6];
}else if (objectType == kPollito7) {
CCLOG(#"Creating the Pollito7");
Pollito *pollito7 = [[[Pollito alloc] init ]initWithSpriteFrameName:#"pollito_1.png"];
[pollito7 setPosition:spawnLocation];
[sceneSpriteBatchNode addChild:pollito7 z:ZValue tag:7];
[pollito7 changeState:kStatePecking7];
}else if (objectType == kPollito8) {
CCLOG(#"Creating the Pollito8");
Pollito *pollito8 = [[[Pollito alloc] init] initWithSpriteFrameName:#"pollito_1.png"];
[pollito8 setPosition:spawnLocation];
[sceneSpriteBatchNode addChild:pollito8 z:ZValue tag:8];
[pollito8 changeState:kStatePecking8];
[pollito8 setScale:0.8f];
}else if (objectType == kOwl) {
CCLOG(#"Creating the Owl");
Owl *owl = [[[Owl alloc] init ]initWithSpriteFrameName:#"owl_1.png"];
[owl setPosition:spawnLocation];
[sceneSpriteBatchNode addChild:owl z:ZValue tag:9];
owl.visible = NO;
}else if (objectType == kChicks) {
CCLOG(#"Creating the Chicks");
Chicks *chicks = [[[Chicks alloc] init] initWithSpriteFrameName:#"PollitosSleeping_1.png"];
[chicks setPosition:spawnLocation];
[sceneSpriteBatchNode addChild:chicks z:ZValue tag:11];
chicks.visible = NO;
}else if (objectType == kSun) {
CCLOG(#"Here comes the Sun");
CCSprite *sun = [[[Sun alloc] init ]initWithSpriteFrameName:#"sun_1.png"];
[sun setPosition:spawnLocation];
[sunSpriteBatchNode addChild:sun z:ZValue tag:12];
}
}
-(void) registerWithTouchDispatcher
{
[[[CCDirector sharedDirector] touchDispatcher] addTargetedDelegate:self priority:0 swallowsTouches:NO];
}
-(void) dealloc
{
CCLOG(#"%#:worked %#", NSStringFromSelector(_cmd), self);
}
-(BOOL) ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event
{
CGSize screenSize = [CCDirector sharedDirector].winSize;
Chicks *chicks = (Chicks*)[sceneSpriteBatchNode getChildByTag:11];
Sun *sun = (Sun*)[sunSpriteBatchNode getChildByTag:12];
Owl *owl = (Owl*)[sceneSpriteBatchNode getChildByTag:9];
CGPoint touchLocation = [PollitosLayer locationFromTouch:touch];
// Check if this touch is on the pollito sprite.
if (CGRectContainsPoint([backbuttonsprite boundingBox], touchLocation))
{
STOPSOUNDEFFECT(nightcrickets);
STOPSOUNDEFFECT(pollitoSound);
STOPSOUNDEFFECT(sunSound);
STOPSOUNDEFFECT(sunSoundLayer);
[[GameManager sharedGameManager] runSceneWithID:kMainScene];
}
else if ((CGRectContainsPoint([henDaySprite boundingBox], touchLocation))&&(henNightSprite.visible == NO))
{
henDaySprite.visible = NO;
henNightSprite.visible = YES;
chicks.visible = YES;
[chicks changeState:kStateChirping];
}
else if ((CGRectContainsPoint([henNightSprite boundingBox], touchLocation))&&(henDaySprite.visible == NO))
{
henDaySprite.visible = YES;
henNightSprite.visible = NO;
chicks.visible = NO;
}
else if ((CGRectContainsPoint([skyDay boundingBox], touchLocation)) && (skyNight.visible == NO))
{
skyNight.visible = YES;
owl.visible = YES;
CCAction *moveUp = [CCMoveTo actionWithDuration:2.0f
position:CGPointMake(screenSize.width * 0.87f,
screenSize.height * 0.91f)];
[moon runAction:moveUp];
[[SimpleAudioEngine sharedEngine] stopEffect:sunSoundLayer];
CCAction *sunDown = [CCMoveTo actionWithDuration:2.0f
position:CGPointMake(screenSize.width * 0.18f,
screenSize.height * 0.40f)];
[sun runAction:sunDown];
STOPSOUNDEFFECT(sunSound);
[self playNightSound];
//[[SimpleAudioEngine sharedEngine] stopEffect:sunSound];
STOPSOUNDEFFECT(sunSoundLayer);
}else if (((CGRectContainsPoint([skyNight boundingBox], touchLocation)) && (skyNight.visible == YES) )){
skyNight.visible = NO;
CCAction *moveAction = [CCMoveTo actionWithDuration:2.0f
position:CGPointMake(screenSize.width * 0.87f, screenSize.height * 0.57f)];
[moon runAction:moveAction];
owl.visible = NO;
CCAction *sunUp = [CCMoveTo actionWithDuration:2.0f
position:CGPointMake(screenSize.width * 0.18f,
screenSize.height * 0.79f)];
[sun runAction:sunUp];
STOPSOUNDEFFECT(nightcrickets);
}
return YES;
}
-(void) ccTouchMoved:(UITouch *)touches withEvent:(UIEvent *)event{
}
-(void) ccTouchCancelled:(UITouch *)touch withEvent:(UIEvent *)event {
}
-(void) ccTouchEnded:(UITouch *)touch withEvent:(UIEvent *)event {
}
#end
To keep it simple, one thing you can do is have the farm layer own the two skies (day and night) and have the day sky own the sun. That way when you are determining what is touched, you can see if the current sky's heavily body (e.g. sun) is touched. If so then stop all necessary effects and play the sun effect. If the sky itself is touched then you can stop the heavily body's audio effect (which would do nothing if one was not playing) before changing the day/night cycle and continuing to play the next set of audio effects. For example:
#intereface FarmLayer()
#property (nonatomic, strong) Sky* day;
#property (nonatomic, strong) Sky* night;
#property (nonatomic, weak) Sky* currentSky;
#end
#implementation FarmLayer
- (void)onEnter
{
[super onEnter];
self.day = [...];
self.night = [...];
self.currentSky = self.day;
// Couldn't think of a better name but you get what I mean.
self.day.skyBody = [Sun ...];
...
}
- (void)ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
// Pseudo-ish code...
// if self.currentSky && self.currentSky.skyBody is touched
// - Stop all necessary audio effects if playing.
// - Play sky body audio.
// else if self.currentSky is touched
// - Stop all necessary audio effects (including self.currentSky.skyBody's audio effect).
// - If self.currentSky == self.day then switch to night (and vice versa).
// - Play all necessary audio effects for the new sky.
// - Make self.currentSky equal to the the new sky.
}
#end
I hope this helped. The example is just a quick one that assumes a lot of stuff and is not meant to be copied and pasted but it should give you an idea on how to go about solving your dilemma. Let me know if I misunderstood the question.
Edited:
Also I forgot to mention, each object can have its own array of audio files and you can have convenience methods to start and stop them. So for example assume you had an array property called audioEffects:
#interface Sky()
#property (nonatomic, strong) NSMutableArray* audioFileNames;
#property (nonatomic, strong) NSMutableArray* audioIds;
#end
#implementation Sky
- (void)addSoundEffectWithFileName:(NSString *)fileName
{
if (!fileName)
{
// Handle error.
return;
}
if (!self.audioFileNames)
{
self.audioFileNames = [NSMutableArray array];
}
[self.audioFileNames addObject:fileName];
if (!self.audioIds)
{
self.audioIds = [NSMutableArray array];
}
[self.audioIds addObject:#0];
}
- (void)playAllAudioEffects
{
for (int i = 0; i < [self.audioFileNames count]; i++)
{
NSString* audioFile = self.audioFileNames[i];
ALuint audioId = [[SimpleAudioEngine sharedEngine] playEffect:audioFile];
self.audioIds[i] = [NSNumber numberWithUnsignedInt:audioId];
}
}
- (void)stopAllAudioEffects
{
for (int i = 0; i < [self.audioIds count]; i++)
{
ALuint audioId = [self.audioIds[i] unsignedIntegerValue];
[[SimpleAudioEngine sharedEngine] stopEffect:audioId];
}
}
#end
Many Many thanks to Allen S. The creation of the separate SkyLayer and creating the properties inside of it, then referencing those as properties inside the parent layer and then using your onEnter worked. I can now reference and stop the audio of the sky elements from other sprites in the parent layer Here's my onEnter code.
(void)onEnter
{
[super onEnter];
CGSize screenSize = [CCDirector sharedDirector].winSize;
self.skyNight = [CCSprite spriteWithFile:#"SkyNight.png"];
[_skyNight setPosition:ccp(screenSize.width * 0.5f,
screenSize.height * 0.75f)];
[self addChild:_skyNight];
_skyNight.visible=NO;
self.currentsky = self.skyDay;
self.skyDay =
[CCSprite spriteWithFile:#"SkyDay.png"];
[_skyDay setPosition:ccp(screenSize.width * 0.5f,
screenSize.height* 0.75f)];
[self addChild:_skyDay];
_skyDay.visible=YES;
self.Sunspin = [CCSprite spriteWithFile:#"sun_1.png"];
[_Sunspin setPosition:ccp(screenSize.width * 0.18f,screenSize.height* 0.85f)];
[self addChild:_Sunspin];
}
I am trying to create sprite animations for a game where when a user clicks on a button, it will spawn 1 unit/enemy, which will move across the screen in a running animation. At the moment, when I run the game, it will play and once I attempt to spawn a unit, the game crashes and gives me a -[__NSCFConstantString texture]: unrecognized selector sent to instance 0x11a15c error.
This is the header file for the Unit itself:
#import <Foundation/Foundation.h>
#import "cocos2d.h"
#import "mainGameLayer.h"
#class MainGameLayer, Waypoint, Tower;
#interface Unit : CCSprite {
CGPoint myPosition;
int maxHP;
int currentHP;
float walkingSpeed;
Waypoint *destinationWaypoint;
BOOL active;
float centerToBottom;
float centerToSides;
}
#property (nonatomic, assign) MainGameLayer *theGame;
#property (nonatomic, assign) CCSprite *mySprite;
#property (nonatomic, strong) CCAction *walkAction;
+(id) nodeWithTheGame: (MainGameLayer *)_game;
-(id) initWithTheGame: (MainGameLayer *)_game;
-(void) doActivate;
-(void) getRemoved;
#end
Below is the implementation file. The 'self = super initWithSpriteFrame' line is currently throwing a warning saying "Incompatible pointer types sending NSString * to parameter of type 'CCSpriteFrame *'.
Also, the "CCSprite *frame = [[CCSpriterameCache....." line is throwing another warning saying 'Flag 0 results in undefined behaviour with p conversion specifier.
#import "Unit.h"
#import "Tower.h"
#import "Waypoint.h"
#define HEALTH_BAR_WIDTH 20
#define HEALTH_BAR_ORIGIN -10
#implementation Unit
#synthesize mySprite, theGame;
+(id) nodeWithTheGame:(MainGameLayer *)_game
{
return [[self alloc] initWithTheGame:_game];
}
-(id) initWithTheGame:(MainGameLayer *)_game
{
if ((self = [super initWithSpriteFrame:#"hero_walk_00.png"])) {
theGame = _game;
maxHP = 40;
currentHP = maxHP;
active = FALSE;
walkingSpeed = 0.5;
centerToBottom = 39.0;
centerToSides = 29.0;
CCArray *walkFrames = [CCArray arrayWithCapacity: 8];
for (int i = 0; i < 8; i++) {
CCSprite *frame = [[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:[NSString stringWithFormat:#"hero_walk_%02.png", i]];
[walkFrames addObject: frame];
}
CCAnimation *walkAnimation = [CCAnimation animationWithSpriteFrames:[walkFrames getNSArray] delay:1.0/12.0];
self.walkAction = [CCRepeatForever actionWithAction:[CCAnimate actionWithAnimation:walkAnimation]];
Waypoint *waypoint = (Waypoint *)[theGame.waypoints objectAtIndex:([theGame.waypoints count]-1)];
destinationWaypoint = waypoint.nextWaypoint;
CGPoint pos = waypoint.myPosition;
myPosition = pos;
[mySprite setPosition: pos];
[theGame addChild: self];
[self scheduleUpdate];
}
return self;
}
-(void) doActivate
{
active = TRUE;
}
-(void) update:(ccTime)dt
{
if (!active) {
return;
}
if ([theGame circle:myPosition withRadius:1 collisionWithCircle:destinationWaypoint.myPosition collisionCircleRadius:1]) {
if (destinationWaypoint.nextWaypoint) {
destinationWaypoint = destinationWaypoint.nextWaypoint;
} else {
[theGame getHpDamage];
[self getRemoved];
}
}
CGPoint targetPoint = destinationWaypoint.myPosition;
float movementSpeed = walkingSpeed;
CGPoint normalized = ccpNormalize(ccp(targetPoint.x - myPosition.x, targetPoint.y - myPosition.y));
mySprite.rotation = CC_RADIANS_TO_DEGREES(atan2(normalized.y, -normalized.x));
myPosition = ccp(myPosition.x + normalized.x * movementSpeed, myPosition.y + normalized.y * movementSpeed);
[mySprite setPosition: myPosition];
}
-(void) getRemoved
{
[self.parent removeChild:self cleanup:YES];
[theGame.units removeObject: self];
// Notify the game that we killed an enemy so we can check if we can send another wave
[theGame enemyGotKilled];
}
-(void) draw
{
ccDrawSolidRect(ccp(myPosition.x + HEALTH_BAR_ORIGIN, myPosition.y + 16), ccp(myPosition.x + HEALTH_BAR_ORIGIN + HEALTH_BAR_WIDTH, myPosition.y + 14), ccc4f(1.0, 0, 0, 1.0));
ccDrawSolidRect(ccp(myPosition.x + HEALTH_BAR_ORIGIN, myPosition.y + 16), ccp(myPosition.x + HEALTH_BAR_ORIGIN + (float)(currentHP * HEALTH_BAR_WIDTH)/maxHP, myPosition.y + 14), ccc4f(0, 1.0, 0, 1.0));
}
#end
Here is the header file of the main game layer:
#import <Foundation/Foundation.h>
#import "cocos2d.h"
#interface MainGameLayer : CCLayer {
CCSpriteBatchNode *_actors;
}
+ (CCScene *) scene;
- (BOOL) circle:(CGPoint)circlePoint withRadius:(float)radius collisionWithCircle:(CGPoint)circlePointTwo collisionCircleRadius:(float)radiusTwo;
void ccFillPoly (CGPoint *poli, int points, BOOL closePolygon);
- (void) enemyGotKilled;
- (void) getHpDamage;
#property (nonatomic, strong) NSMutableArray *towers;
#property (nonatomic, strong) NSMutableArray *waypoints;
#property (nonatomic, strong) NSMutableArray *units;
#end
And the implementation file:
#import "MainGameLayer.h"
#import "Tower.h"
#import "Waypoint.h"
#import "Unit.h"
#implementation MainGameLayer
#synthesize towers;
#synthesize waypoints;
#synthesize units;
+ (CCScene *) scene
{
CCScene *scene = [CCScene node];
MainGameLayer *layer = [MainGameLayer node];
[scene addChild: layer];
return scene;
}
- (id) init
{
if ((self = [super init])) {
// Initialize
self.isTouchEnabled = TRUE;
CGSize winSize = [CCDirector sharedDirector].winSize;
// Setting the background (Map)
CCSprite *background = [CCSprite spriteWithFile:#"layout.png"];
[self addChild: background];
[background setPosition: ccp(winSize.width/2, winSize.height/2)];
[self addWaypoints];
// In Game Buttons / Menu
CCMenuItem *sampleButton = [CCMenuItemImage itemWithNormalImage:#"sample.jpg" selectedImage:#"sample.jpg" target:self selector:#selector(samplePurchased:)];
CCMenu *PurchaseUI = [CCMenu menuWithItems:sampleButton, nil];
[PurchaseUI setScale:0.5];
[PurchaseUI setPosition:ccp(63, 51)];
[PurchaseUI alignItemsHorizontally];
PurchaseUI.isTouchEnabled = TRUE;
[self addChild: PurchaseUI];
// Set up the sprite sheets (Currently in testing)
[[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:#"pd_sprites.plist"];
_actors = [CCSpriteBatchNode batchNodeWithFile:#"pd_sprites.pvr.ccz"];
[_actors.texture setAliasTexParameters];
[self addChild: _actors];
}
return self;
}
-(BOOL) canBuyTower
{
return YES;
}
-(void) ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
for (UITouch *touch in touches) {
CGPoint location = [touch locationInView: [touch view]];
location = [[CCDirector sharedDirector] convertToGL: location];
CCLOG(#"X: %f Y: %f", location.x, location.y);
if ([self canBuyTower]) {
// Spend the gold later
Tower *tower = [Tower nodeWithTheGame:self location: location];
[towers addObject: tower];
}
}
}
-(void) addWaypoints
{
waypoints = [[NSMutableArray alloc] init];
Waypoint * waypoint1 = [Waypoint nodeWithTheGame:self location:ccp(-25,360)];
[waypoints addObject:waypoint1];
Waypoint * waypoint2 = [Waypoint nodeWithTheGame:self location:ccp(73,360)];
[waypoints addObject:waypoint2];
waypoint2.nextWaypoint =waypoint1;
Waypoint * waypoint3 = [Waypoint nodeWithTheGame:self location:ccp(467,360)];
[waypoints addObject:waypoint3];
waypoint3.nextWaypoint =waypoint2;
Waypoint * waypoint4 = [Waypoint nodeWithTheGame:self location:ccp(905,360)];
[waypoints addObject:waypoint4];
waypoint4.nextWaypoint =waypoint3;
Waypoint * waypoint5 = [Waypoint nodeWithTheGame:self location:ccp(1050,360)];
[waypoints addObject:waypoint5];
waypoint5.nextWaypoint =waypoint4;
}
-(BOOL) circle:(CGPoint)circlePoint withRadius:(float)radius collisionWithCircle:(CGPoint)circlePointTwo collisionCircleRadius:(float)radiusTwo
{
float xdif = circlePoint.x - circlePointTwo.x;
float ydif = circlePoint.y - circlePointTwo.y;
float distance = sqrt(xdif*xdif + ydif*ydif);
if (distance <= radius + radiusTwo) {
return TRUE;
}
return FALSE;
}
-(void) samplePurchased: (id)sender
{
Unit *tempUnit = [Unit nodeWithTheGame: self];
[units addObject: tempUnit];
[tempUnit doActivate];
}
#end
I'm basically just working off some of the tutorials on the Ray Wenderlich website; I haven't run into any of these errors before and haven't been able to find much help on Google. Any help here is much appreciated! Thank you in advance!
EDIT: After making the changes I am now getting an invisible sprite move across the screen. The sprite's health bar will appear and move across the screen but not the actual sprite / animation itself. Any reasons for this?
[super initWithSpriteFrame:#"hero_walk_00.png"]
expects a CCSpriteFrame* as parameter, not a NSString*. This is why you get a compiler warning for this line - don't ignore compiler warnings!
The fix is simple, use the correct initializer:
[super initWithSpriteFrameName:#"hero_walk_00.png"]
And this returns a CCSpriteFrame* not a CCSprite*:
CCSprite *frame = [[CCSpriteFrameCache sharedSpriteFrameCache]
spriteFrameByName:[NSString stringWithFormat:#"hero_walk_%02.png", i]];
Hence the other warning. The fix:
CCSpriteFrame *frame = ...
So, I added a popupview to my uisliders. I got the code for the custom sliders with the popup from a guy who had already done that. The popup is showing, but the only problem is that the popup is showing inside the cell in which the slider is at, so it gets cut off at the end of the cell.
How can I bring the popupview in front of the cell ?
(I have multiple sliders each one in a different cell)
#import "MNEValueTrackingSlider.h"
#import "ToothTableViewController.h"
#pragma mark - Private UIView subclass rendering the popup showing slider value
#interface MNESliderValuePopupView : UIView {
MNEValueTrackingSlider *trackingSlider;
ToothTableViewController *toothViewController;
}
#property (nonatomic) float value;
#property (nonatomic, retain) UIFont *font;
#property (nonatomic, retain) NSString *text;
#end
#import "MNEValueTrackingSlider.h"
#import "ToothTableViewController.h"
#implementation MNESliderValuePopupView
#synthesize value=_value;
#synthesize font=_font;
#synthesize text = _text;
- (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
self.font = [UIFont boldSystemFontOfSize:18];
}
return self;
}
- (void)dealloc {
self.text = nil;
self.font = nil;
[super dealloc];
}
- (void)drawRect:(CGRect)rect {
// Set the fill color
[[UIColor colorWithWhite:0 alpha:0.8] setFill];
// Create the path for the rounded rectanble
CGRect roundedRect = CGRectMake(self.bounds.origin.x , self.bounds.origin.y, self.bounds.size.width, self.bounds.size.height * 0.8);
UIBezierPath *roundedRectPath = [UIBezierPath bezierPathWithRoundedRect:roundedRect cornerRadius:6.0];
// Create the arrow path
UIBezierPath *arrowPath = [UIBezierPath bezierPath];
CGFloat midX = CGRectGetMidX(self.bounds);
CGPoint p0 = CGPointMake(midX, CGRectGetMaxY(self.bounds));
[arrowPath moveToPoint:p0];
[arrowPath addLineToPoint:CGPointMake((midX - 10.0), CGRectGetMaxY(roundedRect))];
[arrowPath addLineToPoint:CGPointMake((midX + 10.0), CGRectGetMaxY(roundedRect))];
[arrowPath closePath];
// Attach the arrow path to the buble
[roundedRectPath appendPath:arrowPath];
[roundedRectPath fill];
// Draw the text
if (self.text) {
[[UIColor colorWithWhite:1 alpha:0.8] set];
CGSize s = [_text sizeWithFont:self.font];
CGFloat yOffset = (roundedRect.size.height - s.height) / 2;
CGRect textRect = CGRectMake(roundedRect.origin.x, yOffset, roundedRect.size.width, s.height);
[_text drawInRect:textRect
withFont:self.font
lineBreakMode:UILineBreakModeWordWrap
alignment:UITextAlignmentCenter];
}
}
- (void)setValue:(float)aValue {
_value = aValue;
self.text = [NSString stringWithFormat:#"%4.2f", _value];
[self setNeedsDisplay];
}
#end
#pragma mark - MNEValueTrackingSlider implementations
#import "ToothTableViewController.h"
#implementation MNEValueTrackingSlider
#synthesize thumbRect;
#synthesize sliderButtonPoint;
#pragma mark - Private methods
- (void)_constructSlider {
valuePopupView = [[MNESliderValuePopupView alloc] initWithFrame:CGRectZero];
valuePopupView.backgroundColor = [UIColor clearColor];
valuePopupView.alpha = 0.0;
toothViewController = [[ToothTableViewController alloc] init];
[self addSubview:valuePopupView];
}
- (void)_fadePopupViewInAndOut:(BOOL)aFadeIn {
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.5];
if (aFadeIn) {
valuePopupView.alpha = 1.0;
} else {
valuePopupView.alpha = 0.0;
}
[UIView commitAnimations];
}
- (void)_positionAndUpdatePopupView {
CGRect _thumbRect = self.thumbRect;
CGRect popupRect = CGRectOffset(_thumbRect, 0, -(_thumbRect.size.height * 1.5));
valuePopupView.frame = CGRectInset(popupRect, -20, -10);
valuePopupView.value = (NSInteger)self.value;
}
#pragma mark - Memory management
- (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
[self _constructSlider];
}
return self;
}
- (id)initWithCoder:(NSCoder *)aDecoder {
self = [super initWithCoder:aDecoder];
if (self) {
[self _constructSlider];
}
return self;
}
- (void)dealloc {
[valuePopupView release];
[super dealloc];
}
#pragma mark - UIControl touch event tracking
- (BOOL)beginTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event {
// Fade in and update the popup view
CGPoint touchPoint = [touch locationInView:self];
// Check if the knob is touched. Only in this case show the popup-view
if(CGRectContainsPoint(self.thumbRect, touchPoint)) {
[self _positionAndUpdatePopupView];
[self _fadePopupViewInAndOut:YES];
}
return [super beginTrackingWithTouch:touch withEvent:event];
}
- (BOOL)continueTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event {
// Update the popup view as slider knob is being moved
[self _positionAndUpdatePopupView];
return [super continueTrackingWithTouch:touch withEvent:event];
}
- (void)cancelTrackingWithEvent:(UIEvent *)event {
[super cancelTrackingWithEvent:event];
}
- (void)endTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event {
// Fade out the popoup view
[self _fadePopupViewInAndOut:NO];
[super endTrackingWithTouch:touch withEvent:event];
}
#pragma mark - Custom property accessors
- (CGRect)thumbRect {
CGRect trackRect = [self trackRectForBounds:self.bounds];
CGRect thumbR = [self thumbRectForBounds:self.bounds
trackRect:trackRect
value:self.value];
return thumbR;
}
#end
Ok so I gave up, I cant figure it out. That is the code for the slider and its popupview. If anyone feels like reading the whole thing I could use the help :P
You could try to add the popupview as a subview of the UITableView.
Then to move it along with the slider, you would have to calculate the point by getting the slider's position relative to your tableview.
This can be achieved by using the UIView's convertPoint:toView: method, for example:
CGPoint sliderButtonRelativePoint = [slider.superview convertPoint:sliderButtonPoint toView:tableView];
where slider.superview would be your UITableViewCell, sliderButtonPoint would be the middle-top point of the slider's round button (for example), and tableView would be, well... your UITableView.
You might have to play around with this a little, and you may find there are strange behaviours when scrolling the tableview, but that's what I would try first.