HeliScriptでアイテムをまっすぐ動かす【コピペで使えるサンプルコード付き】

:::note info
本記事は、[HeliScriptでリッチなアスレチックワールドを作ろう！【コピペで使えるサンプルコード付き】](https://qiita.com/IwahanaFuku/private/63e6bbca2bc1f13ed57e)の記事の一部です

VR法人HIKKYのorganization下のQiita/Zenn両方に投稿しております。
:::

## はじめに
かなり前置きが長くなってしまいましたが、ここから実際にHeliScriptを書いて実行してみましょう！
本記事ではアイテムをまっすぐ動かすためのcomponentを作っていきます。このcomponentは、プレイヤーが接触するとゲームオーバーになるためのマグマに使用するほか、他のギミックにも使用できそうなので、Y軸方向に上るだけではなく、Vector3型でvelocityを設定することで、方向と速度を設定できるようにします。

![2024-03-26 11-22-08_2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3629942/55037528-263b-4e0b-aa29-d7ee696b716b.gif)

**Unity設定画面**

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3629942/6c52757e-ed61-8693-fe4a-f49e720e9bbe.png)

**コード全文**
```C#:ItemMove.hs
component ItemMove
{
    Item m_item; //コンポーネントがセットされたItemを取得する
    
	Vector3 m_velocity; //移動する方向と距離

    public ItemMove()
    {
        m_item = hsItemGetSelf(); //コンポーネントがセットされたItemを取得する

        //コンポーネントがセットされたItemのvelocity(Vector3)というプロパティを取得する
        m_velocity = StrToVector3(m_item.GetProperty("velocity(Vector3)")); 
    }

    //毎フレーム呼びだされる。
	public void Update()
	{
        MoveItem();
	}

    //m_velocityに設定した速さを、現在のItemの位置に足す関数
    void MoveItem()
    {
		Vector3 pos = m_item.GetPos();
		pos.Add(Vector3MulFloat(m_velocity, hsSystemGetDeltaTime()));

		m_item.SetPos(pos);
    }

    //String型をVector3型に変換する関数
    Vector3 StrToVector3(string str)
    {
        Vector3 result;

        list<string> strVec = str.Split(",");
        result = makeVector3(strVec[0].ToFloat(), strVec[1].ToFloat(), strVec[2].ToFloat());
        return result;
    }

    //Vector3型とfloat型の掛け算を行う関数
    Vector3 Vector3MulFloat(Vector3 vec, float f)
    {
        Vector3 result;
        result = makeVector3(vec.x * f, vec.y * f, vec.z * f);
        return result;
    }
}
```
## HEO Object
HEO Objectコンポーネントは、Actionや、HeliScriptでモデルを動かしたいときには必ず使用しなければならないコンポーネントです。
Vket Cloudで、3Dモデルを表示しようとした際には、HEO Fieldと、HEO Objectのどちらかを使用する必要がありますが、HEO Fieldで3Dモデルを書き出してしまうと、動かないStaticなものとして扱われてしまいます。

よって、3Dモデルを動かしたい際は、HEO Objectを使用する必要があるのですが、HEO Objectを使うには、一度3Dモデルを、.heo形式というVket Cloud特有の3Dモデル用フォーマットに手動で変換する必要があります。

.heoファイルを書き出すためには、
1. 書き出したいゲームオブジェクトのトランスフォームをリセットする
2. VketCloudSDK > フィールドをエクスポートを行う
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3629942/1af32a02-e348-2bbd-8afc-5ada93135293.png)

ことで、書き出すことが出来ます。

:::note info
CubeやSphereなどの単純な形状であれば、Hierarchy上で右クリックし、3Dアイテムの項目を開くことで、シーン上に追加することが出来ます。
プロトタイプなどに使用する場合は、こちらを使用すると便利です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3629942/4951992d-21f2-6634-ec6a-e03dfa5fa5cd.png)
:::

## コード解説
### メンバ変数の宣言とコンストラクタ
```C#
    Item m_item; //コンポーネントがセットされたItemを取得する
    
	Vector3 m_velocity; //移動する方向と距離

    public ItemMove()
    {
        m_item = hsItemGetSelf(); //コンポーネントがセットされたItemを取得する

        //コンポーネントがセットされたItemのvelocity(Vector3)というプロパティを取得する
        m_velocity = StrToVector3(m_item.GetProperty("velocity(Vector3)"));
    }
```
HeliScriptはメンバ変数の宣言と同時に初期化することは出来ないため、コンストラクタの中で初期化を行う必要があります。

#### Itemクラスの初期化
Itemクラスには、シーン上のItemを取得するための関数として、`hsItemGet(string itemName)`と、`hsItemGetSelf()`の二つがあります。
それぞれの使い分けとして、`hsItemGet(string itemName)`は、マネージャークラスといった複数のアイテムを操作するような全体統括をするコンポーネントに使用する。
`hsItemGetSelf()`は、一つのItemに対してのみ作用する、シーン上に複数配置するような一つの機能に使用する。
といった使い分けをしましょう。

:::note info
複数のItemで構成される、シーン上に複数配置するようなギミックを作りたい場合は、アクティビティとして一つにまとめると取り回しやすくなります。
アクティビティ内でItemを取得するためには、`hsItemGetOwnScene(string itemName)`といったアクティビティでのみ使用する特殊な関数を使用します。
:::

#### m_velocityをpropertyから設定する。

```C#
    //String型をVector3型に変換する関数
    Vector3 StrToVector3(string str)
    {
        Vector3 result;

        list<string> strVec = str.Split(",");
        result = makeVector3(strVec[0].ToFloat(), strVec[1].ToFloat(), strVec[2].ToFloat());
        return result;
    }
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3629942/453dd0df-df51-dc7b-bdbf-b97945e1df58.png)

Propertyからはstring型のkeyとvalueしか受け取れないため、string型の入力値をVector3型に変換する関数を自前で用意する必要があります。

intやfloat型であれば、それぞれのstringクラスに[string.ToInt()](https://vrhikky.github.io/VketCloudSDK_Documents/12.3/hs/hs_string.html#toint)、[string.ToFloat()](https://vrhikky.github.io/VketCloudSDK_Documents/12.3/hs/hs_string.html#tofloat)関数が用意されているので、そちらを利用します。

:::note info
好みにもよりますがPropertyのKeyにValueとして与えたい型の名前を設定しておくと、Unity側でどんな値を設定できるのか明示できるようになります。
:::

:::note warn
今回の`StrToVector3(string str)`関数は簡易な関数ですが、より大規模な開発になる際は柔軟に入力値を受け付けられるようにしたり、不正な入力値をハンドリングして適切なエラーをプリントすることを推奨します。
:::


### 実際に動かす

```C#
    //毎フレーム呼びだされる。
	public void Update()
	{
        MoveItem();
	}

    //m_velocityに設定した速さを、現在のItemの位置に足す関数
    void MoveItem()
    {
		Vector3 pos = m_item.GetPos();
		pos.Add(Vector3MulFloat(m_velocity, hsSystemGetDeltaTime()));

		m_item.SetPos(pos);
    }

    //Vector3型とfloat型の掛け算を行う関数
    Vector3 Vector3MulFloat(Vector3 vec, float f)
    {
        Vector3 result;
        result = makeVector3(vec.x * f, vec.y * f, vec.z * f);
        return result;
    }
```

componentとして作成したスクリプトをItemに設定することで、毎フレーム呼び出されるUpdateを使用することが出来るようになります。

:::note warn
逆に言うと、componentとしてItemにアタッチしないとUpdate関数が呼び出されることはありません。Update内に入れたら必ずUpdate関数が実行されるわけではないので注意しましょう。
:::

`Update()`関数内で、`MoveItem()`関数を呼び出しています。
`MoveItem()`関数は、現在のItemの位置に、propertyから取得した`m_velocity`と、`hsSystemGetDeltaTime()`という、前回のUpdateから何秒経過したかの値が返す関数をかけて、現在の位置に足し合わせる関数です。

これによって、現在の位置から、このフレームで実際に移動させたい距離を足すことが出来るようになります。

:::note info
Update関数は毎フレーム呼ばれる関数なので、FPSが低ければ低いほど移動距離が少なくなってしまいます。
また、モニターのリフレッシュレートによりFPSが多少変化(50~70)するため、それによる動作の違いが発生しないようにします。

VketCloudのFPSによる処理の違いは、[【VketCloud】その壁の設計、抜けられますよ](https://magazine.vket.com/n/na670c53bd2c6)にも記載があります。
:::


[Vector3.Add()](https://vrhikky.github.io/VketCloudSDK_Documents/12.3/ja/hs/hs_struct_vector3.html#addvector3)関数は使い方に少し癖がありますが、C#的な書き方をすると、
```C#
pos += m_velocity * hsSystemGetDeltaTime()
```
と同じように扱えます。

ただ、HeliScriptでは、Vector3 * floatを直接行うことが出来ないので、`Vector3MulFloat(Vector3 vec, float f)`関数を作成しています。

 **前 :** [HeliScriptを扱う上での事前設定＆Tips](https://qiita.com/IwahanaFuku/private/8cf9f74a7b2dff5d93d9) 
 **次 :** [HeliScriptでアイテムを反復して動かす【コピペで使えるサンプルコード付き】](https://qiita.com/IwahanaFuku/items/dfc38371ad0ed7cc034d)