ios開發中蘋果2D引擎SpriteKit介紹,iosspritekit

來源:互聯網
上載者:User

ios開發中蘋果2D引擎SpriteKit介紹,iosspritekit

ios開發中蘋果2D引擎SpriteKit介紹,最近研究了蘋果自家開發的2D引擎SpriteKit和3D引擎SceneKit,開篇之前,需要客觀的講,如果你要從事的是團隊或者公司的項目,還是直接unity搞起,這涉及到開發與維護成本的問題,畢竟SpriteKit目前無法對跨平台給予支援。但是如果你是一個獨立開發人員,對蘋果原生架構感興趣,或者只關注與蘋果的App Store,我想SpriteKit和SceneKit也是個不錯的選擇。

Sprite譯作精靈,可以這樣理解,在SpriteKit的世界裡,遊戲裡的怪獸是一個精靈,主角與主角發射的炮彈也是一個精靈,或者說遊戲裡的一個不會動的背景圖,也可以是一個精靈。下面以精靈為切入點,講解一下一個充滿野心的蘋果弄出來的2D引擎。

一、精靈與情境

1.建立一個Xcode工程,可以看到,不管是iOS,還是macOS,甚至於tvOS,都有一個叫Game的項目建立方式。我們選擇iOS的Game,建立出一個遊戲項目。Game與普通工程項目有什麼不同,其實就一點項目預設的GameViewController的view是以skView的形式load出來的,下面我們接著建立一個遊戲情境SKScene,用以裝載即將new出來的精靈。

2.情境的建立。
註:Scene情境的起始座標是以左下角為(0,0)原點,而非傳統view的左上方。

- (MenuScene *)menuScene {    if (!_menuScene) {        _menuScene = [[MenuScene alloc] initWithSize:self.view.bounds.size];        //@interface MenuScene : SKScene        //@end    }    return _menuScene;}- (void)viewDidLoad {    [super viewDidLoad];    [(SKView *)self.view presentScene:self.menuScene];    // Do any additional setup after loading the view, typically from a nib.}
@implementation MenuScene-(instancetype)initWithSize:(CGSize)size {    if (self = [super initWithSize:size]) {        #if TARGET_OS_IPHONE         #define SKColor UIColor        #else         #define SKColor NSColor        #endif        // SKColor主要是為了相容mac的NSColor與iOS的UIColor        self.backgroundColor = [SKColor whiteColor];        [self addChild:self.titleNode];        [self addChild:self.pathLabelNode];        [self addChild:self.collLabelNode];        [self addChild:self.physLabelNode];        [self addChild:self.physCollNode];    }    return self;}

3.遊戲情境的切換。與初始化的頁面一致,遊戲的轉場為使用presentScene跳轉到建立的Scene當中。

- (SKLabelNode *)titleNode {    if (!_titleNode) {        _titleNode = ({            SKLabelNode *labelNode = [SKLabelNode labelNodeWithFontNamed:@"Chalkduster"];            labelNode.text = @"SpriteKit  Test";            labelNode.fontSize = 30;            labelNode.fontColor = [SKColor blueColor];            labelNode.position = CGPointMake(CGRectGetMidX(self.frame), self.frame.size.height * 0.75);            labelNode.name = labelNode.text;            labelNode;        });    }    return _titleNode;}-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {    for (UITouch *touch in touches) {        CGPoint location = [touch locationInNode:self];        SKNode *node = [self nodeAtPoint:location];        [self changeToGameSceneWithNodeName:node.name];    }}-(void)changeToGameSceneWithNodeName:(NSString *)nodeName {    NSLog(@"nodeName=%@",nodeName);    if ([nodeName isEqualToString:self.pathLabelNode.name]) {        PathScene *pathScene = [PathScene sceneWithSize:self.size];        // 定製轉場類型        SKTransition *reveal = [SKTransition revealWithDirection:SKTransitionDirectionUp duration:0.5];        [self.scene.view presentScene:pathScene transition:reveal];    }    else if ...

4.精靈的建立與添加。精靈的建立有兩種形式,一個是直接以圖片的形式建立,其size預設為圖片的size,另一種則以紋理的形式建立。

// 以圖片建立- (SKSpriteNode *)player {    if (!_player) {        _player = [SKSpriteNode spriteNodeWithImageNamed:@"player"];        _player.name = @"player";        _player.position = CGPointMake(self.size.width /2, self.size.height /2);    }    return _player;}
// 以紋理建立- (SKSpriteNode *)walkMan {    if (!_walkMan) {        _walkMan = [SKSpriteNode spriteNodeWithImageNamed:@"walkR01"];        _walkMan.name = @"walkMan";        _walkMan.position = CGPointMake(self.player.position.x, CGRectGetMaxY(self.player.frame) + 30);        SKTexture * texture1 = [SKTexture textureWithImageNamed:@"walkR01"];        SKTexture * texture2 = [SKTexture textureWithImageNamed:@"walkR02"];        SKTexture * texture3 = [SKTexture textureWithImageNamed:@"walkR03"];        SKTexture * texture4 = [SKTexture textureWithImageNamed:@"walkR04"];        SKTexture * texture5 = [SKTexture textureWithImageNamed:@"walkR05"];        SKAction *animation = [SKAction animateWithTextures:@[texture1, texture2, texture3, texture4, texture5] timePerFrame:1];        SKAction *action = [SKAction repeatActionForever:animation];        [_walkMan runAction:action];    }    return _walkMan;}

5、精靈的添加運動事件

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {    for (UITouch *touch in touches) {        // 添加武器        SKSpriteNode * arms = [SKSpriteNode spriteNodeWithImageNamed:@"projectile"];        arms.position = self.player.position;        [self addChild:arms];        CGPoint location = [touch locationInNode:self];        // 直線軌跡//        SKAction * moveToAction = [SKAction moveTo:location duration:0.5];;        // 持續增加//        SKAction * moveByAction = [SKAction moveByX:100 y:100 duration:0.3];        // 改變大小//        SKAction * sizeAction = [SKAction resizeByWidth:arms.size.width * 1.5 height:arms.size.height * 1.5  duration:0];        // 旋轉//        SKAction * radiansAction = [SKAction rotateByAngle:M_PI * 4 duration:moveToAction.duration];        // 音效//        SKAction * armsSound = [SKAction playSoundFileNamed:@"pew-pew-lei.caf" waitForCompletion:NO];        SKAction * armsAction = [SKAction group:@[pathAction, sizeAction,armsSound]];        [arms runAction:armsAction completion:^{            // 移除            [arms removeFromParent];        }];    }}

二、精靈的接觸檢測

SKScene有一個情境方法,改方法每幀都會觸發一次,可供簡單的事件分析與監測,比如精靈越界銷毀,精靈的接觸監測,故事板的得分情況的更新等等。

/** Override this to perform per-frame game logic. Called exactly once per frame before any actions are evaluated and any physics are simulated. @param currentTime the current time in the app. This must be monotonically increasing. */- (void)update:(NSTimeInterval)currentTime;
-(void)update:(CFTimeInterval)currentTime {    // 怪物與武器的越界移除    // 更新數字版    // 檢測精靈事件(如點擊精靈之後,給它設定個標識,在下一幀的時候做事件處理)}
註:後面講述精靈的物理碰撞,能夠更準確的進行精靈的碰撞檢測

三、精靈的物理引擎

// 方形- (SKSpriteNode *)square {    if (!_square) {        _square = [SKSpriteNode spriteNodeWithImageNamed:@"square"];        _square.position = CGPointMake(self.size.width * 0.8, CGRectGetMidX(self.frame));        _square.name = @"square_prey";        _square.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:_square.size];    }    return _square;}// 圓形- (SKSpriteNode *)circle {    if (!_circle) {        _circle = [SKSpriteNode spriteNodeWithImageNamed:@"circle"];        _circle.position = CGPointMake(self.size.width * 0.65, CGRectGetMidX(self.frame));        _circle.name = @"circle_prey";        _circle.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:_circle.size.width / 2];    }    return _circle;}// 三角形- (SKSpriteNode *)triangle {    if (!_triangle) {        _triangle = [SKSpriteNode spriteNodeWithImageNamed:@"triangle"];        _triangle.position = CGPointMake(self.size.width * 0.5, CGRectGetMidX(self.frame));        _triangle.name = @"triangle_prey";        CGMutablePathRef trianglePath = CGPathCreateMutable();        // 中心        CGPathMoveToPoint(trianglePath, nil, -_triangle.size.width / 2, -_triangle.size.height / 2);        //        CGPathAddLineToPoint(trianglePath, nil, _triangle.size.width / 2, -_triangle.size.height / 2);        CGPathAddLineToPoint(trianglePath, nil, 0, _triangle.size.height / 2);        CGPathAddLineToPoint(trianglePath, nil, -_triangle.size.width / 2, -_triangle.size.height / 2);        _triangle.physicsBody = [SKPhysicsBody bodyWithPolygonFromPath:trianglePath];        CGPathRelease(trianglePath);    }    return _triangle;}

四、精靈的物理碰撞檢測

-(instancetype)initWithSize:(CGSize)size {    if (self = [super initWithSize:size]) {        self.backgroundColor = [UIColor whiteColor];        [self addChild:self.back];        [self addChild:self.square];        [self addChild:self.circle];        [self addChild:self.triangle];        self.physicsBody = [SKPhysicsBody bodyWithEdgeLoopFromRect:self.frame];        self.scene.name = @"self";        self.physicsBody.categoryBitMask = 0x00000001;        self.physicsBody.collisionBitMask = 0x00000001;        self.physicsBody.contactTestBitMask = 0x00000001;        self.physicsWorld.contactDelegate = (id )self;    }    return self;}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {    for (UITouch *touch in touches) {        CGPoint location = [touch locationInNode:self];        // 擷取點擊的SKNode        SKNode * node = [self nodeAtPoint:location];        // 建立一個黑球        Node * ball = [SKSpriteNode spriteNodeWithImageNamed:@"blackBall"];        ball.position = CGPointMake(0, 0);        ball.name = @"ball";        ball.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:ball.size.width / 2];        CGPoint offset = CGPointMake(location.x - ball.position.x, location.y - ball.position.y);        // 斜率        float ratio = (float) offset.y / (float) offset.x;        // 速度        ball.physicsBody.velocity = CGVectorMake(1000, 1000 * ratio);        // 角速度  弧度/秒        ball.physicsBody.angularVelocity = M_PI * 4;        // 密度        ball.physicsBody.density = 100;        // 彈力        ball.physicsBody.restitution = 1;        // 動量 /kg        ball.physicsBody.mass = 100;        // 光滑度  0 ~ 1        ball.physicsBody.friction = 0.5;        // 是否受重力影響 default value is YES        ball.physicsBody.affectedByGravity = NO;        // 是否受加速度影響        ball.physicsBody.allowsRotation = NO;        // 線性阻尼(0:速度從不減弱;1:速度立即減弱)        ball.physicsBody.linearDamping = 0.5;        // 角速度阻尼(0:速度從不減弱;1:速度立即減弱)default 0.1        ball.physicsBody.angularDamping = 0;        // 物體的類別(一個16進位數)        ball.physicsBody.categoryBitMask = 0x00000001;        // 設定哪個物體不可與之碰撞(即不可穿透)        ball.physicsBody.collisionBitMask = 0x00000001;        // 接觸(觸發檢測函數)        ball.physicsBody.contactTestBitMask = 0x00000001;        [self addChild:ball];    }}
- (void)didBeginContact:(SKPhysicsContact *)contact {    NSLog(@"聯絡中的第一個物體:%@",contact.bodyA.node.name);    NSLog(@"聯絡中的第二個物體:%@",contact.bodyB.node.name);    NSLog(@"聯絡點的座標:%@",NSStringFromCGPoint(contact.contactPoint));    NSLog(@"碰撞方向的法向量:%@",NSStringFromCGVector(contact.contactNormal));    NSLog(@"兩個物體的碰撞強度(牛頓每秒):%f",contact.collisionImpulse);    if ([contact.bodyA.node.name containsString:@"prey"] && [contact.bodyB.node.name isEqualToString:@"ball"]) {        [contact.bodyA.node removeFromParent];    }    if ([contact.bodyB.node.name containsString:@"prey"] && [contact.bodyA.node.name isEqualToString:@"ball"]) {        [contact.bodyB.node removeFromParent];    }}

@end

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.