Newbie to iOS and Cocos2d ( 2.x )
Ok I want to create a Menu Object and call it from each new Scene.
Example:
Scene1, add menu
Scene2, add same menu as on Scene1
I've only seen how to initialize the CCMenu when you init the Layer itself. you build the items and then add them to the CCMenu and so on.
http://www.cocos2d-iphone.org/wiki/doku.php/prog_guide:lesson_3._menus_and_scenes
How can I initialize the CCMenu once and then just add it to what ever scene I happen to be viewing? So if I'm viewing Scene1 or Scene2 it's still the same menu.
Does this make sense?
You'll need a different instance of the menu for each scene, so technically speaking, you'll need to initialize it once per scene.
But I think you're asking "how can I write the code once and then reuse that code in each scene." You'll want to create some sort of CC Object that you can reuse. This could be a subclass of a CCMenu, CCLayer, or whatever suits the purpose best. So you may try something like:
#interface MyMenuLayer : CCLayer {
CCMenu *myMenu;
}
#end
Then in the .m file, set up your menu however you like. When you want to include this in Scene1:
MyMenuLayer *menu = [MyMenuLayer node];
[self addChild:menu];
You can use the exact same code in Scene2.
(You could just extend CCMenu instead of CCLayer, but I personally prefer to work with Layers instead of Menus. It's a matter of personal choice.)
It's hard to give a very definitive answer with the information in your question, but I hope this gets you set off on the right path.
Related
When creating a new game in Xcode using Swift, the template creates a GameViewController.swift file and a GameScenes.swift file. Is the right way to think about the purposes of these files that the former (GameViewController) is like the controller while GameScenes is like the view?
If true, why do some tutorials show gesture recognizers (e.g., tap, swipe) getting implemented in GameScenes instead of GameViewController?
Yes you could see it like that.
Just check the example code when you start a new SpriteKit-project. If you open the GameViewController.swift file you see the following line in the viewDidLoad method:
let skView = self.view as SKView
....
skView.presentScene(scene)
Here you see the answer to your question. The view, which is in your UIViewController gets casted to SKView and presents the GameScene. So the steps are like that:
UIViewController --> View --> GameScene
But about the tutorials. It depends on the developer how he handles that. If you compare it to for example an extension. You can write a util-file where you put everything in, what you want do re-use or you write it straight in your GameScene-file. Of course it's best practice to create an own file for it. But many tutorials just want to have everything in one spot so it's easier for beginners to understand etc.
But often it's way more complicated to write it in the UIViewController. For example if your try to use a GestureRecognizer.
But if you check tutorials like for example on raywenderlich.com you will see, that these are well splitted.(in the final projects).
I made a new .ccb file on SpriteBuilder where I created an animated CCSprite with physicsEnabled and a few physics properties. At a certain point I would like to draw the animated CCSprite on a menu. I don't want to make a copy of the whole .ccb file because now I don't need the physics part I just want to copy the CCSprite and the animation (which is a set of keyframes). What's the best way to achieve this?
You just need to make a new class in Xcode, and then make a new object of that class and add it to the menu. I explain the steps:
Go to that new .ccb file in SpriteBuilder and select the content Node of the CCSprite. (It depends on what kind of .ccb file you created, scene,sprite,node...) Then go to Code Connections and select a name for Custom Class, for example MyAnimatedSprite.
So now go to Xcode, and then make a new file in your project with type CCNode, and name it 'MyAnimatedSprite'.
Now the final step is to add this sprite to the menu.
You must have a Physic Node previously added to the menu .ccb file and also declared in the .m file, because you said your sprite has physics enabled. If you don't have it, simply add it with sprite builder wherever you want, and go to Code Connections and select under custom class, Doc Root Var and call it for this example, '_physicsNode'
Now go to the Menu class in Xcode, and simply add the sprite class to the menu with these lines:
#implementation Menu{
..... YOUR CODE .....
CCPhysicsNode *_physicsNode; //add physics node if you don't have it
}
-(void) didLoadFromCCB{
//create a new object of type MyAnimatedSprite
CCNode *myAnimatedSprite = [CCBReader load:#"MyAnimatedSprite"];
...YOUR CODE....
}
And you will have your sprite in your menu working perfectly :)
I want to make a group of cocoa touch objects behave like one object, Is this possible?
For instance, say we had a SuperButton that consisted of two UIButtons, spaced by 10.
Let's just say their frame is set.
Is it possible to make a wrapper class ?
that I can init and call -
[_view addSubview:SuperButton] on and have it create both buttons?
I'm not entirely sure on the terminology for what I'm trying to do so it's hard to find any help on google.
Okay, Let me ask you this question first. So you want to create a SuperButton, when ever you call it it should layout the two buttons for you, is this right ?. YES you can do this. Create a new XIB, which is having just a view. configure your buttons in it. Create your super button class and assign it to this xib. You should be able to call this class and it will return view which can be added to your main view controller.
I've got an app that I've developed for the iPhone, but now want to port to the iPad. The iPhone app is navigation style and based on discrete table view controllers managed by a nav controller. The larger screen real estate of the iPad means that I can comfortably fit a couple of these table view controllers on to the screen at the same time.
The question is how? Should I
a) have the main view load two table view controllers from separate NIBs and then position them on screen (I'm not sure how I set they x and y of subviews loaded from nibs).
b) create sub-views in my main nib and populate these with data from my existing classes (if so how do I hook up the IBOutlets)?
c) do something completely different
One thing I should point out is that I don't want to use the split screen option.
Alert! This QA is now of historic value only.
It is now trivial to do this sort of thing with container views in iOS, which is why Apple edited them:
https://stackoverflow.com/a/25910881/294884
How to add a subview that has its own UIViewController in Objective-C?
Historic answer...
".. how I set they x and y of subviews loaded from nibs?"
I'm not sure if I fully understand your question Phil, but here's an easy and clear way:
Fire up interface builder and in the new larger iPad view, simply add new smaller views (UIViews)... Put them exactly where and how you want them. We are going to call these "basket" views.
Let's say one of your complicated views from the other app is your fatDogs view. Call the new basket view fatDogsBasket. Then in the code, in viewDidLoad, just do the following with all these "baskets"...
[fatDogsBasket addSubview:fatDogs.view];
[clientsBasket addSubview:clients.view];
[namesBasket addSubview:names.view];
[flashingLightsBasket addSubview:flashingLights.view];
// etc
You're done! (Obviously, make sure that the relevant view controllers, fatDogs, flashingLights and so on, are all ready to go and instantiated.)
The "basket" system is handy since each one will hold your previous work in one place; usefully you can (say) set overall invisibility or whatever just by touching the baskets. Obviously, if you want to set, or maybe move, the position of a basket in the code, just go
happyBasket.frame = CGRectMake(509,413,
happyBasket.frame.size.width,
happyBasket.frame.size.height);
UIViews in iOS are very lightweight, so it's no problem at all adding another layer of UIViews.
I hope this is what you were getting at!
------Later...
You went on to ask: "Just to make sure I'm clear on the right way to implement this. The main view controller has IBOutlets for each of the 'baskets' and its this IBOutlet connection to the subview that I'm calling. Each of the view controllers that I'm going to show in each basket has it's own nib and associated IBOutlets. Right? –"
So, "The main view controller has IBOutlets for each of the 'baskets'"...
Right, the main view in the new app, would have lines like this in the .h file:
IBOutlet UIView *fatDogsBasket;
Note that you are simply declaring "fastDogsBasket" to be a UIView. You shouldn't worry too much about the "IBOutlet" word. All that means is "I need to be able to look this item up, over in the interface controller." It's important to realise IT DOES NOTHING.
So yes all the "baskets" will be UIViews and hence of course you must delare them as such in the .h file of your main view controller. Personally is would not use the phrase "a view controller has IBOutlets." It sort of confuses things and gives the wrong idea. Just say "don't forget to mark the UIViews as iboutlets in the header file."
So anyway yes that's exactly what you do, declare all the "basket" UIViews in the .h file of the main controller, and indeed mark them all as IBOutlets so that interface builder will work more easily. Next ..
"its this IBOutlet connection to the subview that I'm calling" -- that's wrong.
The basket such as fatDogsBasket IS SIMPLY A UIVIEW and that's that. It's just a UIView.
Now, as you know you can put UIViews inside other UIViews. (Obviously, this is commonplace, every UIView has scores of UIViews inside it and so on and on - it's the most basic part of building up an interface.)
So, what are you going to put inside your fatDogsBasket uiview? You're going to put in ALL YOUR PREVIOUS WORK on fatDogs! Previously (for the iFone) you wrote a wonderful class - a view controller - called fatDogs. (It may well have even had many subclasses and so on.)
We're now going to take the view from fatDogs (of course, that is fatDogs.view) and literally put it inside fatDogsBasket. (Recall that fatDogsBasket is a UIView.)
So firstly you would have to completely include your amazing class fatDogs (from the old project) in your new project. Click "add existing flies/classes" or something like that...you'll figure it out. Yes, add all the class files, xibs, any subclasses and so on.
Then, simply do this .. in your new super-powerful uber-controller, in viewDidLoad, just do the following with all the "baskets"...
[fatDogsBasket addSubview:fatDogs.view];
[clientsBasket addSubview:clients.view];
[namesBasket addSubview:names.view];
[flashingLightsBasket addSubview:flashingLights.view];
// etc
You're done! Note that the view from fatDogs (ie, fatDogs.view) is now displaying inside of the UIView fatDogsBasket. The class fatDogs will now work completely normally, just as it did in the old days! And incredibly, you can easily (here in your new controller) do things like simply move fatDogsBasket, and it will move the fatDogs view easily all at once, without worrying about the details of fatDogs and it's views.
Finally you ask..
"Each of the view controllers that I'm going to show in each basket has it's own nib and associated IBOutlets."
Exactly correct. When you add your old system "fatDogs" to the new project, you will be adding all of it's xib files and so on. Anyting that happens or doesn't happen inside those classes, to do with perhaps buttons or anything else marked as iboutlets, or anything else, will just still be the same within those classes. I'm pretty sure absolutely NOTHING will change when you use those old classes in your new project.
Just for the record .. "Each of the view controllers that I'm going to show in each basket.." Just to be accurate, you don't really show as such a viewcontroller, you show the view of the viewcontroller (!!). In other words, for fatDogs (a view controller) you will be showing it's view, which is, simply enough, referred to as fatDogs.view. ("view" is, of course, a property of any UIViewController, so you can just say vcName.view and you're done.)
Hope it helps!
And finally you ask .................................
"I've got it compiling OK, but my baskets are showing up empty, i.e. they're not showing the views of the view controllers that I've imported."
Tell is the name of one of your UIViewController classes from the old project, so we can be specific
Let's say you have an old UIViewController called HappyThing. So you will very likely have a file HappyThing.h and a file HappyThing.m and a file HappyThing.xib.
put all those in the new project, you must do so using Add->Existing Files. (Control on one of your current filenames in the list on the left in XCode.)
You will have to do this #import "HappyThing.h" somewhere or other in your new project - either in your Prefix.pch file or at the top of your new UIControllerView
To be clear in HappyThing.h you will have a line of code
#interface HappyThing : UIViewController
In your new UIViewController.h file, you will have to add a new variable, we'll call it xxx,
HappyThing *xxx;
Note that the type of xxx is HappyThing. (Note that as a rule, you would use the naming convention "happyThing" (note the lowercase "h") rather than "xxx", but it's just a variable and I want it to be clear to you that it's just a variable.)
Next! At the moment it's just a variable that is not pointing to anything, it's nothing. (Just as if you said "int x", but then did not actually say "x = 3" or whatever.) So! In your code you have to actually instantiate xxx.
xxx = [[HappyThing alloc] init];
[xxxBasket addSubview:xxx.view];
Note that the first line is what makes an instance of HappyThing come in to existence. And of course, you want to use "xxx" to point to that instance.
The second line puts the view in to the relevant basket! Note that of course what you want is the view associated with xxx (ie, xxx.view) ... remember that xxx is a UIViewController, it is not itself a UIView. The associated UIView is "xxx.view". (The view is literally just a property of xxx.)
Memory management! Note that you used "alloc" to bring xxx in to existence. This means you DO own it, and of course that means YOU DO NOT need to send a retain there. Furthermore, since you do own it, that means You eventually have to RELEASE it. (easy ... [xxx release];)
So simply add the line [xxx release]; to the dealloc routine in your new UIViewController. (Really it won't cause any harm if you forget to do this, but do it anyway.) Conceivably you may want to release it earlier for some reason once you are more comfortable with the process.
(I was just working on a project with a huge number of huge tables, popovers and the like, so I only made them on the fly and got rid of them as soon as possible, to use less memory. But all of that is irrelevant to you at this stage.)
So now you should SEE IT ON THE SCREEN!
Don't forget if you previously had some routine in HappyThing, which you had to call to start it working (perhaps "beginProcessing" or something), you'll have to call that yourself from the new UIViewController. Hence perhaps something like:
xxx = [[HappyThing alloc] init];
[xxxBasket addSubview:xxx.view];
[xxx beginProcessing];
[xxx showAmazingRedFlashingLights]; // or whatever
Finally you asked ...
"When you've use this technique, do you simply include the headers of the imported files in your main view controller, or do you forward class them in some way?"
That was not your problem, your problem was that you were not instantiating it with the line xxx = [[HappyThing alloc] init];. So, good luck!
Regarding the line of code "#class HapyyThing", if you want to simply put it just above the start of the definition of your new UIControllerView. Generally you don't have to if you have your include line in the best place. Anyway it is an unrelated issue. It simply won't compile if your new UIViewController, can't find HappyThing. Enjoy!
note: This is an expansion (and clarification) of a question I asked yesterday.
I am conducting a research project where I want to record all of the user's touches in the iPhone app. After the experiment, I will be able to download the data and process it in either Excel or (more likely) Matlab and determine how many times they clicked on certain buttons, when they clicked certain buttons, etc. To do this, I would need to know:
a) When they touched
b) Where they touched
c) Which view they touched
The first two are easy, but the third I am having trouble with. I know I can do this to get the reference to the UIView that was touched:
CGPoint locationPoint = [[touches anyObject] locationInView:self];
UIView* viewYouWishToObtain = [self hitTest:locationPoint withEvent:event];
However, that will just give me a pointer to the view, not the name of the view that was touched. I could assign each view a tag, but then every time I create a new view I would need to remember to tag it (or, alternatively, log the address of each view when initialized and log it when the view is touched). Subclassing UIView and adding an automatic tag isn't really an option since I'm creating other UIButtons and UISliders and would need to subclass those also, which doesn't seem like a very good solution.
Does anyone know of a clean, easy way to do this?
For "Which view they touched", what information do you need?
Perhaps you could use a category to add a method to UIView. This method would generate a string containing information about the view. Such as:
its type e.g. UIButton etc.
its size and position
the title of the view, if it has one (e.g. the button title)
the parent view type and title
other stuff e.g. is the view enabled, what state it is in. anything you like.
For example: "Type:UIButton Title:"Back" Rect:{3,5,40,25}" or some such string.
This is very clean and gives you quite a lot of information to be going with.
You could add a category to UIView which would then be inherited by all UIView descended objects, although I'm not sure its any more efficient than tagging. Since a category can override methods then you could override init methods for automatic tagging I suppose.
http://macdevelopertips.com/objective-c/objective-c-categories.html
I'm not sure what you mean by the "name" of the view. If you mean the view name in Interface Builder, I don't believe it includes that in the instantiated objects. You could use the Tag attribute which is included, but that's just a number and not a name.