-[_NSCFConstantString texture] error in Cocos2D - ios

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 = ...

Related

add two custom sprites into a scene,why do these sprites' methods will effect each other,anyone can find the mistake in my code? thanks

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.

How to correctly position a rectangle?

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];
}
}

Cocos2d 2.0 SimpleAudioEngine stop sound effect in another 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];
}

Delegate not working between HudLayer and GameLayer

I have created a HudLayer class which defines a protocol for when button presses happen.
-(id) init
{
if( (self=[super initWithColor:ccc4(255, 255, 0, 128)])) {
self.position=ccp(0,0);
self.contentSize=CGSizeMake(480, 40);
scoreLabel=[CCLabelTTF labelWithString:#"0" fontName:#"Marker Felt" fontSize:24];
scoreLabel.position=ccp(62,20);
scoreLabel.anchorPoint=ccp(0,0.5);
[self addChild:scoreLabel];
CCLabelTTF *textLabel=[CCLabelTTF labelWithString:#"Score:" fontName:#"Marker Felt" fontSize:24];
textLabel.position=ccp(5,20);
textLabel.anchorPoint=ccp(0,0.5);
[self addChild:textLabel];
CCMenuItemImage * item = [CCMenuItemImage itemWithNormalImage:#"fire.png" selectedImage:#"fire.png" target:self selector:#selector(projectileButtonTapped:)];
CCMenu *menu = [CCMenu menuWithItems:item, nil];
menu.position = ccp(150, 20);
[self addChild:menu];
}
return self;
}
- (void)projectileButtonTapped:(id)sender
{
NSLog(#"projectileButtonTapped HudLayer");
[self.delegate respondsToSelector:#selector(projectileButtonTapped:)];
}
Then in my HelloWorldLayer class I implement the protocol and set myself as the delegate.
+(CCScene *) scene
{
// 'scene' is an autorelease object.
CCScene *scene = [CCScene node];
// 'layer' is an autorelease object.
HelloWorldLayer *layer = [HelloWorldLayer node];
// add layer as a child to scene
[scene addChild: layer];
//add another layer to the scene
// HudLayer *anotherLayer = [HudLayer node];
// anotherLayer.delegate = self;
// [scene addChild: anotherLayer];
// layer.hud=anotherLayer;
// return the scene
return scene;
}
-(id) init
{
if( (self=[super init]) ) {
_tileMap = [CCTMXTiledMap tiledMapWithTMXFile:#"GridWars#medium.tmx"];
_background = [_tileMap layerNamed:#"Background"];
_foreground = [_tileMap layerNamed:#"Foreground"];
_meta = [_tileMap layerNamed:#"Meta"];
_meta.visible = NO;
CCTMXObjectGroup *objectGroup = [_tileMap objectGroupNamed:#"Objects"];
NSAssert(objectGroup != nil, #"tile map has no objects object layer");
NSDictionary *spawnPoint = [objectGroup objectNamed:#"SpawnPoint"];
int x = [spawnPoint[#"x"] integerValue];
int y = [spawnPoint[#"y"] integerValue];
_wizardHero = [[WizardHero alloc]init];
_redEnemy = [[RedEnemy alloc]init];
_wizardHero.position = ccp(x,y);
[self addChild:_wizardHero];
[self setViewPointCenter:_wizardHero.position];
[self addChild:_tileMap z:-1];
self.touchEnabled = YES;
self.enemies = [[NSMutableArray alloc] init];
self.projectiles = [[NSMutableArray alloc] init];
[self schedule:#selector(testCollisions:)];
for (spawnPoint in [objectGroup objects]) {
if ([[spawnPoint valueForKey:#"Enemy"] intValue] == 1){
x = [[spawnPoint valueForKey:#"x"] intValue];
y = [[spawnPoint valueForKey:#"y"] intValue];
[self addEnemyAtX:x y:y];
}
}
_hud = [HudLayer node];
_hud.delegate = self;
[self addChild:_hud];
}
return self;
}
- (void)projectileButtonTapped:(id)sender
{
// Find where the touch is
// CGPoint touchLocation = [touch locationInView: [touch view]];
// touchLocation = [[CCDirector sharedDirector] convertToGL: touchLocation];
// touchLocation = [self convertToNodeSpace:touchLocation];
if (self.wizardHero.selectedTargets.count > 0) {
// Create a projectile and put it at the player's location
CCSprite *projectile = [CCSprite spriteWithFile:#"Projectile.png"];
projectile.position = _wizardHero.position;
[self addChild:projectile];
// Determine where we wish to shoot the projectile to
int realX;
// Are we shooting to the left or right?
CGPoint diff = ccpSub(self.redEnemy.position, self.wizardHero.position);
if (diff.x > 0)
{
realX = (_tileMap.mapSize.width * _tileMap.tileSize.width) +
(projectile.contentSize.width/2);
} else {
realX = -(_tileMap.mapSize.width * _tileMap.tileSize.width) -
(projectile.contentSize.width/2);
}
float ratio = (float) diff.y / (float) diff.x;
int realY = ((realX - projectile.position.x) * ratio) + projectile.position.y;
CGPoint realDest = ccp(realX, realY);
// Determine the length of how far we're shooting
int offRealX = realX - projectile.position.x;
int offRealY = realY - projectile.position.y;
float length = sqrtf((offRealX*offRealX) + (offRealY*offRealY));
float velocity = 480/1; // 480pixels/1sec
float realMoveDuration = length/velocity;
// Move projectile to actual endpoint
id actionMoveDone = [CCCallFuncN actionWithTarget:self
selector:#selector(projectileMoveFinished:)];
[projectile runAction:
[CCSequence actionOne:
[CCMoveTo actionWithDuration: realMoveDuration
position: realDest]
two: actionMoveDone]];
[self.projectiles addObject:projectile];
}
}
The problem is that only the projectileButtonTapped: in the HudLayer is called (ie. the delegate's method never gets called).
P.S.
To save space I left out both .h files. But I assure you they are correct, with the #protocol used in HudLayer and that same protocol name put in <> within the HelloWorldLayer.
I think :
- (void)projectileButtonTapped:(id)sender
{
NSLog(#"projectileButtonTapped HudLayer");
if ([self.delegate respondsToSelector:#selector(projectileButtonTapped:)]) {
[self.delegate performSelector:#selector(projectileButtonTapped:) withObject:sender];
}
}

How to write a bouncing ball from scratch without cocos2d

It is so easy to write some code to achieve the bouncing ball based on the open source project cocos2d,here is the question.
So without cocos2d, how to implement this with the simplest code.
First you need to create a ball class. This class should have ivars for position, velocity, direction etc.
It should also have some methods for when the ball needs to change direction, like hitTop, hitBottom, hitLeft, hitRight. It should also have a method for updating the position, to move it one step forward.
I also have a BallView so that I can use a image or just a color as the ball.
To make it move you need to have a gameloop in you view controller, there are many methods for doing that but the one I find easiest is CADisplayLink.
Here are some code if you have problems implementing it:
Ball.h
#import <Foundation/Foundation.h>
#import "MovingObjectView.h"
#interface MovingObject : NSObject
#property(nonatomic, retain) MovingObjectView *ball;
#property CGRect bounds;
#property CGPoint position;
#property CGPoint direction;
#property float velocity;
-(id)initWithBounds:(CGRect)b andPosition:(CGPoint)p;
-(BOOL)positionIsInsideRect;
-(void)update;
-(void)hitLeft;
-(void)hitRight;
-(void)hitTop;
-(void)hitBottom;
#end
Ball.m
#import "MovingObject.h"
#implementation MovingObject
-(id)initWithBounds:(CGRect)b andPosition:(CGPoint)p
{
if (self = [super init]) {
self.bounds = b;
self.position = p;
self.direction = CGPointMake(1, 1);
//Change the position to middle if position is outside bounds
if (![self positionIsInsideRect]) {
NSLog(#"Position changed to center");
self.position = CGPointMake(self.bounds.size.width/2, self.bounds.size.height/2);
}
self.ball = [[[MovingObjectView alloc]initWithFrame:CGRectMake(self.position.x, self.position.y, 15, 15)]autorelease];
}
return self;
}
//checks if the balls position is correct
-(BOOL)positionIsInsideRect {
if (self.position.x < self.bounds.origin.x || self.position.x > self.bounds.size.width || self.position.y < self.bounds.origin.y || self.position.y > self.bounds.size.height) {
NSLog(#"Position is outside bounds");
return NO;
}else{
return YES;
}
}
//Call this method to move a ball
-(void)update {
//Checks if the ball is outside bounds
if (self.position.x-(self.ball.frame.size.width/2) <= self.bounds.origin.x) {
[self hitLeft];
}else if (self.position.x+(self.ball.frame.size.width/2) >= self.bounds.size.width){
[self hitRight];
}else if (self.position.y-(self.ball.frame.size.height/2) <= self.bounds.origin.y) {
[self hitTop];
}else if (self.position.y+(self.ball.frame.size.height/2) >= self.bounds.size.height){
[self hitBottom];
}
//Updates the balls position
CGPoint p = self.position;
p.x += self.direction.x*self.velocity;
p.y += self.direction.y*self.velocity;
self.position = p;
self.ball.center = self.position;
}
//Call this when the ball need to bounce
-(void)hitLeft
{
NSLog(#"hitLeft");
CGPoint d = self.direction;
d.x = fabsf(self.direction.x);
self.direction = d;
}
-(void)hitRight
{
NSLog(#"hitRight");
CGPoint d = self.direction;
d.x = -fabsf(self.direction.x);
self.direction = d;
}
-(void)hitTop
{
NSLog(#"hitTop");
CGPoint d = self.direction;
d.y = fabsf(self.direction.y);
self.direction = d;
}
-(void)hitBottom
{
NSLog(#"hitBottom");
CGPoint d = self.direction;
d.y = -fabsf(self.direction.y);
self.direction = d;
}
-(void)dealloc {
[super dealloc];
}
#end
BallView.h
#import <UIKit/UIKit.h>
#interface MovingObjectView : UIView
#property (nonatomic, retain) UIImage *img;
#end
BallView.m
#import "MovingObjectView.h"
#implementation MovingObjectView
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
}
return self;
}
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect
{
if (self.img == nil) {
CGRect bounds = [self bounds];
[[UIColor blackColor]set];
UIRectFill(bounds);
}else {
CGRect bounds = [self bounds];
[[UIColor whiteColor]set];
UIRectFill(bounds);
[self.img drawInRect:rect];
}
}
#end
Then finally in the viewcontroller you need this:
ViewController
In viewdidload:
self.displayLink = [CADisplayLink displayLinkWithTarget:self selector:#selector(gameLoop)];
[self.displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
Then add this method:
-(void)gameLoop
{
//Updates the balls position
[self.movingBall update];
//Here you could add your collision detection code
}

Resources