14日目：チュロスから学ぶオブジェクトの生成と削除(後編)：削除

この記事はアドベントカレンダー「[【VCI】テーマパーク を作ろう](https://adventar.org/calendars/5855) 」の14日目の記事です。

# 今回の内容
今回は前回に引き続きチュロスを作りながら以下について学んで行きます。
　・boneとの衝突の検出
　・オブジェクトの削除

# 所有権への対応
## 衝突判定を取得するonTriggerEnter・onCollisionEnter
今回はチュロスを食べたらなくなる(削除される)という挙動を実現していきます。
「食べた」という判定のどう取るかですが、人の頭にはHeadという名前のボーンがついているため、そのボーンにチュロスのコライダーがあたったら「食べた」という判定にします。

オブジェクトの衝突を取得するにはonTriggerEnter・onCollisionEnterを使います。
詳細は以下の公式ページを御覧ください。
　・[VCIイベント関数](https://virtualcast.jp/wiki/vci/script/reference/eventfunction#oncollisionenter)
また、ボーンとの衝突判定時に呼ばれる関数について以前私が記事を書きましたのでそちらも御覧ください。
　・[TriggerとKinematicについて](https://qiita.com/lightjug/items/b085804cc3cc5c08d486)

onTriggerEnter・onCollisionEnterともに第1引数に対象のSubItem名､第2引数にぶつかったものの名前が取れます。
第1引数はSubItemの子オブジェクトがあたってもSubItemが取れるのに対し、第2引数は実際にコライダーが設定されているオブジェクト名なのでご注意下さい。


## Unityの設定
上記をふまえチュロスがHeadボーンにぶつかると消える処理を作っていきます。コードを作成する前にまず、Unity上で設定を変更します。修正点は以下の3点です。

* コライダーレイヤーをVCIAccessoryにする
    * 内容的にVCIItemやVCIPickUpかと思いがちですが、これらは人のボーンが属するHumanoidPartsとの衝突判定がないです(下画像参考)。そのため、ボーンとの衝突があるVCIAccessoryに設定します。Locationやdefaultなどでも多分大丈夫です。
* grabbableをOFFにする
    * 今回はスクリプトからSubItemのサイズの変更を行う処理が登場しますが、grabbableがONの場合は握った状態でスクリプトからサイズを変更することができません。(執筆時点の挙動です。バグかも知れないため変わる可能性あり。)
* isTriggerをONにする
    * 今回はチュロスを物理的にぶつかるものにする必要がなかったのでColliderのisTriggerはONにしました。壁とか人とかにぶつかるようにしたい場合はisTriggerはOFFにしましょう。その場合は衝突時はonCollisionEnterに入ります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/64877/1d844a18-c619-e68e-9fca-ea03f5708f49.png)

以上でUnityでの設定は完了です。

## コードの作成

公式ページを参考に想定の処理をそのまま組むと以下のようになります。

``` lua
function onTriggerEnter(item,hit)
  --名前にChurrosを含むSubItemがHeadボーンにあたったら
  if string.find( item, "Churros_" ) and hit=="Head" then
    local churros = vci.assets.GetTransform(item)
    -- 削除(y座標-500に移動)
    churros.SetPosition(Vector3.__new(0,-500,0))
  end
end
```

しかし、上記コードでは掴んだ状態で食べると手元から消えてくれません。
VCIでは掴んだまま移動しようとしても、掴んだ判定が残っているため移動前の位置に戻されてしまうためです。

上記問題の解決のため、「ボーンにあたったときに見えなくする」⇒「手から放したときに-500に移動する」の2段階で処理を行うように変更します。

見えなくする手段は
　・マテリアルを透明にする
　・サイズを見えないくらい小さくする
などがあります。
今回は後者の方法で対応します。

まずはボーンとあたったときのコードを以下のように修正します

``` lua
function onTriggerEnter(item,hit)
  --名前にChurrosを含むSubItemがHeadボーンにあたったら
  if string.find( item, "Churros_" ) and hit=="Head" then
    local churros = vci.assets.GetTransform(item)
    -- [追加部分]サイズを1/1000にする
    churros.SetLocalScale(Vector3.one*0.001)
    -- 削除(y座標-500に移動)
    churros.SetPosition(Vector3.__new(0,-500,0))
  end
end
```
サイズを0にするとよくない動きをすることがあるらしいので、0ではなく小さい値に設定しています。
掴まない状態で食べることもあるため-500に移動するコードはそのまま残しておきます。

次に放した際に-500に移動する処理を作成します。

``` lua
---[not SubItemの所有権&Grab状態]アイテムをUngrabしたときに呼ばれる。
---@param target string @UngrabされたSubItem名
function onUngrab(target)
  if string.find( target, "Churros_" ) then
    local churros = vci.assets.GetTransform(target)
    -- 放した際にチュロスのサイズが0.5以下になってたら
    if churros and churros.GetLocalScale().y < 0.5 then
      local churros = vci.assets.GetTransform(target)
      churros.SetPosition(Vector3.__new(0,-500,0))
    end
  end
end
```
0.5という数値は適当です。1/1000~1の数値だったら何でも大丈夫だと思います

最後に、出現処理の部分にサイズを戻すコードを追加したら完了です

``` lua
function AppearChurros(sender, name, churrosName)
  local churros = vci.assets.GetTransform(churrosName)
  -- オブジェクトが取得できていて、かつ所有権を持っている場合のみ処理実行
  if churros then
    if churros.IsMine then
    --対象のオブジェクトを出現ポイントの位置に移動させる
      local appearPoint = vci.assets.GetTransform("Churros_AppearPoint")
      churros.SetPosition(appearPoint.GetPosition())
      churros.SetRotation(appearPoint.GetRotation())
      --[追加部分]サイズを1にする
      churros.SetLocalScale(Vector3.one)
    end
  end
end
vci.message.On("appearChurros", AppearChurros)
```


以上で対応は完了です。これで以下のように掴んでるときも掴んでないときも食べることができるようになりました。
![churros-delete.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/64877/68a2c996-225c-7e5e-b101-bc6f5b53a774.gif)


# 終わりに 
いかがでしたでしょうか？
今回は1口で消えるように作りましたが、工夫次第では2口、3口でなくなるものなども作れるかとお思います。
次回の内容は未定です。