我有一个简单的游戏,从屏幕的顶部到底部“下雨”。
我正在使用SpriteKit,我希望这些石头能够随着时间的推移而增加速度,就像1级2级3级一样。那么最大速度应该很容易实现。
我对石头的速度有一个变速“速度”。
我想我可以使用一个计时器,在5秒速度= 2之后,10秒速度= 5之后,依此类推,但我不确定如何实现它。
编辑:
我正用这个移动我的石头:-(void) moveStones{
SKAction *actionMove = [SKAction moveByX:0 y:-5 duration:0.25];
for(SKSpriteNode *stone in self.stones)
{
[stone runAction:actionMove];
}
}
在我的viewDidLoad中,我有计时器:
moveStones = [NSTimer scheduledTimerWithTimeInterval:0.05 target:self selector:@selector(moveStones) userInfo:nil repeats:YES];
如果计时器不尊重视图,有没有办法在没有该计时器的情况下移动它们?
答案 0 :(得分:2)
如果你是通过物理移动石头,那么在石头产生之后你应该施加更强的冲动/力(基于当前水平)如果你用动作移动它们,那么改变动作速度,或者降低moveDuration 。如果您通过在update:方法中更改其位置来移动石头,则更改指示精灵在每次更新调用中应移动多少点的值。
要实现基于时间的操作(如产生宝石)或决定何时更改生成节点的速度,您应该使用SKAction或update:方法及其传递的名为currentTime
的参数。在SpriteKit中使用NSTimer
可能会导致问题,因为NSTimer不尊重视图,场景或节点的暂停状态,因此最好避免使用它。
以下是有关如何使用SKAction
执行所需操作的示例。在此示例中,您可以看到如何:
<强> GameScene.h 强>
#import "GameScene.h"
@interface GameScene()
@property (nonatomic, assign) NSInteger counter;
@property (nonatomic, assign) NSInteger level;
@property (nonatomic, strong) SKLabelNode *debug;
@end
@implementation GameScene
// Here we set initial values of counter and level. Debug label is created here as well.
-(void)didMoveToView:(SKView *)view {
self.counter = 0;
self.level = 1;
self.backgroundColor = [SKColor grayColor];
self.debug = [SKLabelNode labelNodeWithFontNamed:@"ArialMT"];
self.debug.fontColor = [SKColor purpleColor];
self.debug.fontSize = 30.0f;
self.debug.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame));
self.debug.text = [NSString stringWithFormat:@"Counter : [ %ld ], Level [ %ld ]", (long)self.counter,(long)self.level];
[self addChild:self.debug];
}
//Method to start a timer. SKAction is used here to track a time passed and to maintain current level
-(void)startTimer{
__weak typeof (self) weakSelf = self; //make a weak reference to scene to avoid retain cycle
SKAction *block = [SKAction runBlock:^{
weakSelf.counter++;
//Maintaining level
if(weakSelf.counter < 5){
//level 1
weakSelf.level = 1;
}else if(weakSelf.counter >=5 && weakSelf.counter <10){
//level 2
weakSelf.level = 2;
}else{
//level 3
weakSelf.level = 3;
}
weakSelf.debug.text =
[NSString stringWithFormat:@"Counter : [ %ld ], Level [ %ld ]", (long)weakSelf.counter,(long)weakSelf.level];
}];
[self runAction:[SKAction repeatActionForever:[SKAction sequence:@[[SKAction waitForDuration:1], block]]] withKey:@"counting"];
}
//Method for stopping timer and reseting everything to default state.
-(void)stopTimer{
if([self actionForKey:@"counting"]){
[self removeActionForKey:@"counting"];
}
self.counter = 0.0f;
self.level = 1;
self.debug.text =
[NSString stringWithFormat:@"Counter : [ %ld ], Level [ %ld ]", (long)self.counter,(long)self.level];
}
//Get current speed based on time passed (based on counter variable)
-(CGFloat)getCurrentSpeed{
if(self.counter < 5){
//level 1
return 1.0f;
}else if(self.counter >=5 && self.counter <10){
//level 2
return 2.0f;
}else{
//level 3
return 3.0f;
}
}
//Method which stop generating stones, called in touchesBegan
-(void)stopGeneratingStones{
if([self actionForKey:@"spawning"]){
[self removeActionForKey:@"spawning"];
}
}
//You can use this useful method to generate random float between two numbers
- (CGFloat)randomFloatBetween:(CGFloat)smallNumber and:(CGFloat)bigNumber {
CGFloat diff = bigNumber - smallNumber;
return (((CGFloat) (arc4random() % ((unsigned)RAND_MAX + 1)) / RAND_MAX) * diff) + smallNumber;
}
//Method for generating stones, you run this method when you want to start spawning nodes (eg. didMoveToView or when some button is clicked)
-(void)generateStones{
SKAction *delay = [SKAction waitForDuration:2 withRange:0.5]; //randomizing delay time
__weak typeof (self) weakSelf = self; //make a weak reference to scene to avoid retain cycle
SKAction *block = [SKAction runBlock:^{
SKSpriteNode *stone = [weakSelf spawnStoneWithSpeed:[weakSelf getCurrentSpeed]];
stone.zPosition = 20;
[weakSelf addChild:stone];
}];
[self runAction:[SKAction repeatActionForever:[SKAction sequence:@[delay, block]]] withKey:@"spawning"];
}
//Returns stone with moving action added. Inside, you set standard things, like size, texture, physicsbody, name and position of a stone
-(SKSpriteNode*)spawnStoneWithSpeed:(CGFloat)stoneSpeed{
CGSize stoneSize = CGSizeMake(30,30); //you can randomize size here
CGPoint stonePosition = CGPointMake( [self randomFloatBetween:0.0f and:self.frame.size.width], CGRectGetMaxY(self.frame)); //you can randomize position here
SKSpriteNode *stone = [SKSpriteNode spriteNodeWithColor:[SKColor greenColor] size:stoneSize];
stone.name = @"stone"; //this helps if you want to enumerate all stones by name later on in your game
stone.position = stonePosition;
SKAction *move = [SKAction moveByX:0 y:-200 duration:3.25];
//one way to change speed
move.speed = stoneSpeed;
SKAction *moveAndRemove = [SKAction sequence:@[move, [SKAction removeFromParent]]];
[stone runAction:moveAndRemove withKey:@"moving"]; //access this key if you want to stop movement
return stone;
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
/* Called when a touch begins */
//just a simple way to start and stop a game
if(![self actionForKey:@"counting"]){
[self startTimer];
[self generateStones];
}else{
[self stopTimer];
[self stopGeneratingStones];
}
}
@end
结果如下:
现在由您决定如何设定速度。你可以玩那个。
如果你想跳过某些部分,或者你不知道在哪里看,那么所有内容的核心都是generateStones
方法。这就是你如何通过使用SKActions产生时间延迟的石头。另一个重要的方法是spawnStoneWithSpeed:
,您可以在其中看到如何以动作的速度进行操作。
正如我所说,另一种影响节点移动速度的方法是改变方法moveByX: duration:
的持续时间参数
希望这有帮助!