gpt4 book ai didi

ios - 重新分配SKScene委托(delegate)协议(protocol)

转载 作者:行者123 更新时间:2023-11-29 02:29:20 26 4
gpt4 key购买 nike

因此,我在场景中创建了一个委托协议和相应的属性。在保存所有场景的视图控制器中,我将场景委托设置为其自身,以便可以在菜单中调用全屏广告(来自视图控制器),该菜单是第一个被调用的游戏场景。我可以调用该方法,效果很好。但是,当我过渡到关卡场景之后,又回到菜单场景,调用我的方法来显示全屏广告就什么都没有。我假设是因为被委派给自己的委托已经丢失。如何在游戏场景中将委托人重新设置回自己?这就是我在View控制器中执行此操作的方式

myScene = [GameScene unarchiveFromFile:@"GameScene"];
((GameScene *)myScene).mySceneDelegate = self; // i need to be able to do this within the scene
myScene.scaleMode = SKSceneScaleModeResizeFill;

// Present the scene.
[skView presentScene:myScene];


我如何从菜单场景中调用VC中的fullScreen方法...

[self.mySceneDelegate showFullScreen:self];


...所以在我的代码中,当我从LevelOne场景过渡时,我尝试使用以下代码重新分配委托,但没有任何反应

-(void)goBackToMenu{

GameScene *newscene = [GameScene sceneWithSize:self.size];
[self.view presentScene:newscene transition:[SKTransition doorsCloseHorizontalWithDuration:1]];
((GameScene *)newscene).mySceneDelegate = self;
}


我也尝试将属性属性设置为“强”而不是“弱”,也没有运气

**********************所有代码************************** ************

更多代码..我的Viewcontroller.h

@protocol TCAMySceneDelegate;

@interface GameViewController : UIViewController<TCAMySceneDelegate>

@property(nonatomic, weak) id<TCAMySceneDelegate> mySceneDelegate;

@end


我的视图控制器

- (void)viewDidLoad
{
[super viewDidLoad];

SKView * skView = (SKView *)self.view;

myScene = [GameScene unarchiveFromFile:@"GameScene"];

((GameScene *)myScene).mySceneDelegate = self;

// Present the scene.
[skView presentScene:myScene];
}


-(void)showFullScreen:(GameScene *)gameScene{

NSLog(@"Show Full Screen");

[revmobFS loadWithSuccessHandler:^(RevMobFullscreen *fs) {
[fs showAd];
NSLog(@"Ad loaded");
} andLoadFailHandler:^(RevMobFullscreen *fs, NSError *error) {
NSLog(@"Ad error: %@",error);
} onClickHandler:^{
NSLog(@"Ad clicked");
} onCloseHandler:^{
NSLog(@"Ad closed");
}];
[RevMobAds startSessionWithAppID:@"547251235f2a043608a66f1a"
withSuccessHandler:^{
NSLog(@"Session started with block");
// Here, you should call the desired ad unit
revmobFS = [[RevMobAds session] fullscreen];
[revmobFS showAd];
// [RevMobAds session].testingMode = RevMobAdsTestingModeWithAds;
revmobFS.delegate = self;
[revmobFS loadAd];

} andFailHandler:^(NSError *error) {
NSLog(@"Session failed to start with block");
}];
}


我的游戏scene.h文件。

@protocol TCAMySceneDelegate;

@interface GameScene : SKScene

@property (nonatomic, weak) id<TCAMySceneDelegate> mySceneDelegate;

@end

@protocol TCAMySceneDelegate <NSObject>

-(void)showFullScreen:(GameScene *)gameScene;
@end


我的游戏scene.m文件..

-(void)didMoveToView:(SKView *)view {

//Show Ad

[self.mySceneDelegate showFullScreen:self];

}


现在,上面的showFullScreen:被调用了,但是当第一次显示gameScene(我的游戏菜单)时是在线的..在过渡到游戏中的其他场景(例如关卡)之后,回到我的菜单(gamescene)时,它从未被调用过。希望现在更清楚

我如何从游戏场景切换到另一个场景

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
/* Called when a touch begins */
UITouch *touch = [touches anyObject];
CGPoint location = [touch locationInNode:self];
SKNode *node = [self nodeAtPoint:location];
NSLog(@"Level Selected: %@", node.name);
int x = [node.name intValue];

switch (x) {
case 1:{
LevelOne *newscene = [LevelOne sceneWithSize:self.size];
[self.view presentScene:newscene transition:[SKTransition doorsOpenVerticalWithDuration:1]];
break;
}
case 2:{

LevelTwo *newscene = [LevelTwo sceneWithSize:self.size];
[self.view presentScene:newscene transition:[SKTransition doorsOpenVerticalWithDuration:1]];
}
break;
}
case 3:{
LevelThree *newscene = [LevelThree sceneWithSize:self.size];
[self.view presentScene:newscene transition:[SKTransition doorsOpenVerticalWithDuration:1]];
}
break;
}
//..........

default:
break;
}
}


LevelOne.h代码...

#import <SpriteKit/SpriteKit.h>
#import "DrawCanvas.h"
#import "GameScene.h"

@interface LevelOne : SKScene<SKPhysicsContactDelegate>

@end

最佳答案

就个人而言,我发现您的描述以及所发布的代码有些缺乏细节,也有些混乱。提供代码时,如果您提供更多详细信息,则可能会获得更好的/快速帮助。例如,goBackToMenu属于哪个文件?

如何/在什么情况下

[self.mySceneDelegate showFullScreen:self];


叫?我认为这是从GameScene中的某个触发点开始的。 showFullScreen的方法签名是什么?

并且由于您没有指出mySceneDelegate是什么类型,因此使读者在猜测您的意思。

因此,尝试解读您的要求...

假设您有一些名为GameSceneDelegate的委托。我还要假设您已经知道SKSceneDelegate存在,并且已经在使用它,但是只是没有发布该代码或不需要使用它。

您的GameViewController将其接口定义为:

>

而且您的GameScene将具有如下定义的属性:

@property (nonatomic, weak) id<GameSceneDelegate> mySceneDelegate;


请注意,您应该在此处使用弱。因为如果您的GameViewController曾经对GameScene有很强的引用,那么您就已经创建了一个保留周期。

您可以选择何时设置mySceneDelegate。如果我知道必须定义一个委托,那么我经常要做的就是将其添加为初始化程序的参数。这样,很明显它必须有一个委托。因此,假设您正在使用类方法来生成实例,则可以执行以下操作:

@interface GameScene : SKScene

@property (nonatomic, weak) id<GameSceneDelegate> mySceneDelegate;

+ (instancetype)unarchiveFromFile:(NSString *)file mySceneDelegate:(id<GameSceneDelegate>)mySceneDelegate;

+ (instancetype)sceneWithSize:(CGSize)size mySceneDelegate:(id<GameSceneDelegate>)mySceneDelegate;

@end


这些方法看起来像:

+ (instancetype)unarchiveFromFile:(NSString *)file mySceneDelegate:(id<GameSceneDelegate>)mySceneDelegate
{
GameScene *scene = [super unarchiveFromFile:file];

scene.mySceneDelegate = mySceneDelegate;

return scene;
}

+ (instancetype)sceneWithSize:(CGSize)size mySceneDelegate:(id<GameSceneDelegate>)mySceneDelegate
{
GameScene *scene = [super sceneWithSize:size];

scene.mySceneDelegate = mySceneDelegate;

return scene;
}


请注意,要使其工作,您需要在GameViewController.h中定义它(或根据需要为类别定义一个单独的文件)

@interface SKScene (Unarchive)

+ (instancetype)unarchiveFromFile:(NSString *)file;

@end


另一种方法是在创建场景实例后立即设置mySceneDelegate。

实际上,如果您正在执行此操作,则它应该起作用,并且您的代表应保持原样。 FWIW,我实际上是在游戏中这样做。所以我知道它有效。

好的,这就是您所疑惑的地方。您指示该代表“丢失”。委托“丢失”的唯一方法是有人明确将其设置为nil。或者我想的另一种可能性是您的GameScene正在被释放,而您却没有意识到。

我将设置两件事来帮助对其进行调试。

在GameScene中添加

- (void)dealloc
{
NSLog(@"I'm being dealloc'd");
}

- (void)setMySceneDelegate:(id<GameSceneDelegate>)mySceneDelegate
{
_mySceneDelegate = mySceneDelegate;

NSLog(@"Setting mySceneDelegate");
}


因此,现在您可以尝试确定“丢失”的位置。如果其中任何一个在丢失时打印到控制台,只需在这些方法中设置一个断点即可查看谁在调用它。

另一条也有帮助的信息是


您是什么意思给自己分配代表?我也不知道
那意味着。
您提到您假设代理人丢失了。为什么?你有
证据还是纯粹是猜测?


如果您可以提供一些答案和更详细的信息,我们可能可以找出问题所在。

好的,现在查看您的代码,我认为您的问题在GameScene.m中:

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
/* Called when a touch begins */
UITouch *touch = [touches anyObject];
CGPoint location = [touch locationInNode:self];
SKNode *node = [self nodeAtPoint:location];
NSLog(@"Level Selected: %@", node.name);
int x = [node.name intValue];

switch (x) {
case 1:{
LevelOne *newscene = [LevelOne sceneWithSize:self.size];
newScene.mySceneDelegate = self.mySceneDelegate;
// Or, if you can make it work, newscene = [LevelOne sceneWithSize:size mySceneDelegate:self.mySceneDelegate;
[self.view presentScene:newscene transition:[SKTransition doorsOpenVerticalWithDuration:1]];
break;
}
case 2:{

LevelTwo *newscene = [LevelTwo sceneWithSize:self.size];
newScene.mySceneDelegate = self.mySceneDelegate;
// Or, if you can make it work, newscene = [LevelOne sceneWithSize:size mySceneDelegate:self.mySceneDelegate;
[self.view presentScene:newscene transition:[SKTransition doorsOpenVerticalWithDuration:1]];
}
break;
}
case 3:{
LevelThree *newscene = [LevelThree sceneWithSize:self.size];
newScene.mySceneDelegate = self.mySceneDelegate;
// Or, if you can make it work, newscene = [LevelOne sceneWithSize:size mySceneDelegate:self.mySceneDelegate;
[self.view presentScene:newscene transition:[SKTransition doorsOpenVerticalWithDuration:1]];
}
break;
}
//..........

default:
break;
}
}


我在这里所做的就是将新场景的mySceneDelegate分配给正在使用的现有场景。

您可以清理此代码以提高可读性。

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
/* Called when a touch begins */
UITouch *touch = [touches anyObject];
CGPoint location = [touch locationInNode:self];
SKNode *node = [self nodeAtPoint:location];
NSLog(@"Level Selected: %@", node.name);
int x = [node.name intValue];
GameScene *newScene = nil;

switch (x) {
case 1:
newScene = [LevelOne sceneWithSize:self.size];
// Or, if you can make it work, newScene = [LevelOne sceneWithSize:size mySceneDelegate:self.mySceneDelegate;
break;
case 2:
newScene = [LevelTwo sceneWithSize:self.size];
// Or, if you can make it work, newScene = [LevelTwo sceneWithSize:size mySceneDelegate:self.mySceneDelegate;
break;
case 3:
newScene = [LevelThree sceneWithSize:self.size];
// Or, if you can make it work, newScene = [LevelThree sceneWithSize:size mySceneDelegate:self.mySceneDelegate;
break;

// other cases..........

default:
break;
}
if (newScene) {
newScene.mySceneDelegate = self.mySceneDelegate;
[self.view presentScene:newScene transition:[SKTransition doorsOpenVerticalWithDuration:1]];
}
}


对于您的级别,您需要执行以下操作:

#import <SpriteKit/SpriteKit.h>
#import "DrawCanvas.h"
#import "GameScene.h"

@interface LevelXYZ : GameScene<SKPhysicsContactDelegate>

@end


其中XYZ是水平(例如1)。通过这样做,您将从GameScene继承mySceneDelegate。如果出于某些原因您坚持认为关卡场景不是从GameScene继承的,则添加一个包含委托的基类。因此,将类似于:

@interface MyBaseScene : SKScene

@property(nonatomic, weak) id<TCAMySceneDelegate> mySceneDelegate;

@end


然后GameScene将是这样的:

@interface GameScene : MyBaseScene


而您的关卡场景是

@interface LevelXYZ : MyBaseScene<SKPhysicsContactDelegate>


注意我做了几件事。


将新闻场景更改为newScene。在iOS中,通常使用大小写。
您正在为mySceneDelegate做它。一致性是关键。
最初将newScene声明为nil并根据需要分配。然后,在切换结束时,如果存在newScene,则分配委托并
当下。这样,您只需要在一个地方进行即可。它使生活
更轻松。例如,如果您想更改每个
一,那又如何?您必须更改大小写。注意有一个
失败的原因如果您希望在水平上有特殊的时长,
那就行不通了。但是您可以通过更改
持续时间和过渡类型变量。


顺便说一句,我强烈建议不要让您的场景类包含进行实际过渡的代码。我要么让它调用一个委托来做到这一点,要么找到另一种方式(例如使用需要更改场景的通知)。例如,在我当前的游戏中,我让视图控制器成为所有场景更改的控制器。这样做的好处是您还可以从其他外力调用场景过渡(而不必让场景成为管理场景的过渡)。

最后,您希望可以看到,发现问题的唯一方法是提供正确的代码。我会同意很难知道要显示什么代码,因为如果代码太多,那么人们可能不会阅读它。这是一条好线,但值得深思。

关于ios - 重新分配SKScene委托(delegate)协议(protocol),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27110788/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com