[Unity]コイン発射(2Dランチャー)

## <i class="fa fa-cubes" style="font-size:1em;"></i> 概要
Unityでランチャーからゲームオブジェクトを発射させる方法
![デモ動画.gif](https://qiita-image-store.s3.amazonaws.com/0/183676/b01432f2-cfc1-6e93-6814-fe83e6e549e0.gif)

こんな感じでコインを発射させるスクリプトを書いてみました。
<i class="fa fa-cloud-download" style="font-size:1em;"></i> https://github.com/katsuma99/Launcher/tree/master

```csharp:LaunchUtil.cs
using UnityEngine;

public static class LaunchUtils
{
    public static void LaunchItem(ref Transform item, float power, Vector2 vector, float rotation = 0, float torquePower = 0)
    {
        //発射方向を設定
        Vector2 launchVector = Quaternion.Euler(0, 0, rotation) * vector.normalized;

        //Rigidbody取り出す
        Rigidbody2D r = item.gameObject.GetComponent<Rigidbody2D>();
        if (r == null)
        {
            r = item.gameObject.AddComponent<Rigidbody2D>();
        }

        //力を加える
        r.AddForce(launchVector * power, ForceMode2D.Impulse);

        //回転を加える
        r.AddTorque(torquePower, ForceMode2D.Impulse);
    }
}
```


##<i class="fa fa-angle-double-right" style="font-size:1em;"></i> 解説
LaunchItem()の引数にオブジェクトとパラメータを渡すことで力を加えて発射します。


| 項目| 意味|型|
|:---------------|:------------------|:-----|
| item           |発射するオブジェクト |ref Transform|
| power          |発射する力 |float|
| vector         |発射する方向 |Vector2 | 
| rotation   　  |vector方向を基準に回転する角度 |float|      
| torquePower    |オブジェクトを回転させる力 |float|     

####<i class="fa fa-list" style="font-size:1em;"></i> 処理の流れ
　1. 発射する方向を設定
　2. Rigidbody2Dを追加
　3. 発射する力と回転の設定

###<i class="fa fa-cube" style="font-size:1em;"></i> Step1．発射する方向を設定

```csharp
Vector2 launchVector = Quaternion.Euler(0, 0, rotation) * vector.normalized;
```
*vector* : 発射する方向
*power* : 発射する力
*normalized* : 単位ベクトル
　vectorは長さを見ないで、powerで力を決定する。

*Quaternion.Euler(0,0,R)* : Z軸にR分回転する
　方向を決定して、そこから回転して微調整する。
　方向は変更せずに、回転をいじることでランダムな向きに発射できる。

###<i class="fa fa-cube" style="font-size:1em;"></i> Step2．Rigidbody2Dを追加
```csharp
//Rigidbody取り出す
Rigidbody2D r = item.gameObject.GetComponent<Rigidbody2D>();
if (r == null)
{
    r = item.gameObject.AddComponent<Rigidbody2D>();
}
```
*AddComponent()* : gameObjectにコンポーネント（ここではRigidbody2D）追加
　もしRigidbodyを元から設定されてる場合は追加せずに、GetComponent()で取得する。

###<i class="fa fa-cube" style="font-size:1em;"></i> Step3．発射する力と回転の設定
```csharp
//力を加える
r.AddForce(launchVector * power, ForceMode2D.Impulse);

//回転を加える
r.AddTorque(torquePower, ForceMode2D.Impulse);
```
*AddForce()* : 力を加える
*AddTorque()* : 回転を加える
　加る方法は、ForceModeで設定する。

|モード|効果|例|
|:---------------|:------------------|:------------------|
| Force|連続的な力|投げる|
| Impulse|瞬間的な力 |爆発|

##<i class="fa fa-angle-double-right" style="font-size:1em;"></i> ランチャーの作り方
![ランチャーの作成.PNG](https://qiita-image-store.s3.amazonaws.com/0/183676/28036bef-4579-1d1d-7e50-ca7bc1af74c3.png)


エディタからプロパティをいじるれるランチャーの作り方
　1. ランチャーにしたいゲームオブジェクトに以下のスクリプトを追加する
　2. LaunchUtil.csをプロジェクト内に入れる

```csharp:Launcher.cs
using UnityEngine;

public class Launcher : MonoBehaviour
{
    public GameObject item;

    [SerializeField, Range(0, 10)]
    public int power = 1;

    [SerializeField, Range(-90, 90)]
    public int rotation = 0;

    [SerializeField, Range(-90, 90)]
    public float torquePower = 0;

    public void Fire()
    {
        Transform newItem = Object.Instantiate(item, transform.position, Quaternion.identity, transform).transform;
        LaunchUtil.LaunchItem(ref newItem, power, transform.up, rotation, torquePower);
    }

}
```

*Fire()* : コイン発射
　コイン以外にも、ランチャープロパティのItemにゲームオブジェクトを指定すると好きなものを発射できる。

### <i class="fa fa-info-circle" style="font-size:1em;"></i> 一定間隔でコイン発射
一定間隔でコインが発射されるように作ってみました。
　1. 空のゲームオブジェクトLauncherManagerを作成しする
　2. LauncherManagerに以下のスクリプトを追加する
　3. LauncherManagerの子に作成したランチャーを追加する

```csharp:LauncherManager.cs
using UnityEngine;

public class LauncherManager : MonoBehaviour
{
    [SerializeField, Range(0, 10)]
    public float mTimeOut = 1;

    public int mItemCountMax = 10;
    float mTimeElapsed = 0;

    void Update()
    {
        mTimeElapsed += Time.deltaTime;
        if (mTimeElapsed >= mTimeOut)
        {
            foreach (Transform launcher in transform)
            {
                launcher.GetComponent<Launcher>().Fire();
                if (launcher.childCount > mItemCountMax)
                {
                    Destroy(launcher.GetChild(0).gameObject);
                }
            }
            mTimeElapsed = 0.0f;
        }
    }
}
```
*mTimeOut* : 発射する間隔

## <i class="fa fa-thumb-tack" style="font-size:1em;"></i> ゲームを作ってみた
[![使用例.gif](https://drive.google.com/uc?export=view&id=0B_v5rHiNSeseMDZpQjIyMDljUUU "使用例.gif")](https://www.youtube.com/watch?v=PryO-sxYbkw)

- 色々なオブジェクトを色々なランチャーから発射する
- 発射する方向をランダムに変える
- オブジェクトをタップできるようにする

<i class="fa fa-cloud-download" style="font-size:1em;"></i>　android → https://play.google.com/store/apps/details?id=com.secretcommandlab.taptapdrop 
　　iOS → https://appsto.re/jp/fMfpjb.i




##<i class="fa fa-book" style="font-size:1em;"></i> 参考資料
- [[Unity] Prefab: 弾を発射する | Unity 3DCG
](https://unity3d.sakura.ne.jp/unity/prefab.html)
- [【Unity】スマートボールぽいものを作ろう！ - ④isTriggerとOnTriggerEnter - Exception[0]
](http://acguychan.hateblo.jp/entry/2014/09/10/070744)
- [RigidBodyにAddForce()を行った場合のForceModeによる動作の違い - 強火で進め
](http://d.hatena.ne.jp/nakamura001/20120320/1332224186)
- [UnityのRigidbodyとColliderで衝突判定 - Qiita
](http://qiita.com/yando/items/0cd2daaf1314c0674bbe)