How to add SKSpriteNode from a method into another class? - ios

I'm trying to add a SKSpriteNode one class to another class MainMenu which is a subclass of SKScene. The class I created DumpTruckFramework that defines these methods is a subclass of SKSpriteNode (Which may be the problem?). Below is all the code I am using:
#DumpTruckFramework.h
#import <SpriteKit/SpriteKit.h>
#interface DumpTruckFramework : SKSpriteNode
-(void)createDumpTruckMainBody;
#end
#DumpTruckFramework.m
#import "DumpTruckFramework.h"
#implementation DumpTruckFramework
-(SKNode*)setupDumpTruckMainBody{
SKSpriteNode *mainBody = [SKSpriteNode spriteNodeWithImageNamed:#"Dump_Truck_Main_Body.png"];
mainBody.name = #"";
mainBody.scale = 0.5;
mainBody.position = CGPointMake(300, 400);
return mainBody;
}
-(void)createDumpTruckMainBody{
SKNode *mainBody = [self setupDumpTruckMainBody];
[self addChild:mainBody];
}
#end
Above is the method I use in the MainMenu class to add the mainBody sprite. Maybe the issue could be the [self addChild:mainBody]; code line as self is referring to the DumpTruckFramework class?
#MainMenu.h
#import <SpriteKit/SpriteKit.h>
#interface MainMenu : SKScene
#end
#MainMenu.m
#import "MainMenu.h"
#import "DumpTruckFramework.h"
#implementation MainMenu
-(id)initWithSize:(CGSize)size{
if (self = [super initWithSize:size]){
//[self createMainMenuTitle];
DumpTruckFramework *dumpTruck = [[DumpTruckFramework alloc] init];
[dumpTruck createDumpTruckMainBody];
}
return self;
}
Now what I think is happening is that the method does work but doesn't do what is expected. As the MainMenu scene is what is meant to be displaying the nodes, it's declared to be the "view-able scene".
Hopefully someone can help me resolve this issue, cheers.

You're not adding a sprite node to your scene. You can change createDumpTruckMainBody to:
-(SKNode*)createDumpTruckMainBody{
SKNode *mainBody = [self setupDumpTruckMainBody];
return mainBody;
}
and in your main menu change your code to:
-(id)initWithSize:(CGSize)size{
if (self = [super initWithSize:size]){
//[self createMainMenuTitle];
DumpTruckFramework *dumpTruck = [[DumpTruckFramework alloc] init];
SKNode *node = [dumpTruck createDumpTruckMainBody];
[self addChild: node];
}
return self;
}
Hope this helps.

You can add the dumpTruck to MainScene: [self addChild: dumpTruck];.

What's happening is you are creating an instance of DumpTruckFramework which almost immediately goes out-of-scope, and is therefore destroyed:
-(id)initWithSize:(CGSize)size{
if (self = [super initWithSize:size]){
DumpTruckFramework *dumpTruck = [[DumpTruckFramework alloc] init];
[dumpTruck createDumpTruckMainBody];
// dumpTruck destroyed here
}
return self;
}
So your issue is one of scope. Looks like you need to use an instance variable to maintain the DumpTruckFramework.

Related

No known class method for selector 'circleOfButtons:buttonSize:radius:'

A function circleOfButtons:buttonSize:radius: in SGView (below) is called from ParentView and I want ParentView to define the values inside SGView whenever ParentView sends a message to SGView.
This is the implementation file.
#import <UIKit/UIKit.h>
#import “ParentView.h"
#import "SGView.h"
#implementation ParentView : UIView
- (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:[UIScreen mainScreen].bounds];
if (self) {
self.backgroundColor = [UIColor lightGrayColor];
int count = 5;
CGFloat size = 80.0;
CGFloat radius = 68;
SGView *myView = [SGView circleOfButtons:count buttonSize:size radius:radius];
[self addSubview:myView];
}
return self;
}
SGView arranges multiple UIButtons in a circle and is essentially like this
#import "SGView.h"
#implementation SGView : UIView
+(id)circleOfButtons:(int)buttonCount buttonSize:(CGFloat)buttonSize circleRadius:(CGFloat)circleRadius
{
UIView *multipleViews = [self new];
// … circular geometry …
[multipleViews addSubview:circleButton];
}
return multipleViews;
}
#end
The error message - at the line SGView *myView - is:
No known class method for selector
'circleOfButtons:buttonSize:radius:'
My guess is the compiler wants a declaration in the interface. I’m working through these tutorials trying to decide what the interface file should look like and though there are 6 SO questions that may already have answered my question, only this one had an example that seemed vaguely relevant.
This is my interface file.
#import <UIKit/UIKit.h>
#import "ViewController.h"
#import "SGView.h"
#interface ParentView : UIView {
}
+(id)circleOfButtons:(int)buttonCount buttonSize:(CGFloat)buttonSize circleRadius:(CGFloat)circleRadius;
#end
Can anyone please give an example showing what this interface file should look like ? Thanks.
UPDATE
Here is SGView.h (revised)
#import <UIKit/UIKit.h>
#interface SGView : UIView {
}
+(id)circleOfButtons:(int)buttonCount buttonSize:(CGFloat)buttonSize circleRadius:(CGFloat)circleRadius;
#end
I also noticed if the statement
SGView *myView = [SGView circleOfButtons:count buttonSize:size radius:radius];
is changed to
SGView *myView = [self circleOfButtons:count buttonSize:size radius:radius];
the error changes to
No visible #interface for 'ParentView' declares the selector 'circleOfButtons:buttonSize:radius:'
it was previously
No known class method for selector 'circleOfButtons:buttonSize:radius:'
You are calling
SGView *myView = [SGView circleOfButtons:count buttonSize:size radius:radius];
It should be
SGView *myView = [SGView circleOfButtons:count buttonSize:size circleRadius:radius];
Declare +(id)circleOfButtons:(int)buttonCount buttonSize:(CGFloat)buttonSize circleRadius:(CGFloat)circleRadius in SGView.h file.
Now you will get the method in ParentView class.
Happy coding :) .

Passing Data to SKScene from UIVIewController

What I am trying to accomplish is (should be at least..) very simple: I want to present an SKScene with data that I have in the UIViewController that is presenting this scene. In other words, I have a variable chapter declared as the following:
#import <UIKit/UIKit.h>
#import <SpriteKit/SpriteKit.h>
#interface ViewController : UIViewController
#property (nonatomic) NSInteger chapter;
#end
I have tested with logs that the variable chapter is in fact declared (in my case i am just testing with it as 4).
Here is my ViewController.m file and how I am presenting my scene:
- (void)viewDidLoad {
[super viewDidLoad];
.
.
.
// Configure the view.
SKView *skView = (SKView *)self.view;
if (!skView.scene) {
skView.showsFPS = YES;
skView.showsNodeCount = YES;
// Create and configure the scene.
scene = [OLevel sceneWithSize:CGSizeMake(skView.bounds.size.width, skView.bounds.size.height)];
scene.scaleMode = SKSceneScaleModeResizeFill;
// Set the SKScene chapter #
scene.chapter = self.chapter; // <<<< NOT WORKING?
NSLog(#"CHAP TO PASS: %u", self.chapter);
NSLog(#"CHAP RECEIVED: %u", scene.chapter);
// Present the scene.
[skView presentScene:scene];
}
With scene defined as the following, with the viewDidLoad being the one shown above: (I have it subclassed)
#interface ViewController () {
OLevel *scene;
}
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
.
.
.
Here is my OLevel.h class:
#import <SpriteKit/SpriteKit.h>
#import <GameplayKit/GameplayKit.h>
#interface OLevel : SKScene <SKPhysicsContactDelegate, GKAgentDelegate>
#property (nonatomic) NSInteger chapter;
#end
And my OLevel.m*:
- (id)initWithSize:(CGSize)size {
if (self = [super initWithSize:size]) {
NSLog(#"Creating scene");
NSLog(#"CHAP: %u", self.chapter);
[self setUpScene];
}
return self;
}
I am very much confused as to why this approach is not working. I have set the property in my ViewController to the desired chapter value, I have then told my Olevel what value it is and to set it's own chapter property to such value, and then present the scene correctly. Why do I continue to get 0??
2016-07-18 23:52:32.189 TESTAPP[2038:684620] CHAP TO PASS: 4
2016-07-18 23:52:32.193 TESTAPP[2038:684620] CHAP RECEIVED: 0
2016-07-18 23:52:32.195 TESTAPP[2038:684620] Creating scene
2016-07-18 23:52:32.195 TESTAPP[2038:684620] CHAP: 0
I know this question has been answered here with the same approach that I had originally used before looking for an answer, but I have yet to get it to work..
If anyone knows what I am doing wrong please help me.
You have initialize your scene with the wrong syntax, without type:
...
// Create and configure the scene.
OLevel *scene = [OLevel sceneWithSize:CGSizeMake(skView.bounds.size.width, skView.bounds.size.height)];
scene.scaleMode = SKSceneScaleModeResizeFill;
// Set the SKScene chapter #
scene.chapter = self.chapter;
...
If you want you can also subclass init method with chapter
OLevel.h:
#interface GameScene : SKScene <SKPhysicsContactDelegate, GKAgentDelegate>
#property (nonatomic) NSInteger chapter;
-(id)initWithSize:(CGSize)size chapter:(NSInteger)chapter;
+(id)sceneWithSize:(CGSize)size chapter:(NSInteger)chapter;
#end
OLevel.m:
#import "GameScene.h"
#implementation GameScene
-(id)initWithSize:(CGSize)size chapter:(NSInteger)chapter {
if (self = [super initWithSize:size]) {
self.chapter = chapter;
//some custom code here
NSLog(#"Creating scene");
NSLog(#"CHAP: %ld", (long)self.chapter);
}
return self;
}
+(id)sceneWithSize:(CGSize)size chapter:(NSInteger)chapter {
return ((GameScene *)[[self alloc] initWithSize:size chapter:chapter]);
}
-(void)didMoveToView:(SKView *)view {
...
}
}
In this case you can create your scene as:
// Create and configure the scene.
scene = [OLevel sceneWithSize:CGSizeMake(skView.bounds.size.width, skView.bounds.size.height) chapter:self.chapter];
scene.scaleMode = SKSceneScaleModeResizeFill;
You can also try to pass your data using the NSNotificationCenter
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(receiveTestNotification:)
name:#"TestNotification"
object:nil];
NSDictionary *userInfo = [NSDictionary dictionaryWithObject:myObject forKey:#"someKey"];
[[NSNotificationCenter defaultCenter] postNotificationName: #"TestNotification" object:nil userInfo:userInfo];

iPhone - How to implement delegate between my Static library and the app which the library is used?

I have been creating a cocoa static library in which I have a public nsobject file where I created a custom delegate. In the app I imported the nsobject file and implemented the delegate but the delegate is not getting called... the static library name is glamApi.
the SKUIDPasser.h file of the NSObject in the library
#import <Foundation/Foundation.h>
#protocol SubClassDelegate <NSObject>
#required
- (void)MethodNameToCallBack:(NSString *)s;
#end
#interface SKUIDPasser : NSObject
-(void)getSKUIDsFromCart:(NSString *)SKUIDs;
#property (nonatomic, weak) id <SubClassDelegate> delegatePasser;
#end
and the SKUIDPasser.m file
#import "SKUIDPasser.h"
#implementation SKUIDPasser
#synthesize delegatePasser;
-(void)getSKUIDsFromCart:(NSString *)SKUIDs{
NSLog(#"getSKUIDsFromCart %#",SKUIDs);
[delegatePasser MethodNameToCallBack:SKUIDs];
}
#end
And the method is called from a Viewcontroller in static library
- (IBAction)CartShowEvent:(id)sender {
if (![cartBadge isHidden]) {
buyClicked = TRUE;
[self loadCart];
[self showCartItemsAll];
self.cartView.frame = self.view.bounds;
[self.view addSubview:self.cartView];
SKUIDPasser *pass = [[SKUIDPasser alloc] init];
[pass getSKUIDsFromCart:#"sssss"];
} else {
[Utilities alert:#"No products to display !!!"];
}
}
The Viewcontroller which the custom delegate has to be implemented Viewcontroller.h
#import <glamAPI/SKUIDPasser.h>
#interface ViewController : UIViewController<SubClassDelegate>{
SKUIDPasser *sk;
}
Viewcontroller.m
- (void)viewDidLoad {
[super viewDidLoad];
sk = [[SKUIDPasser alloc] init];
sk.delegatePasser = self;
NSLog(#"sk.delegatePasser %#",sk.delegatePasser);
}
- (void)MethodNameToCallBack:(NSString *)s
{
NSLog(#"MethodNameToCallBack %#",s);
}
I didn't get any error but the method is not calling..Please help me to resolve this
The very first thing you need to understand is that each instance object of a class is entirely different entity and maintains it's state separately.
In you case your have created an object of your static library in viewDidLoad: and set the delegate accordingly, but when you are making the call to method getSKUIDsFromCart, you are using a different instance for which you never set the delegate property. That's why there was no callback.
To solve this, you can set the delegate in method CartShowEvent: before making the call, something like this
SKUIDPasser *pass = [[SKUIDPasser alloc] init];
pass.delegatePasser = self;
[pass getSKUIDsFromCart:#"sssss"];
However i would suggest that you should use the instance variable of library which you already created in viewDidLoad:
- (IBAction)CartShowEvent:(id)sender {
if (![cartBadge isHidden]) {
buyClicked = TRUE;
[self loadCart];
[self showCartItemsAll];
self.cartView.frame = self.view.bounds;
[self.view addSubview:self.cartView];
//No need to create another object.
//SKUIDPasser *pass = [[SKUIDPasser alloc] init];
//Use the previously created instance object
[sk getSKUIDsFromCart:#"sssss"];
}
else {
[Utilities alert:#"No products to display !!!"];
}
}
The SKUIDPasser object that you are calling within (IBAction)CartShowEvent:(id)sender and the SKUIDPasser object that you are setting the delegate are NOT the same.
Just for a test, try calling the method [sk getSKUIDsFromCart:#"sssss"]; just after you set the delegate and you will see that it will be called because this instance has the delegate set correctly:
ViewController.m
- (void)viewDidLoad {
[super viewDidLoad];
sk = [[SKUIDPasser alloc] init];
sk.delegatePasser = self;
[sk getSKUIDsFromCart:#"sssss"];
NSLog(#"sk.delegatePasser %#",sk.delegatePasser);
}
- (void)MethodNameToCallBack:(NSString *)s
{
NSLog(#"MethodNameToCallBack %#",s);
}
Update
I updated my answer to help you call the trigger from the static library
ViewController.m
- (void)viewDidLoad {
[super viewDidLoad];
sk = [[SKUIDPasser alloc] init];
sk.delegatePasser = self;
/*
You now can pass this variable to the static library to get called
from there ...
example:
viewControllerOnStaticLibrary.passer = sk;
*/
NSLog(#"sk.delegatePasser %#",sk.delegatePasser);
}
- (void)MethodNameToCallBack:(NSString *)s
{
NSLog(#"MethodNameToCallBack %#",s);
}
Viewcontroller_in_static_library.h
#property (nonatomic, strong) SKUIDPasser *passer;
Viewcontroller_in_static_library.m
- (IBAction)CartShowEvent:(id)sender {
if (![cartBadge isHidden]) {
buyClicked = TRUE;
[self loadCart];
[self showCartItemsAll];
self.cartView.frame = self.view.bounds;
[self.view addSubview:self.cartView];
//now you are calling the same instance
[self.passer getSKUIDsFromCart:#"sssss"];
} else {
[Utilities alert:#"No products to display !!!"];
}
}

Accessing variables from another class when importing a .ccbi file

I know this topic is covered in a hundred posts here, but I'm having a lot of trouble with this particular instance and cannot figure it out.
Basically, I'm using Spritebuilder to import sprites/nodes into my game. I import a sprite of some specific class in the body of the GameScene class, but I want to be able to define a variable inside of my sprite class, and then edit it from the GameScene class. For example, if my sprite collects a coin inside the GameScene, I want to change the speed of my sprite inside of the update method in the sprite class.
Below is my code, but unfortunately it isn't working. The variable increaseY and increaseX do not appear to be available in my GameScene class. I know this is because I didn't instantiate the Penguin class properly, but I don't know how to properly create an instance of this class while simultaneously importing the .ccbi file of it. The problem line is commented on and has a bunch of ** next to it to easily find it. It's in GameScene.m. I really appreciate the help, been stuck on this for several hours.
Penguin.h
#import "CCSprite.h"
#interface Penguin : CCSprite
{
float xPosition;
float yPosition;
}
#property (nonatomic,assign) float increaseY;
#property (nonatomic,assign) float increaseX;
#end
Penguin.m
#import "Penguin.h"
#implementation Penguin
#synthesize increaseX;
#synthesize increaseY;
- (id)init {
self = [super init];
if (self) {
CCLOG(#"Penguin created");
}
return self;
}
-(void) update:(CCTime)delta
{
self.position = ccp(self.position.x + increaseX,self.position.y + increaseY);
}
#end
GameScene.h
#import "CCNode.h"
#interface GameScene : CCNode
#end
GameScene.m
#import "GameScene.h"
#import "Penguin.h"
#implementation GameScene
{
CCPhysicsNode *_physicsNode;
CCNode *_catapultArm;
CCNode *_levelNode;
CCNode *_contentNode;
}
// is called when CCB file has completed loading
- (void)didLoadFromCCB {
self.userInteractionEnabled = TRUE;
CCScene *level = [CCBReader loadAsScene:#"Levels/Level1"];
[_levelNode addChild:level];
}
// called on every touch in this scene
- (void)touchBegan:(UITouch *)touch withEvent:(UIEvent *)event {
[self launchPenguin];
}
- (void)launchPenguin {
// loads the Penguin.ccb we have set up in Spritebuilder
CCNode* penguin = [CCBReader load:#"Penguin"];
penguin.position = ccpAdd(_catapultArm.position, ccp(16, 50));
[_physicsNode addChild:penguin];
//THE FOLLOWING LINE DOES NOT WORK********************************
penguin.increaseY = 1;
// Gives Error------Property "increaseX" not found on object of type "CCNode *"
self.position = ccp(0, 0);
CCActionFollow *follow = [CCActionFollow actionWithTarget:penguin worldBoundary:self.boundingBox];
[_contentNode runAction:follow];
}
You have to change this line:
CCNode* penguin = [CCBReader load:#"Penguin"];
To this line:
Penguin* penguin = (Penguin*)[CCBReader load:#"Penguin"];
In the old line you were using the compiler was giving you an error because the CCNode class does not have a property called increaseX. increaseX is part of the Penguin class. If you want to access properties of the Penguin class you need to use a cast and let the compiler know, that what you are loading using the CCBReader is actually a Penguin instance.

Weird Error "No known class method for selector 'sceneWithSize:'"

I've recently started working with Sprite Kit now i've just opened a new sprite kit project and removed the MyScene class as I don't need it. I've then created my own subclass of SKView called PhyscisScene now when i've done this and replaced the code in ViewController.mI get this error on line 24 in ViewController.m: No known class method for selector 'sceneWithSize:' Below is all my Class files i've changed hopefully you can tell me whats going on:
ViewController.m
#import "ViewController.h"
#import "PhysicsScene.h"
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Configure the view.
SKView * skView = (SKView *)self.view;
skView.showsFPS = YES;
skView.showsNodeCount = YES;
// Create and configure the scene.
SKScene * scene = [PhysicsScene sceneWithSize:skView.bounds.size];
scene.scaleMode = SKSceneScaleModeAspectFill;
// Present the scene.
[skView presentScene:scene];
}
- (BOOL)shouldAutorotate
{
return YES;
}
- (NSUInteger)supportedInterfaceOrientations
{
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) {
return UIInterfaceOrientationMaskAllButUpsideDown;
} else {
return UIInterfaceOrientationMaskAll;
}
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
#end
PhysicsScene.m
#import "PhysicsScene.h"
#implementation PhysicsScene
- (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
{
// Drawing code
}
*/
#end
PhysicsScene is a subclass of SKView. It looks like PhysicsScene should be a subclass of SKScene. The solution is to convert PhysicsScene to a subclass of SKScene since that is what it looks like you want to use it for.
Looking at the docs, sceneWithSize is a class method of SKScene, not SKView.

Resources