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.
Related
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!
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];
}
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).
I'd like to extend the iOS UIView class so I can store some of my own data and state within my UIView instances. I am new to iOS. I understand that I can't add instance variables to Categories, so presumably I can't add new state to my UIViews.
I am therefore thinking of creating an NSArray, where each of my UIViews has a unique tag which is then used as an index into an NSArray, and where each item in the NSArray holds the additional state information about that particular UIView. The drawback here is the management of the Tags and the NSArray. It would be so much more straightforward if I could just add state directly to any UIView via a Category.
Can anyone advise me on the best way to add some instance variables and state to UIViews? I am using lots of UIView subclasses, and so don't really want to start subclassing UIView.
Thanks.
Associative references will let you do what you want, though I'm not sure why you don't want to subclass (you already say you have a lot of subclasses - perhaps a better strategy of subclassing would be a better solution?).
Just use UIView.tag property for that. Its NSInteger (long), so you can have a map somewhere else.
The question is not only regarding the headline, but more of a "how will I achieve this, without trying to force a Java/Flash design into an Objective C (iPhone)program".
I have 6 views that extends UIView, these views all have different behavior but share certain methods, like -(void) update and -(void) changeState:(NSInteger)state.
A viewController, whose job is it to update, instantiate and display these views has a switch block to do this. So switch(4) {...} instantiates UIView4, but as I need a reference to the currently instantiated view (to do update and changeState:), I have a UIView property on my ViewController called self.currentView. As the instantiated UIView4 extends UIView I can easily go [self.currentView addSubview:UIView4instance] and then release the UIView4instance.
Now how will I call the [UIView4instance update] method on the view? or the [UIView5instance changeState] etc. etc.
Since I added it to self.currentView which is of type UIView it no longer has any reason to believe it has an update or changeState: method, meaning I cannot iterate the views and send them these messages.
This approach brings on a ton of other problems, I would need to test and typeCast my views each time I needed to do any operations on them.
If I were doing something like this Composite Pattern approach in, say, Java. I would either write an interface that all the views (UIView1, UIview2.... UIViewN) would implement. Or maybe an abstract class that all the views inherited the changeState: and update methods from.
This way I could have self.currentView just know that I'm adding objects to your view and they all conform to these methods.
The two solutions I can think of, with my very small Objective-C experience is:
doing it with delegation or categories, but this seems overkill in every way :/
I guess I could also extend UIView and then extend my class extending UIView again, but there is probably a reason Objective-C does not directly support abstract classes...
Hope someone could point me in the right direction regarding these issues.
Thanks:)
Yes it is equal. You can declare a protocol
#protocol MyViewProtocol
-(void)update;
-(void)changeState:(NSInteger)state;
#end
and declare your subclasses like
#interface MyUIView3 : UIView<MyViewProtocol> {
....
}
....
#end
Then, the declaration
UIView<MyViewProtocol>* view=[[MyUIView3 alloc] init];
means that view is an instance (of a subclass of) UIView which also conforms to MyViewProtocol.
Just the way it works in Java, I think. See the apple doc on protocols.
One thing to be aware of is that while defining a protocol like this is a convenience and certainly makes things clearer, it is by no means necessary to make your solution work. Objective-C binds methods at runtime, and so all you really need to do is to make sure all your view classes implement the methods you care about and call them.
You will get a complier warning for this, but it will work.
Now, in general it's probably preferable to define a protocol like this and it's what I generally do. But it's also important to remember that runtime binding is there and can be incredibly powerful.