no visible #interface for 'Player' declares the selector 'walkRight' - ios

// Player.m
#import "Player.h"
#implementation Player
+(id)player{
Player *player = [Player spriteNodeWithColor:[UIColor brownColor] size:CGSizeMake(32, 32)];
player.name = #"player";
player.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:player.size];
return player;
}
- (void)walkRight {
SKAction *incRight = [SKAction moveByX:10 y:0 duration:0];
[self runAction:incRight];
}
#end
// MyScene.h
#import "MyScene.h"
#import "Player.h"
#implementation MyScene
-(id)initWithSize:(CGSize)size {
if (self = [super initWithSize:size]) {
/* Setup your scene here */
self.anchorPoint = CGPointMake(0.5, 0.5);
self.backgroundColor = [SKColor colorWithRed:0.15 green:0.15 blue:0.3 alpha:1.0];
SKSpriteNode *ground = [SKSpriteNode spriteNodeWithColor:[UIColor greenColor] size:CGSizeMake(self.frame.size.width, 30)];
ground.position = CGPointMake(0, -self.frame.size.height/2 + ground.frame.size.height/2);
ground.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:ground.size];
ground.physicsBody.dynamic = NO;
[self addChild:ground];
Player *player = [Player player];
[self addChild:player];
}
return self;
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
Player *player = (Player *)[self childNodeWithName:#"player"];
[player walkRight];
}
-(void)update:(CFTimeInterval)currentTime {
/* Called before each frame is rendered */
}
#end
I'm quite new to objective-c. Well I tried to build the above code and got the error "no visible #interface for 'Player' declares the selector 'walkRight'"
I really do not know why. I would really appreciate it if someone could help me. Thank you.

Make sure you've declared the walkRight method in your Player.h file. This should go somewhere after your interface declaration in that file:
-(void)walkRight;
That allows other files that import Player.h to know that Player.m implements the walkRight method.

Change your player method to return instancetype instead of id. This will make the warning go away. Also declare the walkRight method in the header (.h) file of your Player class.
+(instancetype)player{
Player *player = [Player spriteNodeWithColor:[UIColor brownColor] size:CGSizeMake(32, 32)];
....
return player;
}
Read more about instancetype here and here.
Hope that helps!

Related

Scene not changing in SpriteKit

I've created a game and now I want to add a start screen in which I want to run a video and after that there will be a screen with start button, I've searched over internet but couldn't find out the way to do it, have tried many things, the latest code is:
#import "FirstScreen.h"
#import "GameScene.h"
#import <MediaPlayer/MediaPlayer.h>
#implementation FirstScreen
-(id)initWithSize:(CGSize)size {
if (self = [super initWithSize:size]) {
NSURL *url =[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:#"Intro" ofType:#"mp4"]];
_player = [[MPMoviePlayerController alloc] initWithContentURL:url];
_player.view.frame = CGRectMake(0,0, 1024, 768);
[self.view addSubview:_player.view];
_player.shouldAutoplay = YES;
[_player prepareToPlay];
NSString *nextSceneButton;
nextSceneButton = #"Start";
SKLabelNode *myLabel = [SKLabelNode labelNodeWithFontNamed:#"Chalkduster"];
myLabel.text = nextSceneButton;
myLabel.fontSize = 30;
myLabel.fontColor = [SKColor blackColor];
myLabel.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame));
myLabel.name = #"Start";
[self addChild:myLabel];
}
return self;
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
/* Called when a touch begins */
UITouch *touch = [touches anyObject];
CGPoint location = [touch locationInNode:self];
SKNode *node = [self nodeAtPoint:location];
if ([node.name isEqualToString:#"Start"]) {
SKTransition *reveal = [SKTransition fadeWithDuration:3];
GameScene *scene = [GameScene sceneWithSize:self.view.bounds.size];
scene.scaleMode = SKSceneScaleModeAspectFill;
[self.view presentScene:scene transition:reveal];
}
}
#end
App just starts and give the SIGABRT error. Can you tell me how to do it?
You should check few things to make sure is everything okay there:
Check if everything is okay with file name, look for spaces or typos etc...
See what pathForResource returns (println it)
See what fileURLWithPath returns
Go to : Target -> Build Phases -> Copy Bundle Resources and add Intro.mp4 file there. If that file is already added , delete it, clean your project Project->Clean, and add it again. Build project and run it.

Using a view controller for a game over scene

I need to make an end screen for my app after the collision detection. What is the easiest possible way to make the end screen with a button back to the main menu/to the game. Can I use a ViewController? I've read a lot of tutorials, videos, and also all of the posts on here:
This is my current code (not all of it just some important things):
#implementation MyScene
static const int squirrelHitCategory = 1;
static const int nutHitCategory = 2;
- (instancetype)initWithSize:(CGSize)size {
if (self = [super initWithSize:size]) {
self.physicsWorld.contactDelegate = self;
_squirrelSprite = [SKSpriteNode spriteNodeWithImageNamed:#"squirrel"];
_squirrelSprite.position = _firstPosition;
_atFirstPosition = YES;
_squirrelSprite.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:10];
_squirrelSprite.physicsBody.categoryBitMask = squirrelHitCategory;
_squirrelSprite.physicsBody.contactTestBitMask = nutHitCategory;
_squirrelSprite.physicsBody.collisionBitMask = nutHitCategory;
_squirrelSprite.physicsBody.affectedByGravity = NO;
self.physicsWorld.contactDelegate = self;
[self addChild:_squirrelSprite];
SKAction *wait = [SKAction waitForDuration:3.0];
SKSpriteNode *lightnut = [SKSpriteNode spriteNodeWithImageNamed:#"lightnut.png"];
lightnut.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:CGSizeMake(200,160)];
lightnut.physicsBody.categoryBitMask = nutHitCategory;
lightnut.physicsBody.contactTestBitMask = squirrelHitCategory;
lightnut.physicsBody.collisionBitMask = squirrelHitCategory;
lightnut.physicsBody.affectedByGravity = NO;
self.physicsWorld.contactDelegate = self;
[self addChild: lightnut];
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
// Check time since the last touch event
if (touch.timestamp-_lastTouch >= .9) {
// Allow touch
NSLog(#"greater than or equal to 3 seconds");
if (_atFirstPosition)
{
SKAction *moveNodeLeft = [SKAction moveByX:-207.8 y:0.0 duration:0.85];
[_squirrelSprite runAction: moveNodeLeft withKey:#"moveleft"];
} else {
SKAction *moveNodeRight = [SKAction moveByX:207.8 y:0.0 duration:0.85];
[_squirrelSprite runAction: moveNodeRight withKey:#"moveright"];
}
_atFirstPosition = !_atFirstPosition;
_squirrelSprite.xScale *= -1.0;
}
else {
// Ignore touch
NSLog(#"Seconds since last touch %g",touch.timestamp-_lastTouch);
}
// Store timestamp
_lastTouch = touch.timestamp;
}
-(void)didBeginContact:(SKPhysicsContact *)contact
{
NSLog(#"contact detected");
SKPhysicsBody *firstBody, *secondBody;
firstBody = contact.bodyA;
secondBody = contact.bodyB;
if(firstBody.categoryBitMask == squirrelHitCategory || secondBody.categoryBitMask == nutHitCategory)
{
}
}
I want my end screen to be simple, so the easiest way to make it is best. Thank you!
For my games I add a UIViewController property and assign it to the SKScene.
You can then add a view as a sub view. Example...
SKScene *scene = [SKScene sceneWithSize:self.view.frame.size];
scene.viewController = self;
Then in your scene...
[self.viewController addSubview:yourView];
Here is some of my own game's implementation to help get you started.
In your Storyboard, or XIB whichever you prefer you add a view with buttons as properties of the view. In my case I have a scoreLabel, a menuButton, and a restartButton as properties and can set them all as x.hidden = YES; as I wish by triggering them in the scene such as...
self.vc.menuButton.hidden = YES;
self.vc.restartButton.hidden = YES;
In your GameViewController (Which is a subclass of UIViewController)...
//header
#interface GameViewController : UIViewController
#property (weak, nonatomic) IBOutlet UILabel *scoreLabel;
#property (weak, nonatomic) IBOutlet UIView *hudView;
#property (weak, nonatomic) IBOutlet UIButton *menuButton;
#property (weak, nonatomic) IBOutlet UIButton *restartButton;
#property (nonatomic) MazeScene *maze;
#end
//class
- (void)viewDidLoad
{
[super viewDidLoad];
// Configure the view.
SKView * skView = (SKView *)self.view;
// Debug Options
// skView.showsFPS = YES;
// skView.showsNodeCount = YES;
// skView.showsPhysics = YES;
// Create and configure the maze scene.
CGSize sceneSize = skView.bounds.size;
skView.ignoresSiblingOrder = YES;
MazeScene *maze = [[MazeScene alloc] initWithSize:sceneSize];
maze.scaleMode = SKSceneScaleModeAspectFill;
maze.vc = self;
[skView presentScene:maze];
_maze = maze;
}
In your SKScene...
//header
#interface MazeScene : SKScene <SKPhysicsContactDelegate>
#property (nonatomic, weak) GameViewController *vc;
#end
//class
-(id) initWithSize:(CGSize)size {
if (self = [super initWithSize:size]) {
//(GameViewController*) is a static cast of a subclass of UIViewController.
[self.view addSubview:((GameViewController*)self.vc).hudView];
// [self restartGame] is a specific method for my game, don't worry about it
[self restartGame];
}
return self;
}

UITouch methods in an object not working properly

I have got a SKScene name “Scene” in which I instantiate 2 objects of my class “Button” subclass of SKNode.
In order to not multiply the number of lines of code in my SKScene, I wanted to implemente the touch methods directly in my class “Button”.
Here is the code :
Scene.h
#import <SpriteKit/SpriteKit.h>
#interface Scene : SKScene
#end
Scene.m
#import "Scene.h"
#import "Button.h"
#implementation Scene
- (id)initWithSize:(CGSize)size
{
if (self = [super initWithSize:size])
{
Button *button01 = [Button node];
[button01.number setString: #"1"];
button01.position = CGPointMake(CGRectGetMidX(self.frame) - 50, 160);
Button *button02 = [Button node];
[button02.number setString: #"2"];
button02.position = CGPointMake(CGRectGetMidX(self.frame) + 50, 160);
[self addChild:button01];
[self addChild:button02];
}
return self;
}
#end
Button.h
#import <SpriteKit/SpriteKit.h>
#interface Button : SKNode
#property (strong, nonatomic) NSMutableString *number;
#end
Button.m
#import "Button.h"
SKShapeNode *button;
#implementation Button
- (id)init
{
if (self = [super init])
{
self.userInteractionEnabled = YES;
_number = [[NSMutableString alloc] init];
[_number setString: #"0"];
button = [SKShapeNode node];
[button setPath:CGPathCreateWithRoundedRect(CGRectMake(-25, -25, 50, 50), 4, 4, nil)];
button.fillColor = [SKColor clearColor];
button.lineWidth = 1.0;
button.strokeColor = [SKColor whiteColor];
button.position = CGPointMake(0, 0);
SKLabelNode *label = [SKLabelNode labelNodeWithFontNamed:#"Arial"];
label.text = _number;
label.fontSize = 20;
label.verticalAlignmentMode = SKLabelVerticalAlignmentModeCenter;
label.position = CGPointMake(0, 0);
label.fontColor = [SKColor whiteColor];
[button addChild:label];
[self addChild:button];
}
return self;
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch * touch = [touches anyObject];
CGPoint location = [touch locationInNode:self];
if(CGRectContainsPoint(button.frame, location))
{
button.fillColor = [SKColor whiteColor];
}
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
button.fillColor = [SKColor clearColor];
}
#end
The problem is when I touch inside the button01, it’s the button02 color’s which change. As if the action is only apply on the last instance of my class.
How can I fixe this.
Thanks in advance.
The issue is the following variable has global scope in your Button class:
SKShapeNode *button;
Since it is shared among the instances of Button, it contains a reference to the SKShapeNode of the last Button that was instantiated. In this case, button 2. You can resolve this issue by defining button as an instance variable:
#implementation Button
{
SKShapeNode *button;
}
...
For some reasons your Button has SKNode as a superclass. SKNode doesn't have a size property, which you can change, so it takes the whole size of it's parent node. Consider it as a layer of the scene. So wherever you touch, the latest SKScene's child (which is button02 in your case) will receive the touch.
Solution: Define Button as a subclass of SKShapeNode directly.

setDelegate:]: unrecognized selector sent to instance (device only)

My app was working fine until recently, when the Sprite Scene began to crash after "return self;" it would display the error "-[BEGameScene setDelegate:]: unrecognized selector sent to instance 0x10040de10'" before "terminating with uncaught exception of type NSException" this bug seems to only happen on a device; the ios simulator works fine.
The weird thing is that the bug doesn't seem to be in my code. I took an older, still working version, duplicated it directly from finder and when I ran that it crashed too.
Could it be a problem with Xcode 6 (which I recently downloaded)?
Thanks in advance
Edit:
Sorry, here is the code
#import "BEGameScene.h"
#import "AppDelegate.h"
#import <UIKit/UIKit.h>
#import <SpriteKit/SpriteKit.h>
#interface BEMainGameViewController : UIViewController <BEGameSceneDelegate>
#property (nonatomic, assign) id <BEGameSceneDelegate> delegate;
#end
#import "BEMainGameViewController.h"
#import "BEGameScene.h"
#interface BEMainGameViewController ()
#property (strong, nonatomic) IBOutlet UIPanGestureRecognizer *control;
#end
#implementation BEMainGameViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Configure the view.
SKView *skView = (SKView *)self.view;
skView.showsFPS = NO;
skView.showsNodeCount = NO;
// Create and configure the scene.
BEGameScene *scene = [BEGameScene sceneWithSize:skView.bounds.size];
scene.scaleMode = SKSceneScaleModeAspectFill;
scene.delegate = self;
// Present the scene.
[skView presentScene:scene];
[self.view setBackgroundColor:[UIColor colorWithPatternImage:[UIImage imageNamed:#"Background 1.tiff"]]];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (void)unwindFromGame {
[self performSegueWithIdentifier:#"unwindFromGameScene" sender:self];
}
#end
#import <SpriteKit/SpriteKit.h>
#protocol BEGameSceneDelegate <NSObject>
-(void)unwindFromGame;
#end
#interface BEGameScene : SKScene <UIGestureRecognizerDelegate>
#property (weak, nonatomic) id <BEGameSceneDelegate> delegate;
#end
#import "BEMainGameViewController.h"
#import "BEGameScene.h"
#import "AppDelegate.h"
#implementation BEGameScene {
NSArray *location;
int x_flower;
int x_Trap1;
int x_Trap2;
int randNum;
int speed;
int score;
int life;
BOOL rad;
BOOL collide;
NSInteger interval;
SKSpriteNode *sprite_bee;
SKSpriteNode *sprite_flower;
SKSpriteNode *sprite_flyTrap;
SKSpriteNode *sprite_flyTrap2;
SKSpriteNode *sprite_rad;
SKSpriteNode *sprite_radGlow;
NSTimer *timer;
SKLabelNode *youLoseLabel;
SKLabelNode *instruction;
NSString *scoreText;
NSString * honey;
}
-(id)initWithSize:(CGSize)size {
life = 1;
if (self = [super initWithSize:size]) {
/* Setup your scene here */
//self.backgroundColor = [SKColor colorWithRed:0.15 green:0.15 blue:0.3 alpha:1.0];
SKSpriteNode *bgImage = [SKSpriteNode spriteNodeWithImageNamed:#"BGImage"];
bgImage.position = CGPointMake(self.size.width/2, self.size.height/2);
[self addChild:bgImage];
//Bee movement
SKTexture *texture1 = [SKTexture textureWithImageNamed:#"Bee up.tiff"];
SKTexture *texture2 = [SKTexture textureWithImageNamed:#"Bee down.tiff"];
SKTexture *texture3 = [SKTexture textureWithImageNamed:#"Flower.tiff"];
SKTexture *texture4 = [SKTexture textureWithImageNamed:#"Fly Trap.tiff"];
SKTexture *texture5 = [SKTexture textureWithImageNamed:#"radiation.png"];
SKTexture *texture6 = [SKTexture textureWithImageNamed:#"rad glow.png"];
sprite_bee = [SKSpriteNode spriteNodeWithTexture:texture1];
sprite_bee.position = CGPointMake(160, 100);
sprite_bee.zPosition = 100;
sprite_bee.size = CGSizeMake(110, 110);
SKAction *fly = [SKAction animateWithTextures:#[texture1,texture2] timePerFrame:.2];
[sprite_bee runAction:[SKAction repeatActionForever:fly]];
[self addChild:sprite_bee];
collide = NO;
//Plant creation
speed = 100;
score = 0;
x_flower = 40;
x_Trap1 = 160;
x_Trap2 = 280;
sprite_radGlow = [SKSpriteNode spriteNodeWithImageNamed:#"rad glow.png"];
sprite_radGlow.position = CGPointMake(100,3000);
sprite_radGlow.size = CGSizeMake(140, 140);
sprite_radGlow.zPosition = 50;
SKAction *glow = [SKAction sequence:#[
[SKAction fadeOutWithDuration:.5],
[SKAction fadeInWithDuration:.5],
]];
[sprite_radGlow runAction:[SKAction repeatActionForever:glow]];
[self addChild: sprite_radGlow];
sprite_flower = [SKSpriteNode spriteNodeWithTexture:texture3];
sprite_flower.position = CGPointMake(40, 300);
sprite_flower.size = CGSizeMake(100, 100);
[self addChild:sprite_flower];
sprite_flyTrap = [SKSpriteNode spriteNodeWithTexture:texture4];
sprite_flyTrap.position = CGPointMake(160, 300);
sprite_flyTrap.size = CGSizeMake(100, 100);
[self addChild:sprite_flyTrap];
sprite_flyTrap2 = [SKSpriteNode spriteNodeWithTexture:texture4];
sprite_flyTrap2.position = CGPointMake(280, 300);
sprite_flyTrap2.size = CGSizeMake(100, 100);
[self addChild:sprite_flyTrap2];
sprite_rad = [SKSpriteNode spriteNodeWithTexture:texture5];
sprite_rad.position = CGPointMake(160, 3000);
sprite_rad.size = CGSizeMake(500, 100);
[self addChild:sprite_rad];
}
return self;
}
#end
So I think your issue might be related to SKScene adding a delegate field in iOS 8.
I recommend renaming your internal delegate field to something else, like gameSceneDelgate and see if that fixes your issue.

Having Trouble calling HUD layer method from game layer Cocos2d

I can get the HUD layer to appear, but I can't seem to update it. I got it working in Ray's tutorial, but for some reason I can't get it working in my own app. I made a new Cocos2d project just so I can try and isolate the problem and I'm having the same issue... maybe you guys can help. ( I'm getting no errors and tried to fix the indentation as best I could for StackOverflow..)
Problem: I can't update the scoreLabel
Code:
GameHUD.h
#import <Foundation/Foundation.h>
#import "cocos2d.h"
#interface GameHUD : CCLayer {
CCLabelTTF *scoreLabel;
}
- (void) updateScore:(int)score;
#end
GameHUD.m
#import "GameHUD.h"
#implementation GameHUD
- (id) init {
if (self = [super init]) {
scoreLabel = [CCLabelTTF labelWithString:#"00000" dimensions:CGSizeMake(240,100) hAlignment:kCCTextAlignmentRight fontName:#"Arial" fontSize:32.0f];
scoreLabel.anchorPoint = ccp(0,0);
scoreLabel.position = ccp(200,0);
scoreLabel.color = ccc3(255, 200, 100);
[self addChild:scoreLabel];
}
return self;
}
- (void)updateScore:(int)score {
scoreLabel.string = [NSString stringWithFormat:#"%i",score];
}
#end
HelloWorldLayer.h
#import "cocos2d.h"
#import "GameHUD.h"
#interface HelloWorldLayer : CCLayer
{
GameHUD *_hud;
}
#property (nonatomic,retain) GameHUD *hud;
+(CCScene *) scene;
#end
HelloWorldLayer.m
#import "HelloWorldLayer.h"
#import "AppDelegate.h"
#pragma mark - HelloWorldLayer
#implementation HelloWorldLayer
#synthesize hud = _hud;
+(CCScene *) scene
{
CCScene *scene = [CCScene node];
HelloWorldLayer *layer = [HelloWorldLayer node];
[scene addChild: layer];
GameHUD *hud = [GameHUD node];
[scene addChild:hud];
layer.hud = hud;
return scene;
}
-(id) init
{
if( (self=[super init]) ) {
// create and initialize a Label
CCLabelTTF *label = [CCLabelTTF labelWithString:#"Layer A" fontName:#"Marker Felt" fontSize:64];
// ask director for the window size
CGSize size = [[CCDirector sharedDirector] winSize];
// position the label on the center of the screen
label.position = ccp( size.width /2 , size.height/2 );
// add the label as a child to this Layer
[self addChild: label];
// Try to update the scoreLabel in the HUD (NOT WORKING)
[_hud updateScore:74021];
}
return self;
}
// on "dealloc" you need to release all your retained objects
- (void) dealloc
{
[super dealloc];
}
The init is called when you invoke [HelloWorldLayer node] when the HUD is not created yet, ie, _hud is nil. Sending message to a nil object is a void operation and it doesn't crash as it is if calling functions on 'NULL` objects.

Resources