Как подружить cocos2d iOS с twitter и facebook. Добавляем социальные плюшки в свою игру под iOS

в 11:54, , рубрики: cocos2d-iphone, Facebook, game development, twitter, разработка под iOS, метки: , ,

Введение

Если вам интересно как объеденить cocos2d вместе с социальными сетями (в данной статье будут рассмотрены twitter и facebook), то прошу под кат.

Что нужно сделать

Для начала сформулируем задачу. Есть исходное меню с несколькими вариантами:

  • Start game
  • Settings
  • Social features

При выборе последнего пункта должно появляться другое меню на новом слое, на котором должны быть отображены следующие опции:

  • Post screenshot to twitter
  • Post screenshot to facebook
  • Back to main menu

Видно, что если пользователь выберет Post screenshot to twitter, то программа должна сделать скриншот главного слоя (под главным слоем понимается слой, где отрисовывается ваш игровой процесс) и отправить его в twitter вместе с некоторым сообщением. Аналогичный функционал привязан к кнопке Post screenshot to facebook.

Share kit настройка и модфикация

Для интеграции своего проекта с twitter и facebook я выбрал SDK ShareKit. После установки ShareKit, нужно исправить некоторые баги в исходном коде данного SDK. Данные баги связаны c изменениями в twitter-api. И так, что нужно сделать. Открываем

SHKTwitter.m

ищем строчки с номерами 54-56 и заменяем их на следующий код:

self.authorizeURL = [NSURL URLWithString:@"https://api.twitter.com/oauth/authorize"];
self.requestURL = [NSURL URLWithString:@"https://api.twitter.com/oauth/request_token"];
self.accessURL = [NSURL URLWithString:@"https://api.twitter.com/oauth/access_token"];

Далее, заменяем строчку с номером 323 на следующую:

OAMutableURLRequest *oRequest = [[OAMutableURLRequest alloc] initWithURL:[NSURL URLWithString:@"https://api.twitter.com/1/statuses/update.json"]
consumer:consumer
token:accessToken
realm:nil
signatureProvider:nil];`

После небольших модификаций, открываем

SHKConfig.h

и заполняем для facebook и twitter соответствующие поля. Стоит отметить, что если у вас нет сайта, то можно использовать сайт-заглушку для заполнения поля

SHKTwitterCallbackUrl

(например mysite.wtf/lol)

Создаем меню

Добавляем в проект три класса, которые наследуются от CCLayer. Называем их HelloWorldLayer, IntroLayer, OptionsLayer. Пусть в IntroLayer будет базовое меню, а в OptionsLayer — меню, через которое пользователь может размещать сриншоты через facebook или twitter, а в MainGameScene — будет отображаться этикетка.
Код для header и implementation MainGameSceneLayer:

  • MainGameSceneLayer.h

    
    
    #import <GameKit/GameKit.h>
    
    // When you import this file, you import all the cocos2d classes
    #import "cocos2d.h"
    
    // HelloWorldLayer
    @interface HelloWorldLayer : CCLayer
    {
    }
    
    // returns a CCScene that contains the HelloWorldLayer as the only child
    +(CCScene *) scene;
    @end
    
  • MainGameSceneLayer.m

    
    // Import the interfaces
    #import "HelloWorldLayer.h"
    
    // Needed to obtain the Navigation Controller
    #import "AppDelegate.h"
    
    #pragma mark - HelloWorldLayer
    
    // HelloWorldLayer implementation
    @implementation HelloWorldLayer
    
    // Helper class method that creates a Scene with the HelloWorldLayer as the only child.
    +(CCScene *) scene
    {
    	// 'scene' is an autorelease object.
    	CCScene *scene = [CCScene node];
    	
    	// 'layer' is an autorelease object.
    	HelloWorldLayer *layer = [HelloWorldLayer node];
    	
    	// add layer as a child to scene
    	[scene addChild: layer];
    	
    	// return the scene
    	return scene;
    }
    // on "init" you need to initialize your instance
    -(id) init
    {
    	// always call "super" init
    	// Apple recommends to re-assign "self" with the "super's" return value
    	if( (self=[super init]) ) {
    		// create and initialize a Label
    		CCLabelTTF *label = [CCLabelTTF labelWithString:@"Hello World" fontName:@"Marker Felt" fontSize:64];
    		// ask director for the window size
    		CGSize size = [[CCDirector sharedDirector] winSize];
    		// position the label on the center of the screen
    		label.position =  ccp( size.width /2 , size.height/2 );
    		// add the label as a child to this Layer
    		[self addChild: label];
    		
        }
    	return self;
    }
    // on "dealloc" you need to release all your retained objects
    - (void) dealloc
    {
    	// in case you have something to dealloc, do it in this method
    	// in this particular example nothing needs to be released.
    	// cocos2d will automatically release all the children (Label)
    	
    	// don't forget to call "super dealloc"
    	[super dealloc];
    }
    @end
    

Код для header и implementation IntroLayer с комментариями внутри:

  • IntroLayer.h
    
             #import "cocos2d.h"
    //Конструктор класса
    @interface IntroLayer : CCLayer
    {
    }
    +(CCScene *) scene;
    @end
            

  • IntroLayer.m

    
             // Нужно импортировать все заголовочные файлы слоев, между которыми будет переключение. В данном случае, нужно импортировать только IntroLayer.h, HelloWorldLayer.h, OptionsLayer.h
    #import "IntroLayer.h"
    #import "HelloWorldLayer.h"
    #import "OptionsLayer.h"
    #pragma mark - IntroLayer
    @implementation IntroLayer
    +(CCScene *) scene
    {
    	CCScene *scene = [CCScene node];
    	IntroLayer *layer = [IntroLayer node];
    	[scene addChild: layer];
    	return scene;
    }
    //Как только появится слой IntroLayer, сразу отображаем исходное меню
    -(void) onEnter
    {
    	[super onEnter];
            [self addMenuToTheIntroLayer];
    }
    //Тело метода, в котором создаем и добавляем на слой Introlayer исходное меню
    -(void)addMenuToTheIntroLayer
    {
    //Создаем пункты меню. В конце статьи будет дана ссылка на урок, где вместо текста используются 
    //Пункт первый - Start game
    //Тип шрифта
        [CCMenuItemFont setFontName:@"Marker Felt"];
    //Размер шрифта
        [CCMenuItemFont setFontSize:25];
    //Указатель на пункт меню со ссылкой на обработчик нажатия. 
        CCMenuItemFont* start_game=[CCMenuItemFont itemWithString:@"Start game" target:self selector:@selector(switchToTheGameScene:)];
    //Конец создания пункта - Start game
    
        [CCMenuItemFont setFontName:@"Marker Felt"];
        [CCMenuItemFont setFontSize:25];
        CCMenuItemFont* switch_to_socials=[CCMenuItemFont itemWithString:@"Social features" target:self selector:@selector(switchToSocialFeatures:)];
        
        CCMenu *menu=[CCMenu menuWithItems:start_game, switch_to_socials, nil];
        [menu alignItemsVertically];
        
        [self addChild:menu];
    }
    
    //Обработчики нажатий на меню
    -(void) switchToTheGameScene:(id)sender
    {
    //Прыгаем на другой слой HelloWorldLayer
        [[CCDirector sharedDirector] replaceScene:[HelloWorldLayer scene]];
    }
    -(void)switchToSocialFeatures:(id)sender
    {
        [[CCDirector sharedDirector] replaceScene:[OptionsLayer scene]];
    }
    @end
            

Код для header и implementation OptionsLayer с комментариями внутри:

  • OptionsLayer.h

    
    #import "cocos2d.h"
    //подключаем библиотеки для отправки твито и постов на стенку facebook
    #import "SHK.h"
    #import "SHKTwitter.h"
    #import "SHKFacebook.h"
    
    @interface OptionsLayer : CCNode
    {
    }
    +(CCScene *) scene;
    @end
    
  • OptionsLayer.m

    
    #import "OptionsLayer.h"
    #import "HelloWorldLayer.h"
    //Переходите сразу к обработчикам событий так как там будет описан функционал отправки твитов и сообщений к себе на стенку facebook
    @implementation OptionsLayer
    +(CCScene *) scene
    {
    	CCScene *scene = [CCScene node];
    	OptionsLayer *layer = [OptionsLayer node];
    	[scene addChild: layer];
    	return scene;
    }
    -(void) onEnter
    {
        [super onEnter];
        [self addMenuToTheIntroLayer];
    }
    -(void)addMenuToTheIntroLayer
    {
        [CCMenuItemFont setFontName:@"Marker Felt"];
        [CCMenuItemFont setFontSize:25];
        CCMenuItemFont* start_game=[CCMenuItemFont itemWithString:@"Post to twitter" target:self selector:@selector(postToTwitter:)];
        
        [CCMenuItemFont setFontName:@"Marker Felt"];
        [CCMenuItemFont setFontSize:25];
        CCMenuItemFont* switch_to_socials=[CCMenuItemFont itemWithString:@"Post to facebook" target:self selector:@selector(postToFacebook:)];
        
        [CCMenuItemFont setFontName:@"Marker Felt"];
        [CCMenuItemFont setFontSize:25];
        CCMenuItemFont* back_to_game=[CCMenuItemFont itemWithString:@"Back to game" target:self selector:@selector(backToGame:)];
        
        CCMenu *menu=[CCMenu menuWithItems:start_game, switch_to_socials,back_to_game, nil];
        [menu alignItemsVertically];
        
        [self addChild:menu];
    }
    -(void) postToFacebook:(id)sender
    {
        SHKItem  *facebookItem = [SHKItem image:imgToPost title:@"Check out my highscore! #RobotWarsProject"];
        [SHKFacebook shareItem:facebookItem];
    }
    -(void)postToTwitter:(id)sender
    {
    //метод для создания скриншотов
        [self takeScreenShot];
    //создаем сущность для отправки через twitter
    //в данном случае это будет картинка с комментарием и хэш-тегом
        SHKItem *twitterItem = [SHKItem image:imgToPost title:@"Check out my highscore! #RobotWarsProject"];
        [SHKTwitter shareItem:twitterItem];
    }
    -(void)backToGame:(id)sender
    {
    //если пользователь хочет вернуться обратно и продолжить игру
        [[CCDirector sharedDirector] replaceScene:[HelloWorldLayer scene]];
    }
    @end
    

Делаем скриншоты

Сразу скажу, что если вы используете cocos2d 0.99, то создание скриншотов выглядит достаточно просто:

UIImage *image = [[CCDirector sharedDirector] screenshotUIImage]

Для тех, кто использует более новую версию этого замечательного графического фреймворка, нужно создавать отдельны метод создания скриншотов. Для этого модифицируем код OptionsLayer следующим образом:

  • OptionsLyer.h

    
    #import "cocos2d.h"
    #import "SHK.h"
    #import "SHKTwitter.h"
    #import "SHKFacebook.h"
    
    @interface OptionsLayer : CCLayer
    {
    //в этой переменной будем хранить сриншот
        UIImage *imgToPost;
    }
    //метод, который создает скриншот
    //первый параметр - название слоя, с которого будем создаваться скриншот
    -(CCRenderTexture*) screenshotWithStartNode:(CCNode*)startNode filename:(NSString*)filename;
    @end
    
  • OptionsLyer.m

    
    //Добавляем описание метода 
    - (void) takeScreenShot
    {
            //Называем файл, который будет сохраняться в фото-библиотеку
            NSString* file = @"//imageforphotolib.png";
            
            //Путь к фотографиям. По-моему, это единственное место куда Apple разрашает что-то сохранять без создания песочницы
            NSArray* paths = NSSearchPathForDirectoriesInDomains
            (NSDocumentDirectory, NSUserDomainMask, YES);
            NSString* documentsDirectory = [paths objectAtIndex:0];
            NSString* screenshotPath = [documentsDirectory
                                        stringByAppendingPathComponent:file];
            //
            [CCDirector sharedDirector].nextDeltaTimeZero = YES;
            
            //Поулчаем разамер экрана
            CGSize winSize = [CCDirector sharedDirector].winSize;
            
            //Включаем рендер и передаем ему размеры окна
            CCRenderTexture* rtx =
            [CCRenderTexture renderTextureWithWidth:winSize.width
                                             height:winSize.height];
    //Начинаем отрисовку
            [rtx begin];// открываем текстуру
            [[MainGameLayer node] visit];//получаем ссылку на игровой слой
            [rtx end];//закрываем текстуру
            
            // Сохраяем картинку в документы как *.PNG файл. 
            [rtx  saveToFile:@"imageforphotolib.png"
                      format:kCCImageFormatPNG];
            
        //Конвертируем скриншот из нулей и единичек в UIImage
        NSData *data = [NSData dataWithContentsOfFile:screenshotPath];
        //create an image from the raw data
        UIImage *img = [UIImage imageWithData:data];
        //Сохраняем в Photo Library и передаем полученную картинку свойству imgToPost
        imgToPost=img;
            UIImageWriteToSavedPhotosAlbum(img, nil, nil, nil);
    }
    

На этом статья закончена. Если у вас будут вопросы и/или комментарии, то пишите, с удовольствием на них отреагирую.

Список статей на английском языке

ПЫСЫ попробуйте интегрировать этот проект с моим старым проектом

Автор: getbraine

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js