更新时间:2023-02-01 20:13:14
快捷方式
您可以使用didSet属性观察器根据当前得分来更改游戏速度:
You can use didSet property observer to change the game speed based on the current score:
import SpriteKit
class GameScene: SKScene {
var score:Int = 0 {
didSet{
if score % 10 == 0 {
gameSpeed += 0.5
}
label.text = "Score : \(score), Speed : \(gameSpeed)"
}
}
var gameSpeed:Double = 1.0
var label:SKLabelNode = SKLabelNode(fontNamed: "ArialMT")
override func didMoveToView(view: SKView) {
/* Setup your scene here */
label.text = "Score : \(score), Speed : \(gameSpeed)"
label.position = CGPoint(x: CGRectGetMidX(frame), y: CGRectGetMidX(frame))
label.fontSize = 18
addChild(label)
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
score++
}
}
从文档中
didSet在存储新值后立即被调用.
didSet is called immediately after the new value is stored.
因此,在设置新分数之后,您应该立即更新gameSpeed
变量.
So, immediately after the new score is set, you should update the gameSpeed
variable.
Objective-C方式
在Objective-C中,没有这样的东西可以提供与Swift的didSet和willSet属性观察器完全相同的行为.但是还有其他方法,例如,您可以覆盖乐谱的设置器,例如:
In Objective-C there is no such a thing which can provide the exact same behaviour like Swift's didSet and willSet property observers. But there are another ways, for example you can override a score's setter, like this:
#import "GameScene.h"
@interface GameScene()
@property(nonatomic, strong) SKLabelNode *label;
@property(nonatomic, assign) NSUInteger score;
@property(nonatomic, assign) double gameSpeed;
@end
@implementation GameScene
-(instancetype)initWithCoder:(NSCoder *)aDecoder{
NSLog(@"Scene's initWithSize: called");
if(self = [super initWithCoder:aDecoder]){
/*
Instance variables in Obj-C should be used only while initialization, deallocation or when overriding accessor methods.
Otherwise, you should use accessor methods (eg. through properties).
*/
_gameSpeed = 1;
_score = 0;
NSLog(@"Variables initialized successfully");
}
return self;
}
-(void)didMoveToView:(SKView *)view {
self.label = [SKLabelNode labelNodeWithFontNamed:@"ArialMT"];
self.label.fontSize = 18;
self.label.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame));
self.label.text = [NSString stringWithFormat:@"Score : %lu, Speed %f", self.score, self.gameSpeed];
[self addChild:self.label];
}
//Overriding an actual setter, so when score is changed, the game speed will change accordingly
-(void)setScore:(NSUInteger)score{
/*
Make sure that you don't do assigment like this, self.score = score, but rather _score = score
because self.score = somevalue, is an actual setter call - [self setScore:score]; and it will create an infinite recursive call.
*/
_score = score;
if(_score % 10 == 0){
self.gameSpeed += 0.5;
}
// Here, it is safe to to write something like self.score, because you call the getter.
self.label.text = [NSString stringWithFormat:@"Score : %lu, Speed %f", self.score, self.gameSpeed];
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
self.score++;
}
@end
或者,我想您可以使用 KVO ,但由于简单起见,您可以覆盖设置器.或者,也许您可以制作一个自定义方法来增加得分,处理gameSpeed的更新逻辑并在必要时更新速度:
Or, I guess, you can do the same using KVO, but for your example because of simplicity, you can just override a setter. Or maybe you could just make a custom method which will increase the score, handle the gameSpeed's updating logic, and update the speed if necessary:
//Whenever the player scores, you will do this
[self updateScore: score];
因此,您将有一个附加的方法定义,与此相比,玩家得分时必须调用该方法(假设分数的设置器被覆盖):
So, you will have an additional method definition, which must be called when player scores, in compare to this (assuming that score's setter is overridden):
self.score = someScore;
这完全取决于您.
希望这是有道理的,对您有所帮助!
Hope this make sense and it helps!
我将initWithSize:
更改为initWithCoder
,因为从sks加载场景时未调用initWithSize
,这可能是您的操作方式,因为实际上是在Xcode 7中加载了场景默认情况下,该文件来自.sks文件.
I've changed the initWithSize:
to initWithCoder
, because initWithSize
is not called when the scene is loaded from sks, which is probably how you are doing it, due to fact that in Xcode 7 scene is loaded by default from .sks file.