从另一层重新启动游戏/场景
Posted
技术标签:
【中文标题】从另一层重新启动游戏/场景【英文标题】:Restarting game/scene from another layer 【发布时间】:2013-06-28 01:26:08 【问题描述】:我真的很头疼,想暂时诊断一下这个问题。
详情: 我有以下节点:
-
游戏层;主游戏层,也是一个半单机。
HUDL 层;一个简单的 HUD 层(用于得分和暂停按钮),当然与 GameLayer 一起添加到场景中。
暂停层;一个 CCLayerColor 子类,它包含一个简单的菜单(恢复、重启和主菜单)。
只要按下暂停按钮,PauseLayer 就会作为子项添加到 GameLayer。
问题: 重新启动游戏/场景可以正常工作:[self restartGame] 从 GameLayer 本身内部。 但是使用以下方法从 PauseLayer 调用相同的方法:[[GameLayer sharedGameLayer] restartGame] 并不能完全用新实例替换 GameLayer 场景;旧场景仍然存在,没有子元素,相同的旧分数等,尽管正在调用 GameLayer 的 dealloc(仅在未使用过渡时)。
代码:
游戏层
static GameLayer *sharedGameLayer;
@implementation GameLayer
- (id)init
// always call "super" init
// Apple recommends to re-assign "self" with the "super's" return value
if(self = [super initWithColor:ccc4(255, 255, 255, 255) width:[CCDirector sharedDirector].winSize.width height:[CCDirector sharedDirector].winSize.height])
NSLog(@"%s", __PRETTY_FUNCTION__);
sharedGameLayer = self;
.
.
+ (GameLayer *)sharedGameLayer
@synchronized(self)
if (sharedGameLayer == nil)
sharedGameLayer = [[self alloc] init];
return sharedGameLayer;
- (void)pauseGame
NSLog(@"%s", __PRETTY_FUNCTION__);
if (![[CCDirector sharedDirector] isPaused])
// Disable the top menu.
self.hud.topMenu.enabled = NO;
// Pause game.
[[CCDirector sharedDirector] pause];
// Pause the background music.
[[SimpleAudioEngine sharedEngine] pauseBackgroundMusic];
// Disable touch detection.
[[CCDirector sharedDirector].touchDispatcher removeDelegate:self];
// Add the Pause Layer.
PauseLayer *pauseLayer = [[PauseLayer alloc] init];
pauseLayer.tag = 2;
pauseLayer.zOrder = 10;
[self addChild:pauseLayer z:10 tag:2];
- (void)restartGame
NSLog(@"%s", __PRETTY_FUNCTION__);
[[NSNotificationCenter defaultCenter] removeObserver:self];
[[CCDirector sharedDirector].touchDispatcher removeAllDelegates];
[self stopAllActions];
[self unscheduleAllSelectors];
[self unscheduleUpdate];
[self removeAllChildrenWithCleanup:YES];
[[CCDirector sharedDirector] replaceScene:[GameLayer scene]];
//[[CCDirector sharedDirector] replaceScene:[CCTransitionFade transitionWithDuration:1.0 scene:[GameLayer scene]]];
- (void)dealloc
NSLog(@"%s", __PRETTY_FUNCTION__);
sharedGameLayer = nil;
@end
暂停层
- (id)init
if (self = [super initWithColor:ccc4(0, 0, 0, 128) width:[CCDirector sharedDirector].winSize.width height:[CCDirector sharedDirector].winSize.height])
// Create a menu.
// Resume button.
CCLabelTTF *resumeLabel = [CCLabelTTF labelWithString:@"Resume" fontName:@"Marker Felt" fontSize:32];
resumeLabel.color = ccc3(240, 240, 240);
CCMenuItemLabel *resumeButton = [CCMenuItemLabel itemWithLabel:resumeLabel block:^(id sender)
[[GameLayer sharedGameLayer] resumeGame];
];
// Restart Game button.
CCLabelTTF *restartLabel = [CCLabelTTF labelWithString:@"Restart" fontName:@"Marker Felt" fontSize:32];
restartLabel.color = ccc3(240, 240, 240);
CCMenuItemLabel *restartButton = [CCMenuItemLabel itemWithLabel:restartLabel block:^(id sender)
[[GameLayer sharedGameLayer] restartGame];
];
// Main Menu button.
CCLabelTTF *mainMenuLabel = [CCLabelTTF labelWithString:@"Main Menu" fontName:@"Marker Felt" fontSize:32];
mainMenuLabel.color = ccc3(240, 240, 240);
CCMenuItemLabel *mainMenuButton = [CCMenuItemLabel itemWithLabel:mainMenuLabel block:^(id sender)
[[GameLayer sharedGameLayer] gotoMainMenu];
];
CCMenu *menu = [CCMenu menuWithItems:resumeButton, restartButton, mainMenuButton, nil];
[menu alignItemsVerticallyWithPadding:10.0];
menu.position = ccp([CCDirector sharedDirector].winSize.width / 2, [CCDirector sharedDirector].winSize.height / 2);
[self addChild:menu];
return self;
编辑: 如果我在 GameLayer 的 init 方法中添加 Pause 层(作为 GameLayer 的子级,并且始终可见),一切都会完美运行......这有点奇怪。 任何输入都受到高度赞赏。 提前致谢!
【问题讨论】:
【参考方案1】:从线
static GameLayer *sharedGameLayer;
您需要在@implementation class 行之前编写此行以使其不是类成员变量。在 sharedGameLayer 方法中,您应该将其更改为
+ (GameLayer *)sharedGameLayer
@synchronized(self)
if (sharedGameLayer == nil)
sharedGameLayer = [[self alloc] init];
return sharedGameLayer;
而且,当你定义游戏层类时,你不会调用 init 方法,但你应该调用 sharedGameLayer 来使游戏层类成为单例。
【讨论】:
static GameLayer *sharedGameLayer; 确实已经在@Implementation 指令之外,我已经在代码中更正了。我还按照您的建议修改了 + (GameLayer *)sharedGameLayer 方法,但不幸的是行为仍然相同。 编辑:如果我在 GameLayer 的 init 方法中添加 Pause 层(作为 GameLayer 的子级,并且始终可见),一切正常......这有点奇怪。【参考方案2】:我不建议在 CCLayers 上使用单例模式,但是您是否覆盖/编辑了 CCScene 包装器,使其不会调用 init。
例如
+(id)scene
CCScene* scene = [CCScene node];
[scene addChild:[GameLayer sharedGameLayer]];
return scene;
然后当你打电话时
[[CCDirector sharedDirector] replaceScene:[GameLayer scene]];
记得重启游戏
[[GameLayer sharedInstance] restart];
或者您可以在场景包装器方法中执行此操作。
希望我明白你的意思。
至少这会让你不必一直为游戏层重新分配空间嘿嘿..
【讨论】:
[scene addChild:[GameLayer sharedGameLayer]]; 给出断言失败。此外,restart 方法是实际替换场景的方法。无论如何,我已经几乎解决了一些问题,所以我先编辑我的问题。跨度> 【参考方案3】:问题的罪魁祸首是在使用 CCDirector 的 Pause 方法暂停游戏后调用 CCDirector 的 ReplaceScene: 方法。 我所做的是实现我自己的“暂停”功能主要使用:[self pauseSchedulerAndActions];,在我的例子中也是:[[self.spidersBatchNode children] makeObjectsPerformSelector:@selector(pauseSchedulerAndActions)];对于 spriteBatchNode 内的所有孩子。出现了另一个问题,我将提出另一个问题。感谢所有回复。
【讨论】:
这是新问题的 URL,以防万一有人想跟进:link以上是关于从另一层重新启动游戏/场景的主要内容,如果未能解决你的问题,请参考以下文章
从 cron 重新启动弹性 beanstalk 应用程序服务器