technical

【Swift】プロジェクト内に置いたpng画像をNSDataとして取り出す

こんにちは、ユーリです!
お仕事でSwift使い始めたので、Swift関連の備忘録を書いていきます。

まずはpng画像を簡単に取り出す方法について。 メルストの記事じゃなくてゴメンナサ…


今回は、プロジェクトファイル内にリソース画像などを格納するbundleファイルを設置し、
そこから画像を吸い出す方法で行きたいと思います。

まずは、bundleの作成から。
以下の作業を行う前に、ファイルの拡張子を表示するモードにしておいてください。

bundleの作成


プロジェクトのフォルダをFinderで開き、おもむろに新規フォルダを作成します。
20151218_a01

フォルダができたら、名前を「***.bundle」に変更します。
今回は「resources.bundle」にしましょう! 20151218_a02

すると「まじ?」と聞かれるので「あたぼうよ」と答えます。
20151218_a03

フォルダの拡張子がbundleに変わり、アイコンも変わりました。
20151218_a04 空のbundleファイルができました!

今度は、bundleファイルをプロジェクトに追加します。
Fileメニューから「Add Files to …」でプロジェクトにファイルを追加します。
20151218_b01

先ほど作成したbundleファイルを選択します。
20151218_b02

プロジェクトにbundleファイルが追加されました!
20151218_b03

これ以降は、FinderからXcode内のbundleファイルに直接ドラッグ&ドロップで、プロジェクト内で取り扱いたいpng画像を取り込むことができます。

試しに、画像を一点ドラッグして追加してみます。
こんな画像があったとして。
20151218_b04

ドラッグすると、追加されます。 20151218_b05


次は、いよいよこの画像を呼んでみます。

bundleからpng画像を呼ぶ


先にソースを張ってしまいますが、png画像を呼ぶ為の関数はこちらです。

/// リソース内からpng画像を取り出し、NSData形式で返却する
/// - parameter name : 画像の名前(パス)。拡張子[png]は省略。
/// - returns : NSData形式のpng画像 存在しなければnilを返す。
func getResourceImage(name:String)-> NSData?{
    let bundlePath : String = NSBundle.mainBundle().pathForResource("resources", ofType: "bundle")!
    let bundle : NSBundle = NSBundle(path: bundlePath)!
    if let imagePath : String = bundle.pathForResource(name, ofType: "png"){
        let fileHandle : NSFileHandle = NSFileHandle(forReadingAtPath: imagePath)!
        let imageData : NSData = fileHandle.readDataToEndOfFile()
        return imageData
    }
    return nil
}

この関数はどこに書いてもいいのですが、どこからでも呼べるように、 新しくUtil.swiftというファイルを作り、その中に置いてみます。

File > New > Fileを選び、 20151218_c01

Swiftファイルを選びます。 20151218_c02

名前をつけて、プロジェクトのグループ内に配置しましょう。 20151218_c03

新しいSwiftファイルができたら、その中に先ほどのソースを貼り付けます。 20151218_c05

これで準備完了です!!

使い方


以下のように、拡張子(png)を抜かしたファイル名で呼び出します。 画像が存在しない場合はnilが返るので、無かった場合の処理も考えておきましょう。
こちらの例では、返ってきたNSDataを利用してUIImageを生成しています。
let testData : NSData? = getResourceImage("test")
if testData != nil{
	let testImage : UIImage! = UIImage(data: testData! )

	// do something...

}

また、以下のようにbundle内にフォルダを作って、その中の画像を呼び出したい場合は、スラッシュを挟めば大丈夫です!
20151218_d01

let testData : NSData? = getResourceImage("images/test2")


解説

let bundlePath : String = NSBundle.mainBundle().pathForResource("resources", ofType: "bundle")!
まず、こちらの行はプロジェクト内から「resources」という名前をbundleのパスを生成しています。
プロジェクト内にresourcesというbundleが無いと大変なことになります。
let bundle : NSBundle = NSBundle(path: bundlePath)!
次に、bundleのパスからbundleのインスタンスを得ます。
if let imagePath : String = bundle.pathForResource(name, ofType: "png"){
そして、bundle内に指定した名前のpng画像があるかどうか調べています。
    let fileHandle : NSFileHandle = NSFileHandle(forReadingAtPath: imagePath)!
    let imageData : NSData = fileHandle.readDataToEndOfFile()
    return imageData
そして、画像があった場合は読み込んで、NSDataとして返します。

  • Category: technical / swift
  • Posted: 2015/12/18 12:00
  • Author: ユーリ
technical

cocos2d-xの環境構築をしたら次は何をすればよいのか

こんにちは、ユーリです!
最近、次のスマホゲームを作成するべく、cocos2d-xでの開発をはじめました!

※cocos2d-xとは、iphoneとAndroid、両方のプラットフォームで2dゲーム開発ができるフレームワークです。
この記事は、ある程度プログラムへの知識がある方へ向けて書いています。


環境構築については、うまくまとめていらっしゃるサイト様がたくさんありますので、この場では省きます!
ですが、環境構築をして、テストプロジェクトを作り、サンプルの動作を確認、まで行ったら…次になにをしたらいいか、パッと見つからなかったため、私なりにまとめてみました。
※実行環境
mac OS X ver 10.9.5
cocos2d-x ver 3.3
Xcode ver 6.1.1


メインシーン用クラスを作る


ひとまずHelloWorldの次のステップとして、オリジナルの画面をつくることですね。
デフォで存在している「Classes」フォルダの中にオリジナルシーン用のクラスを作成します。
20150127_1
New File…でファイル作成。

20150127_2
C++ Fileを選びます。

20150127_3
クラス名を決めます。何でもいいんですが、MainSceneにしました。

20150127_4
決定すると、
MainScene.cpp と
MainScene.h の二つのファイルが作成されます。
ソースファイルはこのようにシーンごとに作成します。

Sceneの骨組みと、入力に反応するメソッドを作る


次に、シーンを制御するコンストラクタとデストラクタ、
そして入力に反応するイベントリスナーを実装します。
まずはヘッダファイルから。

//
//  MainScene.h
//  testproject
//
//  Created by yuri on 2015/01/26.
//
//

#ifndef __testproject__MainScene__
#define __testproject__MainScene__

#include "cocos2d.h"

class MainScene :public cocos2d::Layer
{
protected:
    MainScene();            //コンストラクタ
    virtual ~MainScene();   //デストラクタ
    bool init() override;   //初期化処理

public:
    static cocos2d:: Scene* createScene();
    CREATE_FUNC(MainScene);                 //createメソッドを作成
    CC_SYNTHESIZE_RETAIN(cocos2d::Sprite *, _cursor,Cursor);    //_cursor変数を作成し、ゲッターとセッターを実装する
};

#endif /* defined(__testproject__MainScene__) */

まずは必要最低限の実装です。
シーンクラスは、SceneではなくLayerを継承して作成します。 CREATE_FUNC(MainScene); はマクロで、create();関数の生成を行います。
CC_SYNTHESIZE_RETAIN(cocos2d::Sprite *, _cursor,Cursor); では、入力に反応して動くカーソル用のスプライトを生成します。

続いて、ソースファイルです。

//
//  MainScene.cpp
//  testproject
//
//  Created by yuri on 2015/01/26.
//
//

#include "MainScene.h"

USING_NS_CC;

MainScene::MainScene()
: _cursor(NULL) //コンスタラクタ内での初期化
{

}

MainScene::~MainScene()
{
    CC_SAFE_RELEASE_NULL(_cursor);  //オブジェクトをリリースする
}

Scene* MainScene::createScene()
{
    auto scene = Scene::create();
    auto layer = MainScene::create();
    scene -> addChild(layer);
    return scene;
}

bool MainScene::init()
{
    if(!Layer::init()){
        return false;
    }
    auto director = Director::getInstance();    //Directorを取り出す

    //初期化を行う
    this -> setCursor(Sprite::create("CloseSelected.png")); //指定画像をリソースにスプライトを生成
    _cursor -> setPosition(Vec2(100,100));                  //位置の定義
    this -> addChild(_cursor);                              //生成したスプライトをシーンに追加

    //タッチ操作の動作定義
    auto listner = EventListenerTouchOneByOne::create();    //一点タッチされたときのイベント定義
    listner -> onTouchBegan = [this](Touch* touch,Event* event){
        //タッチされたときの処理(この定義は必須である)
        auto touchPosition = touch -> getLocation(); //タッチした位置を取得
        _cursor -> setPosition(touchPosition);    //カーソルの座標にタッチ座標を格納
        log("タッチ位置 : %f , %f" , touchPosition.x , touchPosition.y );
        return true;
    };
    listner -> onTouchMoved = [this](Touch* touch,Event* event){
        //タッチしたあと移動した場合
        auto touchPosition = touch -> getLocation(); //タッチした位置を取得
        _cursor -> setPosition(touchPosition);    //カーソルの座標にタッチ座標を格納
    };
    director->getEventDispatcher()->addEventListenerWithSceneGraphPriority(listner, this);  //作成したイベントを画面にひもづける

    return true;
}

カーソル用の画像は、今回はデフォルトでリソースに入っているボタン画像を使っちゃいました。
20150127_5
お好みのものを使いたい場合、Resourcesフォルダ内に画像を追加する必要があります。

今回は初期化用の関数 init()と、Directorというクラスがポイントになります。
init()内では、リソース内の画像ファイルからスプライトの生成、タッチした時の挙動をイベントリスナーに登録。という二つの動作を実装しています。
Directorはゲーム全体を管理するクラスで、画面サイズや端末情報を得る際に使用します。
今回はこのDirectorクラスを通じて、画面にイベントリスナーを追加しています。
その他の部分はだいたいおまじないです。

あとは、AppDelegate.cpp内のHelloWorldの部分をMainSceneに置き換えれば完成です。

#include "AppDelegate.h"
//#include "HelloWorldScene.h"
#include "MainScene.h"
    // set FPS. the default value is 1.0/60 if you don't call this
    director->setAnimationInterval(1.0 / 60);

    // create a scene. it's an autorelease object
    //auto scene = HelloWorld::createScene();
    auto scene = MainScene::createScene();

背景は真っ暗ですが、タッチするとタッチした位置にカーソルがついてくる画面が完成しました!
20150127_6

今日はここまでに致します…。

  • Category: technical / cocos2d-x
  • Posted: 2015/1/27 13:00
  • Author: ユーリ
technical

【備忘録】Xcodeの実機テストで、ログが出力されなくなった

こんにちは。

Xcodeでのコーディング中のこと。
シミュレータでの動作ではconsoleにログが出力されるのに、
実機テストを行うとログが出力されなくなる ということがありました。

続きを読む…
  • Category: technical / swift
  • Posted: 2014/11/13 10:49
  • Author: ユーリ