如何在每增加 50 点后加速 Sprite Kit 游戏
How to speed up a Sprite Kit game after every additional 50 points
我正在用 Sprite Kit 制作一个 2D 游戏,我需要添加一个方法来在每 50 点后加速游戏。
我想出了一个方法,可以根据需要增加速度,但是我必须在更新方法中每增加50点复制、粘贴和调整一个if语句。
我的解决方案的另一个问题是,我必须在加速后立即增加我的积分,因为如果不是这样,游戏就会完全加速,尽管我不知道为什么。
到目前为止,这是我的解决方案:
// inside the update method
// points are added when an enemy is destroyed
// pointSpeed is the float variable that is used to change positions
if (points == 4) {
pointSpeed++;
points++;
}
if (points == 8) {
pointSpeed++;
points++;
}
if (points == 12) {
pointSpeed++;
points++;
}
我想实现此功能,而不必被迫手动执行所有增量,并且游戏不会在没有积分增量的情况下加速。
如果您想定期更新速度,可以使用取模运算符 - 除以您的间隔后取余数 - 如果等于零,则采取行动。
你发现游戏完全加速的原因是下一次通过更新功能时,它仍然处于正确的点级别,并且它只是增加了速度 - 如果你准备好增加,你可以添加另一个变量来跟踪
// as part of class declaration
var bReadyForIncrement : Bool = true
let pointIncrement : Int = 4 // or whatever you need
// inside the update method
// points are added when an enemy is destroyed
// pointSpeed is the float variable that is used to change positions
if (points % 4)
{
if bReadyForIncrement
{
pointSpeed++;
bReadyForIncrement = false // set this to true wherever you add points
}
}
Swift 方式
你可以使用didSet 属性观察者根据当前分数改变游戏速度:
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 is called immediately after the new value is stored.
因此,在设置新分数后,您应该立即更新 gameSpeed
变量。
Objective-C 方式
在 Objective-C 中没有这样的东西可以提供与 Swift 的 didSet 和 willSet 属性 观察者完全相同的行为。但还有其他方法,例如您可以覆盖分数的 setter,如下所示:
#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 执行相同的操作,但对于您的示例,由于简单起见,您可以只覆盖 setter。或者,也许您可以创建一个自定义方法来增加分数,处理 gameSpeed 的更新逻辑,并在必要时更新速度:
//Whenever the player scores, you will do this
[self updateScore: score];
所以,你将有一个额外的方法定义,当玩家得分时必须调用它,与此相比(假设得分的 setter 被覆盖):
self.score = someScore;
这完全取决于你。
希望这说得通并且对您有所帮助!
编辑:
我已经将 initWithSize:
更改为 initWithCoder
,因为从 sks 加载场景时不会调用 initWithSize
,这可能是你正在做的,由于事实上,在 Xcode 中,默认情况下从 .sks 文件加载 7 个场景。
我正在用 Sprite Kit 制作一个 2D 游戏,我需要添加一个方法来在每 50 点后加速游戏。
我想出了一个方法,可以根据需要增加速度,但是我必须在更新方法中每增加50点复制、粘贴和调整一个if语句。
我的解决方案的另一个问题是,我必须在加速后立即增加我的积分,因为如果不是这样,游戏就会完全加速,尽管我不知道为什么。
到目前为止,这是我的解决方案:
// inside the update method
// points are added when an enemy is destroyed
// pointSpeed is the float variable that is used to change positions
if (points == 4) {
pointSpeed++;
points++;
}
if (points == 8) {
pointSpeed++;
points++;
}
if (points == 12) {
pointSpeed++;
points++;
}
我想实现此功能,而不必被迫手动执行所有增量,并且游戏不会在没有积分增量的情况下加速。
如果您想定期更新速度,可以使用取模运算符 - 除以您的间隔后取余数 - 如果等于零,则采取行动。 你发现游戏完全加速的原因是下一次通过更新功能时,它仍然处于正确的点级别,并且它只是增加了速度 - 如果你准备好增加,你可以添加另一个变量来跟踪
// as part of class declaration
var bReadyForIncrement : Bool = true
let pointIncrement : Int = 4 // or whatever you need
// inside the update method
// points are added when an enemy is destroyed
// pointSpeed is the float variable that is used to change positions
if (points % 4)
{
if bReadyForIncrement
{
pointSpeed++;
bReadyForIncrement = false // set this to true wherever you add points
}
}
Swift 方式
你可以使用didSet 属性观察者根据当前分数改变游戏速度:
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 is called immediately after the new value is stored.
因此,在设置新分数后,您应该立即更新 gameSpeed
变量。
Objective-C 方式
在 Objective-C 中没有这样的东西可以提供与 Swift 的 didSet 和 willSet 属性 观察者完全相同的行为。但还有其他方法,例如您可以覆盖分数的 setter,如下所示:
#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 执行相同的操作,但对于您的示例,由于简单起见,您可以只覆盖 setter。或者,也许您可以创建一个自定义方法来增加分数,处理 gameSpeed 的更新逻辑,并在必要时更新速度:
//Whenever the player scores, you will do this
[self updateScore: score];
所以,你将有一个额外的方法定义,当玩家得分时必须调用它,与此相比(假设得分的 setter 被覆盖):
self.score = someScore;
这完全取决于你。
希望这说得通并且对您有所帮助!
编辑:
我已经将 initWithSize:
更改为 initWithCoder
,因为从 sks 加载场景时不会调用 initWithSize
,这可能是你正在做的,由于事实上,在 Xcode 中,默认情况下从 .sks 文件加载 7 个场景。