I am trying to understand the benefit of using a scripting language like lua in game development on the iphone (using cocos2d for instance) and if it can help solve my problem (and improve my coding skills).
In my game I have the following code:
-(void)MenuItem:(CCMenuItem *) menuItem {
switch (menuItem.tag) {
case 1:
[[CCDirector sharedDirector] replaceScene:[Level1 scene]];
break;
case 2:
[[CCDirector sharedDirector] replaceScene:[Level2 scene]];
break;
case 3:
[[CCDirector sharedDirector] replaceScene:[Level3 scene]];
break;
case 4:
[[CCDirector sharedDirector] replaceScene:[Level4 scene]];
break;
case 5:
[[CCDirector sharedDirector] replaceScene:[Level5 scene]];
break;
case 6:
[[CCDirector sharedDirector] replaceScene:[Level6 scene]];
break;
case 7:
[[CCDirector sharedDirector] replaceScene:[Level7 scene]];
break;
case 8:
[[CCDirector sharedDirector] replaceScene:[Level8 scene]];
break;
default:
break;
}
The problem with that function is if I have 50 levels, this function will take 3 pages of code. I would like to replace this entire function with:
-(void)MenuItem:(CCMenuItem *) menuItem {
[[CCDirector sharedDirector] replaceScene:[<script> #"Level" + menuItem.tag</script> scene]];
}
where script> /script> would be a way to embed a scripting language that would concatenate the string "Level" and the level number, thus creating the name of the class. So this function would be independent of the number of levels.
So my question is: Can scripting help ? If yes, how can it help and if no, is there a solution to do that?
I'd suggest this:
NSString *levelToLoad = [NSString stringWithFormat:#"Level%d", menuItem.tag];
[[CCDirector sharedDirector] replaceScene:[NSClassFromString(levelToLoad) scene]];
Yeah, I just saved you hours of typing.
AppStore rules prohibit the use of scripting languages in your apps.
But that is not your problem, you could use the reflection API:
[[NSClassFromString([NSString stringWithFormat:#"Level%i", menuItem.tag]) scene]];
Which is not the best way to go, since you are in control of all the code, therefore you don't need to use it, it "just works" and feels hacky.
You should rather implement a level manager and have it search for the given level for you (example):
[MyLevelManager levelWithId:menuItem.tag];
Related
I am trying to create pause screen for my game. The game is developed upon continuous scrolling background (top to bottom) with obstacles which are moving independently (left to right).
Below is the code:
PauseScene.h
#interface PauseScene : CCNode {}
#property (nonatomic, retain) HelloWorldScene *mainScene;
//+ (PauseScene *)scene;
- (id) init;
#end
PauseScene.m
#implementation PauseScene
- (id) init {
if (self = [super init]) {
// Adding RESUME and QUIT button and few others to make the whole Pause screen
}
return self;
}
// Called the method when Resume button is selected
- (void) Resume:(id) sender {
//[[CCDirector sharedDirector] startAnimation];
//[[CCDirector sharedDirector] resume];
self.mainScene.userInteractionEnabled = YES;
[self.mainScene removeChild: self];
[self.mainScene StartGame]; // StartGame in MainScene contains the same code which commented out above, I will paste StartGame method later
}
// Quit method is called when the Quit button is pressed
- (void) Quit:(id) sender {
//[[CCDirector sharedDirector] resume];
//[[CCDirector sharedDirector] startAnimation];
self.mainScene.userInteractionEnabled = YES;
[self.mainScene removeChild: self];
NSLog(#"Pre Reload", nil);
//[self.mainScene scheduleOnce:#selector(ReloadGame) delay: 1.0f];
[self.mainScene ReloadGame]; // Reload method contains the code commented above
}
#end
PauseScene is mere node class.
StartGame and ReloadGame methods in MainScene file
- (void) StartGame {
// Create and display HUD layer, like, scores, navigation buttons, etc.
// Resuming the game
//[[CCDirector sharedDirector] stopAnimation];
[[CCDirector sharedDirector] resume];
[[CCDirector sharedDirector] startAnimation];
}
- (void) ReloadGame {
// Resume the game
//[[CCDirector sharedDirector] stopAnimation];
[[CCDirector sharedDirector] resume];
[[CCDirector sharedDirector] startAnimation];
[[CCDirector sharedDirector] replaceScene:[HelloWorldScene scene] withTransition:[CCTransition transitionFadeWithDuration:1.0f]];
}
The pause button is displayed in HUD layer of MainScene, so, when the pause button is clicked, we will pause the game and display the PauseScene
- (void)onPauseClicked:(id)sender {
// Code to display the pause node of this scene
// Pause the game
[[CCDirector sharedDirector] stopAnimation];
[[CCDirector sharedDirector] pause];
}
When I comment out that stopAnimation and pause part the Pause and Resume works perfect. But when I implement any of these, at the time of quitGame, replaceScene is not working somehow. I think this is because game goes in pause mode but it is not working even if I call replaceScene using scheduler on delay of 5-10 seconds.
And if I don't use these stopAnimation and pause, some sprites which are given CCAction are not being paused and goes on even when my game is paused.
Your help is appreciated because I am using Cocos2d 3.0 and unable to find any proper help.
Thanks #LearnCocos2D for your tips.
I am able to successfully implement pause/resume by just removing the code stopAnimation or startAnimation and pause and resume methods. I just replaced these all with paused property for the node.
To pause the game, need to set paused = YES for every node in the game and reverse to resume.
I've been trying to resolve a problem for a long time, unfortunately i couldn't find a solution. I hope you can help me...
I'm trying to develop a turn based game. Player 1 is the user, player 2 is the iphone. I want to receive touches when it's the player1's turn.
-(BOOL) ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event {
if (self.playerNo==1) { //control player1
CGPoint touchLocation = [self convertTouchToNodeSpace:touch];
[self selectSpriteForTouch:touchLocation];
return YES;
}
//if it's not player1's turn, return NO
return NO;
}
When it's iphones turn, I want to disable touches during 5 seconds. I tried all the ways below, but no success.
-(void)iphonesTurn
{
[NSThread sleepForTimeInterval:5];
//
//game logic...
//
}
During 5 seconds I touch screen several times. I realised that all the touches looks like stored and the app reacts to all of my touches when it's the player1's turn.
How can I completely disable touches?
Thanks for your help.
I don't know where is located your snippet of code but if it runs into the main thread you must NEVER block (pause) it!
Try to do something like that (it works with the final version of cocos2d 2.0):
- (void)iphonesTurn
{
[[[CCDirector sharedDirector] touchDispatcher] setDispatchEvents:NO];
[self scheduleOnce:#selector(enableTouch) delay:5.0f];
}
- (void)enableTouch
{
[[[CCDirector sharedDirector] touchDispatcher] setDispatchEvents:YES];
}
I'm new to Objective C and app development so please go easy on me!
I'm trying to make a basic game and need to move a sprite left or right continuously while the user's finger is on the screen - left side to go left, right to go right...
I'm trying to use update to repeat movements of a few pixels every 1/60th second. So far, this is what I have (and sorry about the formatting):
#import "GameplayLayer.h"
#implementation GameplayLayer
-(id)init {
self = [super init];
if (self != nil) {
CGSize screenSize = [CCDirector sharedDirector].winSize;
// enable touches
self.isTouchEnabled = YES;
blobSprite = [CCSprite spriteWithFile:#"blob.png"];
[blobSprite setPosition: CGPointMake(screenSize.width/2, screenSize.height*0.17f)];
ball = [CCSprite spriteWithFile:#"ball.png"];
[ball setPosition:CGPointMake(10, screenSize.height*0.75f)];
[self addChild:blobSprite];
[self addChild:ball];
[self schedule:#selector(update) interval:1.0f/60.0f];
}
return self;
}
-(void) update:(ccTime)dt{
if (_tapDownLeft == YES){
blobSprite.position.x==blobSprite.position.x-5;
}
if (_tapDownRight == YES){
blobSprite.position.x==blobSprite.position.x+5;
}
}
-(void) ccTouchesBegan:(UITouch*)touch withEvent: (UIEvent *)event{
CGPoint touchLocation = [touch locationInView:[touch view]];
touchLocation = [[CCDirector sharedDirector] convertToGL:touchLocation];
if (touchLocation.x > 400) {
if ((blobSprite.position.x+10)<460){
_tapDownRight = YES;
}
}
if (touchLocation.x < 200) {
if ((blobSprite.position.x-10>20)){
_tapDownLeft = YES;
}
}
else {
_tapDownLeft = NO;
_tapDownRight = NO;
}
}
-(void)ccTouchEnded:(UITouch *)touch withEvent:(UIEvent *)event{
_tapDownLeft = NO;
_tapDownRight = NO;
}
-(void) registerWithTouchDispatcher{
[[CCTouchDispatcher sharedDispatcher]addTargetedDelegate:self priority:0 swallowsTouches:YES];
}
#end
Am I on the right lines with this? At the moment it's giving me 'expression result unused' in update. Could anyone tell me what I'm missing? Any help would be greatly appreciated.
Thanks,
Patrick
i see a few things here:
not certain your selector will call update : #selector(update:)
I would not rely on dt being either exactly 1/60th of a second, nor being constant. I would favor defining a speed constant (in points per second) and compute the deltaX in points based on the desired speed and dt, at each update cycle.
I dont see a 'registerWithTouchDispatcher' call (i try to place them in onEnter and onExit) methods.
Somewhere in there, make certain you remove your children (either in dealloc, or better in a local cleanup method (dont forget to invoke [super cleanup]).
Remove the argument in the update function
Has anyone managed to get the gesture recognition working in cocos-2d?
I have read a post here that claimed to have achieved it, here: http://www.cocos2d-iphone.org/forum/topic/8929
I patched from the git hub here: https://github.com/xemus/cocos2d-GestureRecognizers/blob/master/README
I made a subclass of CCSprite (which is a subclass of CCNode):
-(id) initWithTexture:(CCTexture2D*)texture rect:(CGRect)rect {
if( (self=[super initWithTexture:texture rect:rect]) )
{
CCGestureRecognizer* recognizer;
recognizer = [CCGestureRecognizer
CCRecognizerWithRecognizerTargetAction:[[[UITapGestureRecognizer alloc]init] autorelease]
target:self
action:#selector(tap:node:)];
[self addGestureRecognizer:recognizer];
}
return self;
}
Delegate method:
- (void) swipe:(UIGestureRecognizer*)recognizer node:(CCNode*)node
{
NSLog(#" I never get called :( ");
}
My tap event never gets called.
Has anyone got this working? How difficult is it to do gesture recognition manually for swipe detection?
You need to attach the gesture recognizer to something "up the chain". Don't attach them to the individual nodes; attach them to the UIView (i.e., [[CCDirector sharedDirector] openGLView]).
Here's what I did:
- (UIPanGestureRecognizer *)watchForPan:(SEL)selector number:(int)tapsRequired {
UIPanGestureRecognizer *recognizer = [[[UIPanGestureRecognizer alloc] initWithTarget:self action:selector] autorelease];
recognizer.minimumNumberOfTouches = tapsRequired;
[[[CCDirector sharedDirector] openGLView] addGestureRecognizer:recognizer];
return recognizer;
}
- (void)unwatch:(UIGestureRecognizer *)gr {
[[[CCDirector sharedDirector] openGLView] removeGestureRecognizer:gr];
}
This particular code is used in a superclass for scene controllers, so the target for the selector is hard-coded to "self", but you could easily abstract that to a passed-in object. Also, you could extrapolate the above to easily create gesture recognizers for taps, pinches, etc.
In the subclass for the controller, then, I just do this:
- (MyController *)init {
if ((self = [super init])) {
[self watchForPan:#selector(panning:) number:1];
}
return self;
}
- (void)panning:(UIPanGestureRecognizer *)recognizer {
CGPoint p;
CGPoint v;
switch( recognizer.state ) {
case UIGestureRecognizerStatePossible:
case UIGestureRecognizerStateBegan:
p = [recognizer locationInView:[CCDirector sharedDirector].openGLView];
(do something when the pan begins)
break;
case UIGestureRecognizerStateChanged:
p = [recognizer locationInView:[CCDirector sharedDirector].openGLView];
(do something while the pan is in progress)
break;
case UIGestureRecognizerStateFailed:
break;
case UIGestureRecognizerStateEnded:
case UIGestureRecognizerStateCancelled:
(do something when the pan ends)
(the below gets the velocity; good for letting player "fling" things)
v = [recognizer velocityInView:[CCDirector sharedDirector].openGLView];
break;
}
}
If you don't want to handle everything manually I created a simple category that will add gesture recognizers to any cocos2d version
read more at:
http://www.merowing.info/2012/03/using-gesturerecognizers-in-cocos2d/
or grab it from github
https://github.com/krzysztofzablocki/CCNode-SFGestureRecognizers
My question is to look for design solution for pause/resume states (including all data info, which need save ) during cocos2d game.
Including following cases, but not limited:
1). User choose quit, then pop out one dialog for user to choose " quit directly", " pause " ;
2). Someone call in , pop out dialog for user to choose "quit " or " pause " game.
If choose "pause", everything which deserve saving, should be saved. Just like PC games do.
I know Director provides "pause" , "resume " , is that okay for this task ?
Thanks for anyone clues or comments.
Welcome for further discussing via email : apple.dev.sh#gmail.com
Here is a good example:
To pause:
- (void) applicationDidEnterBackground:(UIApplication *)application
{
[[CCDirector sharedDirector] stopAnimation];
[[CCDirector sharedDirector] pause];
}
- (void)applicationWillResignActive:(UIApplication *)application
{
[[CCDirector sharedDirector] stopAnimation];
[[CCDirector sharedDirector] pause];
}
When resuming:
- (void)applicationDidBecomeActive:(UIApplication *)application
{
[[CCDirector sharedDirector] stopAnimation]; // call this to make sure you don't start a second display link!
[[CCDirector sharedDirector] resume];
[[CCDirector sharedDirector] startAnimation];
}