参 Cocos2d-xで絵がタッチされたらスイッと動かす

#目次
1 はじめに
2 絵を動かす
2.1 絵を移動する
2.2 画面がタッチされたら移動する
2.3 絵がタッチされたら移動する
4 今後の予定
タッチされた絵を消す、そこに一瞬キラッとした視覚効果表示する

#はじめに
本記事は、cocos2d-xおよびCocos Code IDEを導入し、プロジェクトを作成し絵(スプライト)を表示した人で、そこから絵を動かしたい人に向けた、覚書です。絵を動かす命令はアクションと呼ばれています。まず、絵をゆっくり移動します、その後、タッチへ応答する形で絵を移動します。これにはイベントと呼ばれる命令を使います。


#絵を動かす ゆっくり移動する
今回は下記コードから説明を始めます。


```GameScene.lua
local GameScene = class("GameScene",function()
    return cc.Scene:create()
end)

function GameScene.create()
    local scene = GameScene.new()
    scene:addChild(scene:createLayer())
    return scene
end


function GameScene:ctor()
    self.visibleSize = cc.Director:getInstance():getVisibleSize()
    self.origin = cc.Director:getInstance():getVisibleOrigin()
    self.schedulerID = nil
end

function GameScene:playBgMusic()
--[[local bgMusicPath = cc.FileUtils:getInstance():fullPathForFilename("background.mp3") 
    cc.SimpleAudioEngine:getInstance():playMusic(bgMusicPath, true)
    local effectPath = cc.FileUtils:getInstance():fullPathForFilename("effect1.wav")
    cc.SimpleAudioEngine:getInstance():preloadEffect(effectPath)]]
end

-- create a layer
function GameScene:createLayer()
    local layer = cc.Layer:create()

    local sprite = cc.Sprite:create("land.png")
    sprite:setPosition(100,100)
    layer:addChild(sprite)

    return layer
end

return GameScene
```

下の方、`GameScene:createLayer()`関数内にa)を追記します。

```GameScene.lua
...
function GameScene:createLayer()
    local layer = cc.Layer:create()

    -- スプライトを追加
    local sprite = cc.Sprite:create("land.png")
    sprite:setPosition(100,100)
    layer:addChild(sprite)

    -- ここから
    -- a)スプライトを移動
    local move = cc.MoveTo:create(2, cc.p(400,400))
    sprite:runAction(move)
    -- ここまで追記

    return layer
end
...
```

では変更を保存して実行してみましょう。絵が左下から右上にゆっくり移動します。

![3-1 move.png](https://qiita-image-store.s3.amazonaws.com/0/90495/54525f86-e387-973d-0c51-aa81ff9a1d38.png)


`cc.MoveTo:create(2, cc.p(400,400))`は、2秒かけて座標(400,400)へ移動するという意味です。
`sprite:runAction(move)`により、sprite(land.pngの絵)に対してこの移動命令が実行されます。

また、アクションを使わないで、sprite:setPosition(400,400)でも移動できますが、瞬間移動になります。
他にもrunActionで実行できる命令があります。今後随時追加した時に説明します。

#絵を動かす 画面がタッチされたら移動する
上記コードは起動すると勝手に移動して終わりでしたが、タッチに応答して動くようにしましょう。下記の様にコードを変更します。

```GameScene.lua
...
function GameScene:createLayer()
    local layer = cc.Layer:create()

    -- スプライトを追加
    local sprite = cc.Sprite:create("land.png")
    sprite:setPosition(100,100)
    layer:addChild(sprite)

    -- b)タッチイベント開始時に呼ばれる関数
    local function onTouchBegan(touch, event)
        local location = touch:getLocation() --後で使う
        
        -- a)スプライトを移動
        local move = cc.MoveTo:create(2, cc.p(400,400))
        sprite:runAction(move)
        
        return true -- タッチ開始時に呼ばれる関数はtrueを返す事
    end

    -- c)タッチイベントで呼ばれる関数を登録
    local listener = cc.EventListenerTouchOneByOne:create()
    listener:registerScriptHandler(onTouchBegan, cc.Handler.EVENT_TOUCH_BEGAN )
    
    -- d)このレイヤーでのタッチイベント取得を有効化
    local eventDispatcher = layer:getEventDispatcher()
    eventDispatcher:addEventListenerWithSceneGraphPriority(listener, layer)

    return layer
end
...
```

b), c), d)が追記部分です。b)がタッチイベント開始時に呼ばれる関数で、c)でその関数をタッチ開始時に呼びだす関数として登録しています。最後にd)でこのレイヤーにおけるイベントの取得を有効にしています。

変更を保存して実行すると、絵が左下に表示され、画面のどこかをクリックすると、ゆっくり右上に移動します。

a)を下記のように変更すると、画面をクリックする度に絵がランダムな座標へ向かって、スッと滑らかに移動します。これはタッチされる度にa)を含むb)の関数が実行されているためです。

```GameScene.lua
...
        -- a)スプライトを移動
        local x = math.random(100,400) -- 100から400の乱数
        local y = math.random(100,600) -- 100から600の乱数
        local move = cc.MoveTo:create(0.3, cc.p(x,y))
        sprite:runAction(move)
...
```

ここで、math.randomはLuaの算術ライブラリ関数の一つですが、その簡単さが感じられると思います。便利な関数が簡単に使えるのもLuaの利点です。

#絵を動かす 絵がタッチされたら移動する
上のコードでは、画面のどこをクリックしても絵が動いていました。では、絵がタッチされたら移動するように変更します。b)の関数内を下記のように変更します。

```GameScene.lua
...
    -- b)タッチイベントで呼ばれる関数
    local function onTouchBegan(touch, event)
        local location = touch:getLocation()

        -- e)タッチ点に絵があるか確認
        if cc.rectContainsPoint(sprite:getBoundingBox(), location) then
            -- a)スプライトを移動
            local x = math.random(100,400) -- 100から400の乱数
            local y = math.random(100,600) -- 100から600の乱数
            local move = cc.MoveTo:create(0.3, cc.p(x,y))
            sprite:runAction(move)
        end
        
        return true
    end
...
```

変数locationには、タッチ点の(x,y)座標が入っています。（location.xおよびlocation.yでアクセスできる）
e)のcc.rectContainsPointは、絵(sprite)の四角い領域にタッチ点(location)が含まれていればtrueを返す便利で利用頻度の高い関数です。これにより、タッチ開始時の点が絵の領域内にあるか確認し、あれば移動するというコードが簡潔に記述できます。

![3-2 move on touch location.png](https://qiita-image-store.s3.amazonaws.com/0/90495/f76a1bcd-8207-6ce2-18bf-2f224a29adf2.png)

サッと移動するアクションを実行した時に絵（スプライト）が非常に滑らかに動き、動きが激しいゲーム開発に向いていることが感じられると思います。

以上が絵を動かすためのアクションと、タッチに反応するためのイベントに関する簡単な説明です。

#今後の予定
ゲーム開発では、タッチされた絵を消して、そこにキラッとした視覚効果を一瞬表示するという振る舞いがよく用いられます。

次回は、表示した絵を画面から削除するアクション、またキラッとした視覚効果を追加するパーティクルについて説明します。