How can I create a usable, base class that inherits CCLayer? - objective-c

I am wanting to create a base class that inherits from CCLayer. My reason is because I have a single-image, full screen CCSprite that I want to overlay on every scene of my application. Creating a base class, and adding a CCSprite containing the image as the top-most Z object seems to make sense because it will prevent me from having to re-code the same overlay implementation again and again for each scene.
I've been able to derive a class from CCLayer with relative ease. However, I cannot figure out how to correctly create a scene another layer class that is a child, of a child of CCLayer. How can this be done, and work?
I understand that when most users ask such questions, the first follow is "Show us your code." I can show you the code but I am most interested in is a very generic implementation of Cocos2d object, that is derived from CClayer and can be used as a base class for other layers, pre-wiring common sprites and objects.

I think this may be your problem:
"I cannot figure out how to create a scene that is a child, of a child of CCLayer."
As I understand it, Cocos layers are added as children to Cocos scenes, not the other way around, as the quote seems to imply.
I think you could simply make a custom layer class, deriving it from CCLayer and adding your CCSprite. Then simply go to everywhere you are creating or deriving a CCLayer and instead create or derive it from your custom layer class and then show or hide the sprite when needed.
Alternatively, and probably more easily, you could create a category on CCLayer adding a "showFullscreenSprite" method which simply creates the sprite and sets its image, then calls
[self addChild:yourSprite z:yourSprite.zOrder tag:9999];
You would also need a corresponding "hideFullscreenSprite" method which would simply do this
[self removeChildByTag:9999 cleanup:YES];
The nice thing about this approach is you wouldn't need to sub-class at all and all of your CCLayers would now have your "showFullscreenSprite" and "hideFullscreenSprite" methods available.
(Note: "9999" has to be some number you're not already using as a CCNode tag. Make it big enough so you don't have to worry about it. Maybe pull it out into a constant such as "FULL_SCREEN_SPRITE_TAG" or some such for readability.)
Hope this helps!

Related

How to create an extended MKMapView

I have an app which uses maps on several different screens. All the maps should display the same basic information (annotations and overlays), but every instance adds different additional annotations and overlays to the map. I want to create a class, which implements the common features and behaves exactly like the MKMapView. How is this possible?
I've had three ideas to solve this, but none of them seems to be a good solution.
Subclass MKMapView. The problem with this approach is that the map gets the information about it's annotations and overlays from it's delegate, which should be the subclass (a view...) itself, therefore adding additional data is problematic (I can't set the delegate other than the class itself).
Wrap MKMapView. I could create an NSObject/UIView subclass which has an MKMapView, but either I have to proxy all of the map's methods to my class or access the map with a knowledge of the inner objects (myMapView.mapView.xxx...).
Create a delegate class (NSObject with MKMapViewDelegate functions). The delegate class could then implement the common behavior. This solution also has issues similar to the first one.
How can I solve this elegantly?
Create a class and Add Map to view of that class.
Now make that class as parent class for all class where you want to add Mapview.
Provide data to parent class when you want to add annotations and overlays.

Objective-C: Refactoring code - how do I get a pointer to a view instance?

I am not very experienced with OOP so I wanted to share what I am currently doing and ask for some advice about how I should go about a couple of things.
I am currently working on a simple game that uses a 2d grid. Here is a quick overview of my class structure:
'GameBoard'- has an array of the possible cell states for the game, and methods that implement the rules.
'GameView' - has the superclass NSView, and is placed in my window as a custom view. This class is intended to read from the game board and draw the contents of the array by mapping the stares to an enumeration of images in its drawRect: method.
'GameController' - this is an intermediate class intended to initialise the game board and view, and handle the various UI controls. This class has instance variables of the 'GameBoard' and 'GameView' type.
Originally, I was doing nearly everything in the View class, and had it working fine but it started to get hard really to follow, which was my main reason for wanting to spread my code over a new class.
I have created a method in 'GameController' that initialises a new game, with some user defined parameters (removed in the snippet to save space).
-(IBACTION)initialiseGame:(id)sender {
gameBoard = [[GameBoard alloc] init...];
gameView = [[GameView alloc] init...];
}
What I want to do here is pass the game view a pointer to the game board instance so that I can read it's array to draw the current state of the game, something like:
-(void)initWithGameBoard:(GameBoard*)gameBoard;
Is this the right way of going about that, or should I be doing this in a different way?
My next problem with moving to the controller class is that I cannot seem to find out how to do is get a pointer to the instance of GameView that I have placed on the window in IB? Would it be better to not place the view on the window in interface builder, and instead place it on the window programatically in the initialiseGame function? If so how would I go about doing that?
I guess one other question would be, should I just scrap this idea and stick to doing everything in the GameDraw class?
Thank you very much for taking your time to read this, this is probably a very simple question to any experienced object-oriented programmer, but I cannot seem to find the answers specifically anywhere.
There's more than one way to do make this work, but here's how I would do it:
Instantiate the view once in IB. Don't invoke alloc/init yourself.
In your view controller, make an outlet for your view and connect it in Interface Builder. That's how your controller will get access to it. Your view controller will need to be the file owner — probably it already is.
Design the view to be reusable. Give it a -setGameBoard: method for the controller to invoke. Make sure the view can draw something blank when it doesn't have a game board.
Write -initializeGame: like this:
-(IBAction) initialiseGame:(id) sender {
gameBoard = [[GameBoard alloc] init...];
[gameView setGameBoard:gameBoard];
}

Optimum class hierachy in Obj-C

In my project (a game) I have multiple objects that are manipulated by touch, so I thought that having all touchable objects as subclasses of a "Touchable" abstract class would be a good idea, something along the lines of:
Touchable is a subclass of CCSprite
Box is a subclass of Touchable
Motor is a subclass of Touchable
therefore Box and Motor are CCSprites, and they inherit the common methods of Touchable, and can override them
Is this a correct way to go about this, or is there some other way to tackle this hierachy?
I previously explained why subclassing CCSprite is almost always a bad idea.
"Touchable" as the name suggests is an ability of an object. A node can either be touched, or it can not. Moreover, this must not be restricted to sprites. What if later on you want a touchable label, a touchable particle effect, or some other touchable node class?
Obviously you can't subclass CCNode to make it touchable and then turn subclasses of that touchable node class back into sprites, labels, etc. because cocos2d already established a class hierarchy - this is where the inflexibility of such a hierarchical system surfaces, and starts becoming a real pain.
You could add such a touchable (or killable, flying, jumping, drivable, swipeable, etc) ability to any object, at any time, and you could take it away at any time as well. That makes it a candidate for a plugin class (a component). Any ability, especially those that may be temporary, should not be part of a superclass but instead be additional objects that you can add to an existing object, and enable/disable as needed.
One way to go about this is to use the userObject property of nodes. Write an Abilities container class, and assign it to the userObject of your nodes. Then add the desired Ability classes to the container of a node. The node then updates the userObject container class by forwarding the update method, which forwards update to all abilities. Or the Ability container itself registers with CCScheduler to receive updates. The only thing the container class and ability classes need is a (weak) reference to the owning node.
Depends on if "Touchable" represents a random set of behaviors that each class must explicitly implement to support or if there can be a single implementation that "just works" with inheritance (with, maybe, a bit of customization).
If the former, then your thinking is mostly correct. If the latter, then Jack's suggestion of using an #protocol (which is a lot like an Interface in Java) makes sense.
Personally, I'd keep it really simple. Start with an SPAbstractSprite class that is a subclass of CCSprite. Then, subclass that into SPBox and SPMotor.
Start your implementation in SPBox and/or SPMotor and, as common things fall out, refactor them into SPAbstractSprite.
As for the notion of "touchable", I wouldn't worry about trying to make that a named thing for now. Approach it the same way as above; implement touchable support in your motor or box, then refactor up to the abstract parent class later.
I am, quite admittedly, a very design-and-code-interleaved person, though, and fully acknowledge that there are those who really like to sit down and draw out a nice set of box/lines/hierarchy before writing a line of code.
In any case, you should note that the class hierarchies across the Apple provided classes and examples tend to be quite shallow and don't tend to do a huge amount of this abstraction, though abstraction is still used heavily (UIView is an abstract container for all the view like goop that all those subclasses need, for example).

The most efficient way to implementing similar scenes

So I'm creating a game with cocos2d, and alot of my scenes (not all, but alot), will have sort of a "scoreboard" you could call it, and they will have the basic principals. I was wondering, how could I make it so the "game scenes" could all implement the scoreboard?
I was thinking this could use something like Categories, but I'm fairly new to iOS/obj-c so I don't know if that's the right approach.
In Java, I could probably just make all the scenes subclasses and have the superclass do all of the scoreboard handling, but I have no idea how to do that in iOS/obj-c.
Thanks
Subclass CCNode or any other class that's appropriate (CCScene, CCLayer, it doesn't really matter). Name this class MyScoreboard. Design your scoreboard node like any other scene by adding nodes to it and positioning them.
Then, wherever you need the scoreboard just create an instance and add it to the node hierarchy:
MyScoreboard* scoreboard = [[MyScoreboard alloc] init];
[self addChild:scoreboard];
Amend init with parameters (initWithScore:Player:WhatNot:) as needed.
You can use the same solution here. Create subclass of CCScene. Then implement your score logic there. All subclasses of your scene will be able to call these methods. For example, you can create methods showScore/hideScore or smth else. There you can construct and add/remove imstance of your scores to the current scene.

UIView/UIImageView inheritance

In my program, I have a class called Object, which inherits from UIView. I also have other objects called: circle, square, triangle which inherit from Object.
My problem is that I would like to make a possible object called Image, which also inherits from Object. I would like all objects on the screen to inherit from Object, and then pass an NSArray pointer to my physics functions that contains all objects on the screen.
What is the best way to have my Image object acquire all the properties of my Object class?
Should I just create new properties for my Image object, or is there a way to inherit Object and still be able to display an image, since Object inherits from UIView and not UIImageView.
You've realized that a class cannot extend two parent classes.
Could your "Object" be a Protocol instead of a Class? That way circle, square and image could all implement that protocol while extending either UIView or UIImageView as needed?
That's a very…unusual way to do it. Have you had any Java experience?
What are you trying to do with the Shapes? Are you trying to draw them in those respective classes? Here, you're blurring the lines of MVC. From what it seems like, your Circle, Square, etc. classes are both a model and a view, which shouldn't happen. If you're trying to draw the shapes, you wouldn't create classes for them—you'd use the Quartz drawing methods to draw them in your view controller's view. If you're trying to store info about those shapes, you wouldn't want them to inherit from UIView. NSObject (or a custom Shape class) would be a better option. (It's also a bad idea to call the class "Object"—it could get confused with NSObject).
You're second paragraph is where my first question came from. Your NSArray does not have to contain variables of the same type—this is very different from Java's arrays (and other languages such as C# and C). Therefore, unless there were some methods or ivars you wanted to inherit, there was no reason to declare the Object class.
As for displaying images, what are you intending to do with Image? If you just want to display images (a view), then make it a subclass of UIImageView (which is a subclass of UIView). If you want do store information about images, make it a subclass of Shape (or in this case, your Object). However, you really can't do what you want to (inherit from both Object and UIImageView) because you shouldn't combine functionality of views and models.
Really, your best option here is to revisit your classes, make them adhere to MVC, and rethink your inheritance chain. Hope this helps!
The simplest thing would be to have Image inherit from Object and then have Image own a subview of type UIImageView.