Spritekit框架的初级使用(仿Magic Shatter)

Spritekit框架

Spritekit框架是iOS7.0之后,由苹果官方引入的一款游戏框架,现在我们就来看看他与UIKIT框架的不同。

SKSpriteNode(精灵)

SpriteKit 框架下多了几个大类,其一便是SKSpriteNode,也就是游戏精灵,它可以帮助我们实现很多动画,逻辑运算等 。
SKSpriteNode的初始化方法。

<php>
SKSpriteNode *node = [[SKSpriteNode alloc] initWithColor[UIColor redColor] size:CGSizeMake(0, 0, 10, 10)];
[self addChild:node];
</php>

SKAction

SKAction,说句老实话,我也不太清楚这个类,但是我知道,这个类的作用就是让精灵能够动起来,一切与精灵有关的运动,都是由它产生的。
它的初始化有许多的类方法,你可以根据自己不同的需求来做不同的初始化方法。

我对于SpriteKit框架的认识,大概就是这样的,需要更加深入地了解,请点击:(http://www.cocoachina.com/industry/20130930/7087.html

仿消灭星星(纯代码开发)

创建一个新的xcode工程,选择Single View Application
选择这个
选择Objective-C语言,名字自己取。
好了,现在正式开始上代码了:

导入游戏框架

进去编辑界面后,选择General,一直拉到最下面,点击Linked Frameworks Libraries下的加号按钮
添加游戏框架
在搜索框内输入sprite kit,选择spritekit.framework后,点击add。
添加游戏框架2

现在创建一个新的类,继承于SKSence;

创建继承SKSence的新类型

创建游戏界面

在GameScene.m中,创建私有属性。

@interface GameScene ()
// 属性
@property (nonatomic, assign)CGFloat squareLength;//游戏方块的长度
@property (nonatomic, assign)CGPoint backgroundOrigin;//背景方块的长度

@property (nonatomic, strong)NSMutableArray *squareArray;//游戏方块的数组
@property (nonatomic, strong)NSMutableArray *findArray;//需要销毁的方块数组

@property (nonatomic, strong)dispatch_queue_t dealQueue;//创建一个子线程

// 自定义用户界面
- (void)initializeDataSource;/**< 初始化数据源 */
- (void)initializeUserInterface;/**< 初始化用户界面 */

@end

@implementation GameScene
- (instancetype)initWithSize:(CGSize)size {
    if (self = [super initWithSize:size]) {
        // 初始化数据源一定要在初始化用户界面之前
        [self initializeDataSource];
        [self initializeUserInterface];
    }
    return self;
}

- (void)initializeDataSource {
_squareArray = [[NSMutableArray alloc] init];
_findArray = [[NSMutableArray alloc] init];
_dealQueue = dispatch_queue_create("com.tallmantech.colorful", DISPATCH_QUEUE_SERIAL);
}

- (void)initializeUserInterface {

}

现在暂时先回到viewController.m中,导入游戏框架,和我们刚刚创建的新类;

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

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    SKView *view = [[SKView alloc] initWithFrame:self.view.bounds];
    self.view = view;

    GameScene *scene = [[GameScene alloc] initWithSize:view.bounds.size];
    scene.backgroundColor = [UIColor orangeColor];
    [view presentScene:scene];
}

@end

这时候运行出来的情况是这样的一个情况:
运行结果1
剩下的步骤吗,就跟viewController.m没有太多的关系了,点入GameScene.m,我们开始添加背景方块和游戏方块。

-(void)addBackSquare {
    // 获取游戏屏幕的长宽
    CGFloat width = self.size.width;

    // 设置游戏区域的长宽和起始点
    _squareLength = width / 8;
    _backgroundOrigin = CGPointMake(0, 0);

    // 挂载背景方格
    SKSpriteNode *node;
    for (NSInteger i = 0; i < 11; i ++) {
        for (NSInteger j = 0; j < 8; j ++) {
            node = [[SKSpriteNode alloc] initWithColor:[UIColor whiteColor] size:CGSizeMake(_squareLength, _squareLength)];
            // 设置布局的位置
            CGFloat positionX = _backgroundOrigin.x + j * _squareLength + _squareLength / 2;
            CGFloat positionY = _backgroundOrigin.y + i * _squareLength + _squareLength / 2;
            node.position = CGPointMake(positionX, positionY);

            // 将node的信息存入userdata中
            node.userData = [NSMutableDictionary dictionaryWithObjectsAndKeys:@"backSquare", @"nodeType", [NSValue valueWithCGPoint:CGPointMake(positionX, positionY)],@"position", nil];
            node.name = @"backSquare";
            [self addChild:node];
        }
    }
}

在初始化用户界面的方法中调用addBackSquare这个方法,运行之后的样式:
运行结果2
现在我们再把游戏的方块也添加上去:

// 添加游戏方块
-(void)addSquare {
    NSArray *countArray = @[@4,@5,@5,@5,@4];

    // 计算添加彩色方块的长度
    CGFloat colorSquareLength = _squareLength - 5;
    NSInteger count = arc4random_uniform(5);
    NSNumber *currentCount = countArray[count];
    NSInteger integer = [currentCount integerValue];
    // 随机取数
    int index;
    SKSpriteNode *node;

    for (NSInteger i = 0; i < 11; i ++) {
        for (NSInteger j = 0; j < 8; j ++) {
            index = arc4random() % integer;
            switch (index) {
                case 0:
                    node = [[SKSpriteNode alloc] initWithColor:[UIColor yellowColor] size:CGSizeMake(colorSquareLength, colorSquareLength)];
                    break;
                case 1:
                    node = [[SKSpriteNode alloc] initWithColor:[UIColor blueColor] size:CGSizeMake(colorSquareLength, colorSquareLength)];
                    break;
                case 2:
                    node = [[SKSpriteNode alloc] initWithColor:[UIColor orangeColor] size:CGSizeMake(colorSquareLength, colorSquareLength)];
                    break;
                case 3:
                    node = [[SKSpriteNode alloc] initWithColor:[UIColor redColor] size:CGSizeMake(colorSquareLength, colorSquareLength)];
                    break;
                case 4:
                    node = [[SKSpriteNode alloc] initWithColor:[UIColor lightGrayColor] size:CGSizeMake(colorSquareLength, colorSquareLength)];
                    break;
                default:
                    break;
            }

            // 指定节点的位置
            CGFloat positionX = _backgroundOrigin.x + _squareLength * j + _squareLength / 2;
            CGFloat positionY = _backgroundOrigin.y + _squareLength * i + _squareLength / 2;
            node.position = CGPointMake(positionX, positionY);

            // 将node的信息存入userdata中
            node.userData = [NSMutableDictionary dictionaryWithObjectsAndKeys:@"colorSquare", @"nodeType", [NSValue valueWithCGPoint:CGPointMake(positionX, positionY)],@"position", [node color], @"color", @"YES", @"exsit", nil];
            node.name = @"colorSquare";

            [_squareArray addObject:node];

            [self addChild:node];
        }
    }
}

一样的,在初始化用户界面的方法中调用addSquare,运行结果如下:运行结果3
好了,大致的游戏界面就这样完成了,现在开始处理点击事件。

逻辑处理

因为在SKScene中含有一个touch事件,那么自然就可以直接通过这个点击来进行游戏

#pragma mark - 点击事件
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    self.userInteractionEnabled = NO;
    if (_findArray) {
        [_findArray removeAllObjects];
    }

    // 获得点击的点
    UITouch *touch = [touches anyObject];
    CGPoint location = [touch locationInNode:self];
    CGPoint nodePosition = [self recentNode:location];
    SKNode *node = [self nodeAtPoint:nodePosition];

    if ([node.name isEqual:@"colorSquare"]) {
        __weak typeof(self) weakSelf = self;
        dispatch_async(_dealQueue, ^{
            [weakSelf dealWithColorNode:node];

        });

    }else {
        self.userInteractionEnabled = YES;
    }
}

// 判断点击的地方是否在节点上
- (CGPoint)recentNode:(CGPoint)location {
    int countX = (location.x - _backgroundOrigin.x)/ _squareLength;
    int countY = (location.y - _backgroundOrigin.y)/_squareLength;
    CGFloat x = _backgroundOrigin.x + countX*_squareLength + _squareLength/2;
    CGFloat y = _backgroundOrigin.y + countY*_squareLength + _squareLength/2;
    return CGPointMake(x, y);
}

#pragma mark - 逻辑处理
- (void)dealWithColorNode:(SKNode *)node {
    [self findFourDirectSquareOfSKNode:node AndNsMutableArray:_findArray];
    if (_findArray.count == 1) {
        self.userInteractionEnabled = YES;
        return;
    }

    for (SKNode *node in _findArray) {
        [node.userData setObject:@"NO" forKey:@"exsit"];
        SKAction *fadeOut = [SKAction fadeOutWithDuration:0.2];
        SKAction *removeAction = [SKAction removeFromParent];
        SKAction *all = [SKAction sequence:@[fadeOut, removeAction]];
        [node runAction:all completion:^{
            [_squareArray removeObject:node];
        }];
    }

    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        [self squareDown:[self needEndDown]];
    });

}

// 向四周查找是否有相同颜色的node
- (void)findFourDirectSquareOfSKNode:(SKNode *)node AndNsMutableArray:(NSMutableArray *)findArray {

    if (![findArray containsObject:node]) {
        [findArray addObject:node];
    }
    CGFloat height = self.size.height;

    NSValue *value = (NSValue *)[node.userData objectForKey:@"position"];
    CGPoint position = [value CGPointValue];

    // 获取node的x,y的坐标
    CGFloat positionX = position.x;
    CGFloat positionY = position.y;

    CGFloat minX = _backgroundOrigin.x+_squareLength/2;
    CGFloat minY = _backgroundOrigin.y+_squareLength/2;

    CGFloat maxX = _backgroundOrigin.x+_squareLength/2 + _squareLength*7;
    CGFloat maxY = _backgroundOrigin.y+_squareLength/2 + _squareLength*(height / _squareLength);

    CGFloat leftNodePositionX = positionX - _squareLength;
    CGFloat rightNodePositionX = positionX + _squareLength;
    CGFloat upNodePositionY = positionY + _squareLength;
    CGFloat downNodePositionY = positionY - _squareLength;

    SKNode *leftNode;
    SKNode *rightNode;
    SKNode *upNode;
    SKNode *downNode;

    if (leftNodePositionX >= minX) {
        leftNode = [self nodeAtPoint:CGPointMake(leftNodePositionX, positionY)];
        if ([self isSameColorNode:node WithNode:leftNode]) {
            if (![_findArray containsObject:leftNode]) {
                [_findArray addObject:leftNode];
                [self findFourDirectSquareOfSKNode:leftNode AndNsMutableArray:findArray];
            }
        }
    }
    if (rightNodePositionX <= maxX) {
        rightNode = [self nodeAtPoint:CGPointMake(rightNodePositionX, positionY)];
        if ([self isSameColorNode:node WithNode:rightNode]) {
            if (![_findArray containsObject:rightNode]) {
                [_findArray addObject:rightNode];
                [self findFourDirectSquareOfSKNode:rightNode AndNsMutableArray:findArray];
            }
        }
    }
    if (upNodePositionY <= maxY) {
        upNode = [self nodeAtPoint:CGPointMake(positionX, upNodePositionY)];
        if ([self isSameColorNode:node WithNode:upNode]) {
            if (![_findArray containsObject:upNode]) {
                [_findArray addObject:upNode];
                [self findFourDirectSquareOfSKNode:upNode AndNsMutableArray:findArray];
            }
        }
    }
    if (downNodePositionY >= minY) {
        downNode = [self nodeAtPoint:CGPointMake(positionX, downNodePositionY)];
        if ([self isSameColorNode:node WithNode:downNode]) {
            if (![_findArray containsObject:downNode]) {
                [_findArray addObject:downNode];
                [self findFourDirectSquareOfSKNode:downNode AndNsMutableArray:findArray];
            }
        }
    }
}

// 判断node是否为相同颜色的
- (BOOL)isSameColorNode:(SKNode *)node WithNode:(SKNode *)OtherNode {
    return [[node.userData objectForKey:@"color"] isEqual:[OtherNode.userData objectForKey:@"color"]];
}

// 让findArray中node上方的节点落下
- (void)squareDown:(NSMutableArray *)needDownArray {
    if (needDownArray && needDownArray.count) {
        SKNode *node = needDownArray.firstObject;
        NSInteger number = [self howManyCaseToFallWithSKNode:node];
        // 改变userdata
        CGFloat positionY = node.position.y - number * _squareLength;

        // 移动
        SKAction *moveAction = [SKAction moveTo:CGPointMake(node.position.x, positionY) duration:0];
        [node runAction:moveAction completion:^{
            NSMutableDictionary *userData = node.userData;
            [userData setObject:[NSValue valueWithCGPoint:CGPointMake(node.position.x, positionY)] forKey:@"position"];
            node.userData = userData;
            [needDownArray removeObject:node];
            [self squareDown:needDownArray];
        }];
    }else {
        [self moveToLeft];
    }
}

- (NSMutableArray *)needEndDown {
    NSMutableDictionary *needDownNodeDic = [[NSMutableDictionary alloc] init];

    CGFloat height = self.size.height;
    CGFloat maxY = _backgroundOrigin.y + _squareLength / 2 + height;

    for (SKNode *node in _findArray) {
        CGFloat positionX = node.position.x;
        CGFloat positionY = node.position.y;

        NSNumber *positionX_num = [NSNumber numberWithFloat:positionX];
        NSNumber *positionY_num = [NSNumber numberWithFloat:positionY];

        if (![needDownNodeDic objectForKey:positionX_num]) {
            [needDownNodeDic setObject:positionY_num forKey:positionX_num];
        }else {
            NSNumber *oldNumberOfY = [needDownNodeDic objectForKey:positionX_num];
            CGFloat oldY = [oldNumberOfY floatValue];
            CGFloat minPositionY = oldY < positionY ? oldY : positionY;
            NSNumber *maxNumberX = [NSNumber numberWithFloat:minPositionY];
            [needDownNodeDic setObject:maxNumberX forKey:positionX_num];
        }
    }

    NSMutableArray *nodeArray = [[NSMutableArray alloc] init];
    NSArray *keysArray = [needDownNodeDic allKeys];
    for (NSNumber *key in keysArray) {
        CGFloat minPositionY = [[needDownNodeDic objectForKey:key] floatValue];
        CGFloat positionX = [key floatValue];
        for (NSInteger i = 1; minPositionY + (i * _squareLength) <= maxY; i ++) {
            CGFloat nodePositionY = minPositionY + (i * _squareLength);
            __block SKNode *node = nil;
            NSArray<SKNode*> * nodes = [self nodesAtPoint:CGPointMake(positionX, nodePositionY)];
            [nodes enumerateObjectsUsingBlock:^(SKNode * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
                if ([obj.name isEqualToString:@"colorSquare"]) {
                    node = obj;
                    *stop = true;
                }
            }];
            if ([node.name isEqualToString:@"colorSquare"]) {
                [nodeArray addObject:node];
            }
        }
    }
    return nodeArray;
}

- (NSInteger)howManyCaseToFallWithSKNode:(SKNode *)node {

    CGFloat minY = _backgroundOrigin.y + _squareLength / 2;

    CGFloat positionX = node.position.x;
    CGFloat positionY = node.position.y;

    NSInteger fallNumber;
    for (fallNumber = 1; positionY - fallNumber * _squareLength >= minY; fallNumber ++) {
        CGFloat downPositionY = positionY - fallNumber * _squareLength;
        SKNode *downNode = [self nodeAtPoint:CGPointMake(positionX, downPositionY)];

        if ([downNode.name isEqualToString:@"colorSquare"]) {
            break;
        }
    }
    return fallNumber - 1;
}

- (void)moveToLeft {

    CGFloat minPositionY = _backgroundOrigin.y + _squareLength / 2;
    CGFloat minPositionX = _backgroundOrigin.x + _squareLength / 2;


    NSMutableArray *lookNodeArray = [[NSMutableArray alloc] init];
    for (NSInteger i = 0; i < 8; i ++) {
        SKNode *lookNode = [self nodeAtPoint:CGPointMake(minPositionX + _squareLength * i, minPositionY)];
        [lookNodeArray addObject:lookNode];
    }

    NSMutableArray *lineArray = [[NSMutableArray alloc] init];
    for (NSInteger i = 0; i < lookNodeArray.count - 1; i ++) {
        NSNumber *line = [NSNumber numberWithInteger:i];
        SKNode *node = lookNodeArray[i];
        if ([node.name isEqualToString:@"backSquare"]) {
            [lineArray addObject:line];
            SKNode *nextNode = lookNodeArray[i + 1];
            if ([nextNode.name isEqualToString:@"colorSquare"]) {
                break;
            }
        }
    }

    NSInteger number = lineArray.count;
    NSInteger line = [[lineArray lastObject] integerValue] + 1;
    NSInteger nodeNumber = self.size.height / _squareLength + 1;
    if (number == 0) {
        if (![self isContinueGame]) {
            [self refreshGame];
        }
        self.userInteractionEnabled = YES;
        return;
    }
    NSMutableArray *moveArray = [[NSMutableArray alloc] init];
    for (NSInteger i = line; i < 8; i ++) {
        for (NSInteger j = 0; j < nodeNumber; j ++) {
            CGFloat positionX = minPositionX + i * _squareLength;
            CGFloat positionY = minPositionY + j * _squareLength;
            SKNode *moveNode = [self nodeAtPoint:CGPointMake(positionX, positionY)];
            if ([moveNode.name isEqualToString:@"colorSquare"]) {
                [moveArray addObject:moveNode];
            }
        }
    }
    if (moveArray.count == 0) {
        if (![self isContinueGame]) {
            [self refreshGame];
        }
        self.userInteractionEnabled = YES;
        return;
    }
    [self animationWith:moveArray AndGeShu:number];
}

- (void)animationWith:(NSMutableArray *)array AndGeShu:(NSInteger)number {
    if (array && array.count) {
        SKNode *node = [array firstObject];
        CGFloat positionX = node.position.x - number * _squareLength;
        CGFloat positionY = node.position.y;
        SKAction *moveAction = [SKAction moveToX:positionX duration:0];
        [node runAction:moveAction completion:^{

            [node.userData setObject:[NSValue valueWithCGPoint:CGPointMake(positionX, positionY)] forKey:@"position"];

            [array removeObject:node];
            [self animationWith:array AndGeShu:number];
        }];
    }else{
        [self moveToLeft];
    }
}

// 查看是否还有可以消除的方块
- (BOOL)isContinueGame {
    for (SKNode *node in _squareArray) {
        NSMutableArray *findArray = [[NSMutableArray alloc] init];
        [self findFourDirectSquareOfSKNode:node AndNsMutableArray:findArray];
        if (findArray.count > 1) {
            return YES;
        }
    }
    return NO;
}

// 刷新游戏
- (void)refreshGame {
    for (SKNode *node in _squareArray)
    {
        [node removeFromParent];
    }
    [self addSquare];
}

最后完成的大致就是这样的:运行结果

这个是简化版的,喜欢的同学上app store上下载Magic Shatter。谢谢……

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值