Unity3D+IK(Inverse Kinematics)のAnima2Dチュートリアル

Blogをいつもご覧いただきありがとうございます。

前回は「Unity3D+Anima2Dチュートリアル」というテーマの記事を投稿しました。

今回はAnima2dのInverse Kinematicsについて説明したいと思います。

Inverse Kinematicsとは何ですか?

Anima2Dには、Inverse Kinematicsのコンポーネントがあります。これを使い、親関係のボーンオブジェクトの子供を動かすと、親も連動し動きます。

例を挙げると、腕と肩の関係のようなものです。(以下省略”IK”です)。

シンプルなアニメーションは、ボーンをいじるだけで充分ですが、もしアニメーションが複雑な場合はかなり時間がかかると思います。

そういう場合は「IK」が便利です。移動させたいボーンを「IK」と繋げればこのボーンのチェーンを丸ごと動かすことができとても便利です。

 

IKの種類は?

 

Anima2DのIKには,IK CCDIK Limb という2種類のIKがあります。

IL Limbは骨を2本しかコントロールできません、余弦定理ですので、今回の場合手足に利用します。

IK CCD は設定に応じて、最大コントロールできる本数がルートボーンまでの全部の骨をコントロールすることができます。今回の場合頭と尻尾に使います。

 

では、前回の引継き、IKの使い方を説明します。
IKをの使い方を説明する前に、先ずAnima2Dの効率をアップでさせる機能を紹介したいと思います。

「PoseManager」というものです。

使い方はとても簡単です。下記の画像のように、前回の「牛」のオブジェクトに「Pose Manager」を入れれば、使えるようになるはずです。

そして、「Create new pose」をクリックしたら、今のスプライトのポジションとローテーションがセーブできます。

一つの「Idle」のポーズを「Save」をクリックしてから、後はどんな調整しても、ただ「Load」ボタンをクリックしたら、最初設定のポーズに戻れます。(ちなみに、「Save」はオーバライドしますので、ご注意ください。)

「Pose Manager」の使い方はここまでです。

それでは、「IK」の使い方の説明に入りましょう。

Step 1: IKをクリエイトします

「牛」のオブジェクトの中に、もう一個の空のオブジェクトを作って、名付け「IK」です。

下記の画像のようにそのオブジェクトに右クリックして、「2D Object」→「IK Limb」をクリックしたら、「IK」が出ます。

では、「IK」のパラメータを説明しましょう。

  • Record:アニメーションモードの間,ボーンのキーフレームを記録します。
  • Target: IKが適用されるボーン。
  • Weight:​IKのポーズに対する影響度。
  • Restore Default Pose: 計算を実行する前に最初のポーズを設定します。
  • Orient Child:ターゲットの子ボーン(使用可能な場合)をIKローテーションに回転させます。
  • Num bonesIKの影響を受けるボーンの数.最大はルートボーンまで。
  • Iterations solverの反復回数。
  • Dampingソルバのステップ速度を制御する.値が小さいと変化が見やすい,大きいと変化が見にくいです。Dampingの値が大きければ、もっと自然に見えるかもしれません。

 

Step 2:「IK」をコントロールしたい関節に配置します

下記の画像のように、三つの「IK」をクリエイトして、分かりやすい名前を付けてから、それぞれにコントロールしたいところに置いてください。

上記の説明の通り、「頭」の部分には、使っているのはIK CCDです。

お気付きだとおもいますが、このグレーのリングを自分が望んでいる所に配置しても、スプライトはまだコントロールできません。

なぜかというと、下記の画像表示の通りに、右側の「Inspector」の「Target」はまだ「None」になっていますので、コントロールできるオブジェクトはまだありません。

では、「Target」に相応の「Bone」オブジェクトに入れてみてください。

設定が終了したら、グレーのリングは青のリングに変わります。

では、下記の画像の手順通りにすれば、左側のコントロールしたい「IK」のオブジェクトをクリックして、右側のリングを移動したら、「牛」全身が一緒に動きます。

注意点:偶にリングを移動しても、欲しい角度に合わせられない場合があったら、下記の画像の状態で「IK」の「Inspector」の「Filp」のチェックを入れてから、もう一度調整すれば、合わせられると思います。

適用後の図:

これで、「IK」のリングを弄れば、簡単に関節が調整できるようになりました。

複雑なボーンが入っているスプライトでは、「IK」はとても役に立ちます。

今回のインバース キネマティクス(IK)の使い方はここまでになります。

では皆さん、次回の内容をご期待ください!

Unity+Myo(ジェスチャーを活用して牛乳を搾るゲームを作りました)

Blogをいつもご覧いただきありがとうございます。先日「Myo」のジェスチャーでゲームを作ってみましたので今回はここでジェスチャーの使い方を紹介しようと思います。

下記のURLはゲームの映像です。
https://www.youtube.com/watch?v=4Jz7y1n3Iec

· Myoってどんなもの?

Myoアームバンドは、腕、手首、指のジェスチャーで、デバイスをワイヤレス操作することができます。

下記のURLはMyoの公式サイトです。
https://www.myo.com

· Myoのジェスチャーの紹介

デフォルトで認識するプリセットジェスチャーは下記のとおりです。

· グー(Fist)
· パー(FingersSpread)
· ダブルタップ(DoubleTap)
· 手首で手を左に仰ぐ動作(WaveIn)
· 手首で手を右に仰ぐ動作(WaveOut)
· リラックス(Rest)

「グー」と「パー」を合わせて、モミモミすることができそうなので、私はこの二つのジェスチャーを利用して牛乳を搾るゲームを作りました。それでは、ジェスチャーの部分に入りましょう。

· sdkの導入

環境状況:
Unity2018.1.0f2
SDKバージョン:Windows SDK 0.9.0
Firmware: 1.5.1970
https://developer.thalmic.com/downloads
SDKを持っていない人は上記のサイトからダウンロードできます。

SDKをダウンロードして、Unityにインポートしましたが、エラーが三つ出ました。

エラーが発生しているスクリプト(ColorBoxByPose)をチェックしたら、レンダリングの設定の書き方が古すぎますのでUnity2018.1.0f2(恐らくUnity2017以降のバージョン)では、書き方を変える必要がありますね。

では、そこの書き方を変えましょう!

上記のように修正してエラーが消えるはずです。

次はMyoをコントロールするために、SDKが用意してくれたプリハブをシーンに入れます。

サンプルシーンの中で「Joint」というGameObjectがあります。このGameObjectに存在するスクリプト(JointOrientation)がMyoデバイスの方向を管理しています。これをプリハブにして、自分のシーンに適用します。

方向を制御するスクリプトできたので、次はジェスチャー検出のコードですね。

それでは、ジェスチャー検出用のスクリプトを作りましょう。

そのオブジェクトに自分が作った「gManager」を入れて、ジェスチャー検出のコードを全部このスクリプト内に記述することにします。

これで、SDKのプラグインの導入が完了しました。

· ジェスチャー検出

例:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Pose = Thalmic.Myo.Pose;
public class GestureManager : MonoBehaviour {
Public GameObject myo;
ThalmicMyo thalmicMyo;
void Start () {
  thalmicMyo = myo.GetComponent<ThalmicMyo>();
 }
void Update () {
  Fist();
  Stroke()
}
//ジェスチャーは「グー」の時
void Fist()
 {
   if(thalmicMyo.pose == Pose.Fist)
   {
   /*この部分は「グー」の処理の内容
   (牛乳を搾る機能を埋め込みました)
   */
   }
 }
//ジェスチャーは「パー」の時
void Stroke()
 {
  if(thalmicMyo.pose != Pose.Fist || thalmicMyo.pose == Pose.FingersSpread || thalmicMyo.pose == Pose.Rest)
  {
  /*この部分は「パー」の処理の内容
  (ここで手を離す機能と牛を撫でる機能を埋め込みました)
  */
  }
 }
}

「撫でる」機能は正確に言うと「パー」かリラックスの状態で手首や腕を振るという動作です。
上記のコードの通りにvoid Stroke()関数の中にMyoのジャイロの処理を埋め込めば「撫でる」ができます。

例:

void Stroke()
{
  if (thalmicMyo.pose != Pose.Fist || thalmicMyo.pose == Pose.FingersSpread || thalmicMyo.pose ==Pose.Rest)
  {
   if (thalmicMyo.gyroscope.magnitude > 120f)
     {
       //gyroscopeのmagnitudeは120より大きい場合
      //(速く腕を振ると簡単に120を超えます。)
     }
    else if (thalmicMyo.gyroscope.magnitude < 10f)
     {
      //gyroscopeのmagnitudeは10より小さい場合
     //(腕が静止に近い場合)
     }
  }
}

ここまではもう方向変更と簡単な「グー」と「パー」の処理が実現できるようになりました。でもMyoのもう一つのスクリプト(ThalmicMyo)の内容をみていきましょう。

· ThalmicMyo

ThalmicMyoはMyoのSDKの中でコアの部分です。

下記に主要な変数名を説明します。
· ArmSynced:boolタイプの変数で、trueになったらMyoデバイスが検出できます。
·arm:左の腕と右の腕どちらかと設定できます。
·pose:Myoが検出したジェスチャを保存します。UnKnowは今のジェスチャーです。
·accelerometer:加速度の計算用のVector3タイプの変数です。約9.8 m/s^2です。
·gyroscope:今のジャイロの軸のスピードを検出できます。単位は「度/秒」
·isPaired:trueの時にMyoのデータが読み込めます。
·Vibrate:Myoが提供しているバイブレーションタイプです。三つの種類があります。

public enum VibrationType { Short, Medium, Long }

バイブレーションの書き方は下記の通りです。

例:

using VibrationType = Thalmic.Myo.VibrationType;
if(thalmicMyo.pose == Pose.Fist)
{
  thalmicMyo.Vibrate(Vibrate.Short);
}

上記の「撫でる」機能はThalmicMyoの変数を利用して実装してみました。

· 実装して気づいたこと

1.実装してみて素早いジェスチャでは認識までに若干のディレイをかんじました。デバイスの特性上仕方がない点かとおもいますが、頻繫にジェスチャーを素早くおこない操作するゲームはわりと不向きかもしれません。

2.Myo Connect(Mac/Windows上のデフォルトマネージャー)をつかってキャリブレーションを行ったほうがやはり操作感が向上します。(PC用にビルドしたアプリのみで利用可能)

3.キャリブレーションをする時にゲームをする際と同じ腕のポジションでキャリブレーションするとジェスチャの認識向上におすすめです。

4.UnityでAndoroid用のビルドをためすために、有志の方が開発したandroid+UnityのSDKのGitHubにアップされたパッケージを利用してためしました。

ただ、Myo Connectのような、マネージャーソフトがない為キャリブレーション、個人のプロファイルの設定ができないの理由で、腕の方向やコントロール精度は満足いくものにはなりませんでした。

Unity3Dタイルマップ作成時の注意点

Unity3D has a tile map system that allows you to make 2D maps with no programming at all. This tool is available for free with the unity base package and can be expanded with the 2D extras package found in unity’s GitHub. It’s fairly easy to use but if you are not careful when setting it up you could have a hard time.  

Unity3Dのタイルマップはプログラミングなしで簡単2Dのマップを作れるツールです。このツールはUnity3Dのベースパッケージに入ってて、UnityのGitHubにある2D-extrasのパッケージで機能拡張できます。使いやすいものですがセットアップで間違えると痛い目に会います。 

On this post I will be going through a couple details that you should take in account when making your tile map. 

このポストでは、タイルマップを作っている時の4つの注意点をあげます 

1.スプライトシート 

Tiles usually come in sprite sheets. A sprite sheet is an image containing a series of smaller images most commonly of the same size and organized in columns and rows. 

普段はタイルがスプライトシートにあります。スプライトシートというのは小さくて同じサイズの複数のイメージが含められているのイメージをさします。 

After importing a sprite sheet into your project. Unity allows you to divide the sheet into individual tiles. To do this you click on the sprite sheet and look at the inspector, the texture type should be “Sprite (2D and UI)” and the sprite mode set to “Multiple”. To start the division process click on the Sprite Editor button. During this process there are a couple factors you should take in account: 

Unityにインポートをして選択されたままにInspectorで複数のイメージにスライスが可能です。このプロセスに注意点が二つあります。 

  • Pixels per unit :  Before even going into the Sprite Editor make sure that the value of the “Pixels Per Unit” parameter on the inspector is the same size of your tiles. E.g: if your sheet is holding 64×64 px tiles then make the “Pixels per unit” 64. If you forget this step your tiles will have padding or overlap each other. 
  • Pixels Per Unit: 「Sprite Editor」に入る前に「Pixels Per Unit」のパラメータがタイルのピクセルサイズと同じにしないといけません。例えばスプライトシートに64px✖64pxのタイルが入ってたら、「Pixels Per Unit」を64に設定してください。設定が違うとパディングがはいったり、タイルが重なったりします。
  • Pivot: When using the slice tool in the Sprite Editor. Make sure to set the pivot to “center”. If you miss this step the tiles will be offset from the grid in the scene.
  • Pivot: スライスツールを作っているときに、「Pivot」のパラメータが「Center」を選択しないと、タイルがシーンのグリッドからオフセットされます。 

2.コライダー 

Sprites are just the visual part of our tiles. Without colliders, even if we can see the ground, our characters would just fall off the world. Unity made it very easy to add colliders to your grid. Just select the tilemap and add a “Tilemap Collider 2D” component to it. This is fast and easy but it creates a collider for every tile with a sprite on it. This means that even tiles surrounded by other tiles that will never be in contact with anything will also have a collider. I.e: A lot of unnecessary colliders that will never be used and use resources are being created. 

スプライトはタイルの見た目だけのものなのでコライダーを付けないと、床を見えても、キャラクターが突き抜けて落ちます。コライダーを付けるのは簡単にできます。Tilemapのオブジェクトに「Tilemap Collider 2D」というコンポーネントを付けることで付けますが、これで全てのタイルにコライダーが適用されてしまいます。言い換えるならば一回も使わない無駄なコライダーが生成されてリソースを余分に使っています。 

 

To prevent this, we can add an other component. The “Composite Collider 2D” component. This component requires a little bit of setup. When this component is added to your tilemap GameObject, it automatically adds a RigidBody2D component to the object. If you are adding collision to static objects like the ground or a wall, make sure to set the “Body Type” of the RigidBody2D component to “Static” or it will fall down with gravity. Now go back to your “Tilemap Collider 2D” component and tick on the “Used By Composite” box. This will merge you colliders leaving only the outer colliders. 

これを防ぐためもう一個のコンポネントを付けられます。「Composite Collider 2D」というコンポネントです。追加するときに自動でRigidBody2Dが追加されます。もし動かない物のコライダーを作っているときに(床、壁、など)RigidBody2Dの「Body Type」を「Static」にしないと重力で落ちます。最後に「Tilemap Collider 2D」の「Used By Composite」を選択することで内側の無駄なコライダーがなくなります。

 

3.Rule Tiles: 

Rule tiles are part of the “2D extras” package you can find in Unity’s GitHub (https://github.com/Unity-Technologies/2d-extras).  

UnityのGitHubの”2D-extras”のパッケージにRule Tilesという物があります。(https://github.com/Unity-Technologies/2d-extras).  

This tiles can save you a lot of time when map designing, by allowing you to create a set of rules for which sprite is displayed depending on the tiles around it.  

このタイルのルールを設定するとマップをつくる際にタイルのスプライトを周りにあるタイルを見て設定されるので、これレベルデザインの時間を節約できます。 

 

Rule tiles also make it easy to create tile animations. 

そして、タイルアニメーションもつくれます。 

 

One thing to take care of when setting up this rules is the order you add them to the list. When unity is checking your list of rules it stops and selects the first sprite that fulfills the rule. So if you have a more specific set of rules after a very general one, it might be ignored. 

ルールを設定するときの注意点はルールの順番です。Unityがチェックするたびに先にルールに一致するスプライトが選択され、残っているルールを無視します。つまり、幅広いルールを持っているスプライトの次に細かいルールを適用するものがあった場合、幅広いルールに合致して、細かいルールが無視される可能性が高いです。 

 

Getting the tiles to work as you intend them to, might take some time but once you have it set up, it will speed up your map making time. And if you decide to change a sprite midway through the map design, you can just change the sprite for that rule without having to touch the tiles in the scene. A good rule of thumb is to keep the tiles with very specific rules at the top of the list and the more general ones at the bottom. And remember you can drag the rules up and down within the list to change the order easily. 

思った通りに設定するには時間がかかるかもしれませんが、一度設定したら、マップ作りがスピードアップします。そして途中でタイルのスプライトを変更したい場合もシーンにあるタイルを作り直しは必要ないです。そのルールのスプライトを変更することで済みます。経験を積んだら設定時間も減ります。ヒントとしては細かいルールを幅広いルールより先に付けること。リスト内での順番がドラッグで簡単に変更できます。 

4.レイヤー: 

Layers are powerful tools that help us keep rendering orders separate, make pretty overlaps and set colliders to some objects while ignoring others. But it’s important you keep track of the layer you are working on at all times, because just as any other software that uses layers like Photoshop or Gimp, editing the wrong layer will cause you problems. So if you run into some weird behavior like colliding into clouds, falling through the ground or tiles not animating correctly, make sure you check everything is on the right layer. To help you with this Unity has an option to gray out all layers except the one you are working on. This option can be turned on by changing the “Focus On” parameter located on the Scene window to “Tilemap.  

レイヤーは非常に便利なツールでレンダリング順を設定するのに役立ちますが、PhotoshopやGimpのように間違えたレイヤーに間違えたタイルを入れるミスは起こりやすいので気を付けないといけません。雲にぶつかったり、床を突き抜けたり、タイルアニメーションが変になったりしていた場合は、レイヤーに正しくアサインされているかの確認をおすすめします。レイヤーに関するトラブルを防ぐためにUnityには変更中のレイヤー以外のレイヤーをグレーアウトする機能を持っています。シーンにあるの「Focus On」パラメータを「Tilemap」に変更することで起動されます。 

Stingray(VRテンプレート)の持ち上げ処理を調べてみる
(離す処理)


前回、ついに『持ち上げる処理』の実装を全て見終えました。
しかし、これまで見た処理はあくまで『持ち上げる』というだけの処理です。

今回は、『持ち上げたものを離す』処理を最後まで見ていきます。



■ Un-link – Release



赤の部分は『トリガーが離された時』に実行されています。
画像だとやや見づらいので、
この画像を更に黄色・オレンジに区切って詳細に見ていきます。

①離したコントローラがリンクされているかチェック



まずは、持ち上げている状態かどうかを表す変数『is_linked』
true(持ち上げている状態)なのかをチェック、
『ユニットを持ち上げているコントローラ』『トリガーを離したコントローラ』が同一かもチェックします。

②コントローラとのリンクを外し、加速度を設定する



続いて、『SteamVR Unlink Node From Tracker』ノードで
ユニットとリンクしている対象(コントローラの持つ持ち上げ関数)とのリンクを外します。
その後は『SteamVR Set Actor Kinematic』で自由に動かせないようにします。

直後の『Set Actor Velocity』ノードには
前々回に登場した変数『wand_velocity』の値をセットしています。

『Set Actor Velocity』ノードは引数のユニットのアクタに対して引数の分だけの速度を設定します。

変数『wand_velocity』はコントローラの持つ加速度を表しているため、
離した時点での加速度がそのままユニットの速度になっているということになります。

加速度の設定が終わったら変数『is_linked』をfalseに変更、
ユニット自身の『Unlinked』イベントを実行しています。

『持ち上げたものを離す』という処理はこのように実装されていました。

一応、この先にもいくつか処理が残ってはいますが、『離す』処理はここで完了です。



■ Hide – Unhide the Controller



ここでの処理は『物を離した後、コントローラを可視状態にする』というものです。

これはVRテンプレートのバットのユニットフローを見ないとわからないのですが、
一部のユニットは『linked』イベントの処理で
『コントローラを不可視にする』
という実装がされています。
ここで可視状態にするという処理を行っていない場合、
バットを離した後でもコントローラが見えないままという問題が発生するため、
この実装が行われています。

ちなみに、ここで使用されている『Set Unit Visibility』は以前使用した時とは異なり、
ユニットそのものを引数で設定しているため、ユニット全体の可視・不可視を変更できています。



■ set_invisable



その下にある『Event for Hiding the Wand』から続く処理は
『External In Event』ノードから始まる、独立したイベントです。

先ほどの説明で出てきた『コントローラを不可視にする』という処理はここで行われています。
つまり、
コントローラによってバットが持ち上げられる
→バットの持つlinkedイベントが実行される
→バットのlinkedイベントの中でコントローラのset_invisableイベントが実行される
という処理の流れになっています。

一旦両方のコントローラを可視状態にしてから、
不可視に設定するコントローラだけ不可視にしています。
使用しているノードは可視の時から変わりません。



以上で、コントローラの持ち上げ処理は全て見終えることができました。
残っているコントローラ関連の処理はテレポートのみとなります。
残念ながら、StingrayのVRテンプレート調査はこれで終わりですが、
ここまで基礎を理解することができれば、
きっとテレポートの処理を理解することも簡単だと思います。

今まで、ありがとうございました。

Stingray(VRテンプレート)の持ち上げ処理を調べてみる
(持ち上げ編)


今回も引き続き、『物を掴む処理』を見ていきます。
次回を含め、覚えることが盛りだくさんです。



画像の中の青い部分は前回にやった『物に触れている間の処理』です。
緑の部分はまだ特に触れてはいませんが、
基本的にいつも通りの入力(トリガー)を拾う処理の為、割愛します。



■ 状態のチェック

コントローラのトリガーを引いた際にオレンジの部分の処理が行われます。



ここでは、触れている物の状態をチェックし、『持ち上げることができるか』を判定しています。

◯ Is the Wand Touching an Object?

最初に、変数『wand_is_touching』の値で『Branch』ノードを実行しています。
この変数は前回の『Physics Trigger』の処理で何かに触れている時にTrueに変更されています。

つまり、『何かに触れているか』をチェックしています。

◯ check for no pick up in unit data

Trueならば今度は変数『touching_unit』の値が持つ『pick_up』のデータと『no』を
『Compare Objects』ノードで比較しています。

『Compare Objects』ノードは、A・Bに渡された値が同じであるかどうかを返します。

まとめると、ここでは
『触れているユニットが持つ持ち上げられる物体かどうかのデータを見て、その内容がnoであるかどうか』
をチェックしています。

◯ Is the Actor Dynamic?

上記処理で等しくなかった(noではなかった)場合、
『Is Actor Dynamic』ノードの結果がTrueであるかという処理を行っています。

『Is Actor Dynamic』ノードは、『Actor』に指定された物体が動的であるかどうかを返します。

つまり、『持ち上げようとしている物体が動かせるものか』という確認になります。

ここまでの処理で、『物体を持ち上げるまでの確認』が完了しました。



■ Attach the Object to the Wand



続いて、物体を持ち上げる処理を見ていきます。
画像の中の黄色のエリアですが、
かなり量が多いので幾つかのグループに分割して処理を見ていきます。

①対象を動かせるようにする



まず、『SteamVR Set Actor Kinematic』を使用して、対象を自由に動かせるようにします。

②スナップをきかせるかどうかをチェック



続いて、現在触れているユニットがスナップをきかせるような物(バット)であるかをチェックするために、
触れているユニットが持つ『snap』というスクリプトデータが『yes』かどうかをチェックしています。



『snap』が『yes』である場合、
『preserve_world』をFalseに変更し、
ユニットのローカル位置とローカル回転を0に変更しています。
こうすることで、どんな状態の物を拾っても必ず同じ位置、同じ向きに向くようになります。

『snap』が『yes』以外であった場合、
『preserve_world』をTrueに変更します。

どちらの場合でも終了後は次の処理に遷移します。

③リンク付けを行う



次は『SteamVR Unlink Node From Tracker』を使用して、
現在手に触れている物のリンクを外しています。

その後、コントローラに対してユニットのリンク付けを行います。

④各種イベントの実行と変数の設定



最後に、リンク付け後に必要な処理を行っています。
コントローラがリンク中であるかを示す変数『is_linked』をTrueにしてから
『Sequence』ノードに続いています。
『Sequence』ノードは上から順に繋げられた処理を実行するというものです。
実装に必須な処理というわけではありませんが、
『Flow』の可読性向上に役立つことが多いです。

持ち上げたユニットの『pickup_sound』イベントの実行、
持ち上げられたユニットにコントローラの情報をセット、
持ち上げたユニットの『Linked』イベントの実行、
持ち上げたユニットの『hilight_off』イベントの実行。
という順に行っています。

こうすることで、『対象を持ち上げる処理』は実装されています。
しかし、これだけではまだ『対象を手放す』事はできません。



次回は、『対象を手放す処理』を見ていきます。

UE4のVRテンプレートを利用してミニゲームを作ってみよう!(一応の最終回)

この記事は以下のような方を対象としています。
——————————-
・VR機器を持っていて、UE4でとりあえず使ってみたい方
・UE4での経験がまだ浅い方
——————————-

前提のスキルとして
——————————-
・UE4のエディタの操作方法がわかる
——————————-
があればOKです。

また、先に前回前々回の記事を読んでから、この記事を読み始めていただきたいです。
 
こんにちは、名残惜しいですが『パンチングゲーム制作』は今回で一旦の最終回です。
最後までしっかりやっていきましょう!

さて、前回まででは
『敵のBPの追加』
『敵のパラメータを設定』
『敵の移動処理』
『敵が死亡したら消える処理』
をやってきました。
 
今回はついに
『攻撃時に敵を死亡させる処理』
『プレイヤーが敵に攻撃する処理』
『レベルそのものの設定』
『プレイ中に敵をスポーンさせる処理』
『出来上がったものを試しにプレイ』
をやっていきます。
 
 
11.敵のブループリントを実装しよう!(ラスト)
敵のブループリントもこれで最後です。
これまでに『生存している間、移動する処理』『死亡したら消える処理』を実装してきました。
そうなると、残っている処理は『生存/死亡を切り替える処理』です。
 
最初の仕様の通り、生存/死亡が切り替わるタイミングとは『プレイヤーに殴られた時』となります。
 
プレイヤーに殴られた時に呼び出されるイベントに、生死を切り替える処理を実装しましょう。
 
もしかしたら忘れている方もいるかもしれませんが、こういう時こそ『BPインターフェイス』を利用します。
画面上の『クラス設定』を選択し、『詳細ウィンドウ』の『インターフェース』→『実装インターフェース』に、初期に作成した『PunchingInterface』を追加しましょう。
これで、殴られたとき用のイベントが追加できるようになります。

 
 
ブループリント上で右クリックを行い、これまた最初に作成した『Punching』イベントを追加しましょう。
(インターフェイス追加後にコンパイルしないと表示されないので要注意です)
これが殴られた時に呼び出されるイベントです。
あとはこの先に生死を切り替える処理を実装しましょう。
生死を判定している変数とは、そう、『IsAlive』です。
『IsAlive』をFalseに変えてしまえば敵の実装も完了です!

 
 
12.ブループリントを修正しよう!(ラスト)
敵のBP実装が終わったところで、今度はテンプレートのBPに一部処理を追加します。
追加する箇所は『BP_MotionController』です。
処理を追加するといってもノード2つだけなので身構えないで大丈夫です。
『イベント ActorBeginOverlap』ノードに、先ほど敵側のBPで作成した
『Punching』の呼び出し処理を繋げるだけでOKです。

 
 
これで、プレイヤーの拳が敵に触れたタイミングで
敵側の死亡処理が呼び出されるようになります。
ちょこんと触れただけで死亡してしまうのは違和感があるかもしれませんが、
今回はテスト目的なので気にしないことにします。
ちなみに手のコリジョンは掴み状態(攻撃モード)じゃないとONにならないように最初から実装されています
このような『テンプレート側で既に行われている処理』については、また後日に説明します
 
 
13.レベルに必要なデータを配置しよう!
ようやく、レベルそのものを弄るときが来ました。
今回は見やすさを追求して、見下ろしカメラでの編集をお勧めします。
見下ろしモードにするためには、エディタの左上から『上』を選択するだけです。
 
まず、マップの中心に『MotionControllerPawn』を配置しましょう。これがプレイヤーになります
『詳細ウィンドウ』の『AutoPossessPlayer』にプレイヤーのポーンを設定するのをお忘れなく
これはVR以外でも必要な処理です。

 
 
続いて、エネミーをスポーンさせるポイントを配置します。
そして、モードウィンドウから『ターゲットポイント』を以下の画像のようにマップ四方に配置しましょう。
ターゲットポイントが見つからない場合は、モードウィンドウで『ターゲットポイント』と検索すれば大丈夫です。
一応、配置が終わったのちに編集視点を『パースペクティブ』に戻し、細かい修正もしておきましょう。
これでレベルへのアクタ配置は終了、いよいよ最後にエネミーをスポーンさせる処理を行います。

 
 
14.レベルブループリントを編集しよう!
『ツールバー』の『ブループリント』→『レベルブループリントを開く』と選択して、
『レベルブループリント』を開きましょう。
ターゲットポイント等、レベル側の処理は『レベルブループリント』で行われます
ここで、エネミーを出現させる処理を行います。
エディタ上でターゲットポイントをクリックしておくと、レベルブループリントでもリファレンスを取得できます。
そして、Tick内で『Delay』を行い、その後に『クラスからアクタをスポーンします』のノードを繋げます。
このノードは、引数Classを引数SpawnTransformの場所にスポーンさせる処理です。
今回はターゲットポイントの位置にスポーンさせるため、ターゲットポイントのリファレンスから『GetActorTransform』で位置を取得して引数に設定しています。
スポーンさせるのはもちろん敵キャラのため『BP_Enemy_Ball』をClassに設定しましょう。

 
 
その後、残りのターゲットポイントからもスポーンさせるように実装します。
以下の画像では少しだけ出現タイミングをずらすため、一つのポイントからスポーン後に『Delay』を使用しています。
ぶっちゃけここももっといい方法がありますが、今回はテスト目的なので気にしないように。
(この記事シリーズ、こればかりな気がします)

 
 
15.(一応の)完成!
試しにプレイしてみましょう!
一応、最初に提示した通りの仕様でゲームが動作しているはずです!
なお、VRでの起動は『VR プレビュー』を選択しないとできないので、そこだけ要注意です。
ちなみに、『VRプレビュー』はUE4起動時点でHMDが接続できていないと選択できませんので、注意してください。

 
 
ただ、ある程度プレイしてみればわかりますが、
今のままでは
『非常に単調』
『敵のパターンが同じでつまらない』
『出現スピードと出現量が嚙み合っておらずフィールドから溢れてしまう』
『ゲームオーバーがないので緊張感も何もない』
などと問題が山積みであることがわかります。
 
 
ここからは読者の皆様が、自分なりに色々と試して作っていきましょう
きっと、いいゲームが作れるはずです。
 
 
全3回、テンプレートを利用したパンチングゲーム制作はこれにて一応終了です。
 
 
ですが、まだまだ解説していない処理も多いです。
例えば、『VRテンプレートで最初から用意されている処理』とか。
 
 
次回からは、そういった『最初から用意されている処理』についての説明をします。
(もしかしたらパンチングゲームのブラッシュアップもやっていくかも…?)

UE4のVRテンプレートを利用してミニゲームを作ってみよう!(第二回)

2017/04/14:記事の文章にあった間違いを修正しました。
トランスフォームの可動性を変更しないと動かせませんね…。
失礼しました。
 
 
この記事は以下のような方を対象としています。
——————————-
・VR機器を持っていて、UE4でとりあえず使ってみたい方
・UE4での経験がまだ浅い方
——————————-
 
 
前提のスキルとして
——————————-
・UE4のエディタの操作方法がわかる
——————————-
があればOKです。

また、先に前回の記事を読んでから、この記事を読み始めていただきたいです。
 
こんにちは、前回から始まった『パンチングゲーム製作』。
わかりやすく説明できたでしょうか?
 

さて、前回まででは
『VRテンプレートでのプロジェクト作成』
『不要なBPの削除』
『BPインターフェイスの作成』
をやってきました。
 
今回は
『敵のBPの追加』
『敵のパラメータを設定』
『敵の移動処理』
『敵が死亡したら消える処理』
を実装していきます。
 
ガリガリ、というほどではありませんが、
それなりに本格的にBPを弄っていきますので、気を引き締めましょう!
 
 
6.敵を追加しよう!
ついに敵キャラを作ります。
『新規追加』→『ブループリント クラス』で新しいBPを作成します。
StaticMeshActorを継承しましょう。
球体型の敵にしようと思うので、『BP_Enemy_Ball』と名付けましょう。
 
 
7.敵のパラメータを設定しよう!
さて、今のままだと何も見えません。
敵の姿を追加していないためです。
敵のBPを開いて、『StaticMeshComponent』の『StaticMesh』を変更し、敵の姿を設定しましょう。
今回は最初からUE4に用意されている『SM_Ball_01』を使用します。
エンジンのコンテンツを可視化しないと使えないので、そこだけ注意です。
続いてStaticMeshComponentを、以下のように変更してください。
・『トランスフォーム』の『可動性』をムーバブルに変更。
・『Physics』の『Simulate Physics』をTrue。
・『Collision』の『SimulationGeneratesHitEvents』をTrue。
・『Collision』の『オーバーラップイベントを発生させる』をTrue。
・『Collision』の『コリジョンプリセット』を『PhysicsActor』に変更。
 
ここの変更はUE4で衝突判定をとりたい場合、必須になります。
絶対に忘れないようにしましょう。
ちなみに筆者はある時、これを忘れ、かれこれ数時間単位で頭を抱えたことがあります。

 
 
8.敵のブループリントを実装しよう!(その1)
いよいよブループリントを作成していきます。
敵のブループリントを開きます。
今はまだ、特に何も処理は書かれていないはずです。
(作ったばかりですから当然ですね)
これから移動のための処理をここに追加します。
まずはbool型の変数を作成します。
この変数は敵の生存・死亡判定に使用しますので、『IsAlive』とでも名付けましょう。
Tickノードとブランチノードを接続し、条件式には変数IsAliveを設定します。
敵の死亡時・生存時に別々の処理を行うためです。
 
 
続いて、『AddWorldOffset』ノードを作成し、先ほどのブランチのTrueに繋げます。
作成した時に一緒に出てくると思いますが、引数ターゲットに何も繋がっていない場合はコンポーネントのウィンドウから『StaticMeshComponent』をドラッグ&ドロップしてゲットして繋げましょう。
『AddWorldOffset』ノードは引数に指定したターゲットに対して、引数DeltaLocationだけ移動させる処理です。

 
 
9.敵のブループリントを実装しよう!(その2)
移動するための処理を追加したはいいですが、まだ敵は移動しません。
DeltaLocationの値に何も設定されていないからです。
次は、DeltaLocationの値を設定していきます。
ここの値には敵から見たプレイヤーの向きを設定すれば大丈夫です。
敵から見たプレイヤーの向きの計算式は以下のようにノードを繋げればわかるはずです。

 
プレイヤー位置(GetPlayerPawn→GetActorLocation)から
敵キャラの現在位置(GetActorLocation)を減算し、
その値を正規化(Normalize)しています。
この値をDeltaLocationに繋げましょう。
 
これにて、基本的な移動処理は完成になります。
ほんとはもっといい別の方法があるのですが、今回はテスト目的なのでこれで十分です。
 
10.敵のブループリントを実装しよう!(その3)
今度は、死亡した時の処理を追加します。
先ほどのブランチのFalseから『Delay』ノードに繋いだのち、『DestroyActor』ノードとも繋げます
引数の値は3ぐらいでいいでしょう。
『DestroyActor』ノードは、アクタを丸ごと消してしまうノード、
『Delay』ノードは引数に指定した時間だけ処理を止めるノードです。
(Delayは本来多用しない方がいいと思いますが…)

 
 
中途半端なところで申し訳ありませんが、今回はこれでおしまいです。
次回はついに敵キャラが完成、メインの部分を実装していきます!

UE4のVRテンプレートを利用してミニゲームを作ってみよう!(第一回)

この記事は以下のような方を対象としています。
——————————-
・VR機器を持っていて、UE4でとりあえず使ってみたい方
・UE4での経験がまだ浅い方
——————————-
 
 
前提のスキルとして
——————————-
・UE4のエディタの操作方法がわかる
——————————-
があればOKです。
 
 

『せっかくHMDを買ったんだし、自分でVRゲームを作ってみたい!』

この記事を見ている方の中にも、そういった考えを持った方がいらっしゃるのではないでしょうか?
ごもっともな考えです。新しい機材が手に入ったのならば、その機材を使ったゲームを作りたいと考えるのはクリエイターの性ですからね。


しかし、いざそういった機材を使ってゲームを作ろうとすると、なかなか作れないのが現実。
Unityを使おうとすれば色々とややこしい設定が必須になり、
ネイティブで実装しようとした場合の苦労は言わずもがな。
『VRで動くプログラムを見たい』、ただそれだけなのに、
そこへ辿り着くまでに力尽きてしまうこともありえます。


という事で、今回からは
『簡単にVRを使う』
『簡単に作れる』
『わかりやすい』
の3点を重視して、UnrealEngine4(以下UE4)を利用して
VRのミニゲームを作っていきたいと思います。
(全3~4回予定)


0.作り始める前に…
まず、このチャプターでは
『どんなゲームを作るのか』
『そもそもなぜUE4を使うのか』
の2点について説明します。


実装には関係ないチャプターですが、一応読んでおいて頂きたいです。

『どんなゲームを作るのか』

以下がゲームの仕様です。

・プレイヤーはフィールドの中心にいて、移動はできない
・エネミーはフィールドの四方からスポーンしてプレイヤーに近づいてくる
・操作はモーションコントローラを使用
・グリップトリガーを引いている間攻撃モードになる
・攻撃モード中に拳が敵に当たると、敵を撃破する
・テスト目的なので極力シンプルに。
・ゲーム性は追及しない

なんだか色々あってわかりづらいかもしれませんので、一言に纏めますと、
『グーパンで敵をぶん殴ってやっつけるゲーム』
です。


割と複雑なプログラムに感じるかもしれませんが、
UE4では簡単に作ることができます。


『そもそもなぜUE4を使うのか』

最初にお話しした通り、VRを使ってゲームを作るためには、ややこしい設定をしなければならないという壁が立ちふさがります。
実を言うと、UE4でもそういった設定が必要になります。
そうなると、『じゃあ結局UE4を使う理由はなんだ?』
という話になります。

UE4には『テンプレート』というものがあり、その中にはVR用のテンプレートもあります。

このテンプレートを使えば、ややこしい設定などが全て済まされた状態でプロジェクトが起動します。これを利用しない手はありません。

結局のところ、『UE4でVRパンチングゲームを作る』理由というのは、
・テンプレートである程度の設定が出来上がっている。
・一部処理を追加するだけで一応作ることができる。
・作っている最中にUE4の基礎機能を覚えられる。
という利点があるからなのです。


そのため、説明の内容も『UE4のVRの基礎を学ぶ』というより、
『VRを通してUE4の基礎を学ぶ』という点に主眼を置いており、
UE4でガリガリとゲームを作る『UE4玄人』向けではなく、
まだUE4を触って間もないorほぼ触っていない『UE4初心者』向けの記事になります。

さて、長い話はここで終わりにして、ゲーム作りを始めていきましょう!


1.VRテンプレートでプロジェクトを作成しよう!
普通にUE4を起動して、プロジェクトを作ります。
『新規プロジェクト』の画面からテンプレートが選択できますので、
『VirtualReality』を選択しましょう。
これがVRのテンプレートプロジェクトであり、最初から
・HMDとモーションコントローラのトラッキング処理
・モーションコントローラで物を掴む処理
・掴みを行った際のアニメーション
などが実装されていて、非常に便利です。

今回に限らず、UE4でVRのプロジェクトを作りたい場合は、
このテンプレートを参考にすればいいでしょう。


2.新規レベルを作成しよう!
プロジェクトが開かれると、おそらく『StartupMap』というレベルが出てくるはずです。
このレベルはテンプレートの案内になるもので、要約すると
『HMDだけなら左のマップ、モーションコントローラもなら右のマップでチェックできる!』
って意味のマップです。
今回は普通にミニゲームを作るので、この案内には従わずに普通にマップを作ります。
左上の『ファイル』→『新規レベル』と選択して、新しいレベルを作ります。
レベルのテンプレートが選べるので、ここは『VR-Basic』を選択しましょう。
そのあとはちゃんとレベルを保存しておきましょう!
このマップがパンチングゲームのメインマップになります。

3.ブループリントを修正しよう!(その1)
ここからがいよいよ本番、ブループリント(以下BP)の編集をやっていきます。
最初に編集するのは、『VirtualRealityBP』→『Blueprints』にある、
(ほかのBPもすべてここにあります)
『MotionControllerPawn』です。
このBPはこのVRテンプレートの要というべきBPです。
そのため、内部の処理も非常に多く、一見すると頭が痛くなります。
まずは、このBPから、『パンチングゲームに不要な処理』をすべて消してしまいましょう。
具体的には
『Event BeginPlay』
『Event Tick』
『InputAction GrabLeft』
『InputAction GrabRight』
以外のカスタムイベントから伸びているノードをすべて消してしまえばいいです。

4.ブループリントを修正しよう!(その2)
次は『BP_MotionController』を編集していきます。
このBPは画面に表示される手(モーションコントローラ)を制御するためのものです。
今回も不要な処理を削除していきます。
『Event Tick』の中にある、『Clear Arc』以降のノードをすべて削除しましょう。

5.ブループリントインターフェイスを追加しよう!
さっきから削除してばかりでしたが、今度はBPを追加していきます。
『新規追加』→『ブループリント』→『ブループリントインターフェース』を選択して、
BPインターフェイスを追加しましょう。
名前は好きにしていいですが、とりあえず『PunchingInterface』とでもつけます。
BPインターフェイスとは、外部からイベントを呼び出すためのBPです。
開いてみると中身の編集はできなくなっています。
まぁ関数を追加する以外に編集の必要はないので、当然ですね。
関数を一つ追加して、『Punching』とでも名付けましょう。
あっという間でしたがBPインターフェイスの編集はこれで完了です。

アッサリ気味でしたが、今回はここまで。
それでは、いよいよ次回からは『敵キャラクター』の実装を進めていきます!

迷路の自動生成アルゴリズム「穴掘り法」をCoffeeScriptとenchant.jsで実装してみた

前回のブログで、「enchant.jsでさくっとアルゴリズミックなゲームを作る時なんかに良さそうです。」と書いたCoffeeScriptですが、早速enchant.jsとの組み合わせで、代表的なアルゴリズムである「穴掘り法」(正確には穴掘り法に自分なりの解釈を加えたもの)を実装してみました。

分かったことですが、CoffeeScriptはやっぱりとってもコードが書きやすい。

ネスト(ループの入れ子)が多いところも書きやすい。

JavaScriptはカッコが多い言語なので、CoffeeScriptのようにカッコなしでかけるのは本当に気持ちがいいし、とても捗りますね。

やっぱり、こうしたものをコーディングするには丁度良さそうです。

最初に考えたこと

コーディングにかかる前に、迷路生成のアルゴリズムを実装する時にどのように組んでいったらいいか、ざっと考えてみました。

・最初
・・どれかひとつの座標をランダムで選ぶ(ただし、XYともに偶数偶数)
・・「基点の座標一覧」にそこを追加
・・掘る

・掘る
・・ランダムに1方向選び、2マス先の座標が掘れるかたしかめる
・・掘れれば、「基点の座標一覧」にそこの座標を追加し
・・1マス先と2マス先を掘る

・掘れなかったら、それ以外の方向の2マス先の座標が掘れるかたしかめる
・・掘れれば、「基点の座標一覧」にそこの座標を追加し
・・1マス先と2マス先を掘る

・それでも掘れなかったら、それら以外の方向の2マス先の座標が掘れるかたしかめる
・・掘れれば、「基点の座標一覧」にそこの座標を追加し
・・・・「基点の座標一覧」から現在の座標を削除し、1マス先と2マス先を掘る

・それでも掘れなかったら
・・「基点の座標一覧」から現在の座標を削除し、
・・もし「基点の座標一覧」にひとつでもあれば
・・・「基点の座標一覧」からどれかひとつをランダムで選ぶ
・・・その座標で掘る
・・「基点の座標」がもうなかったら
・・・終わり

いよいよ実装へ

digという関数はちょっと凝りました。結局、穴掘り法にちょっと変更を加えたものになりました。

numR = 39
numC = 39
posArr = []
pos = []
directions =[[2,0],[-2,0],[0,2],[0,-2]]

# 地図生成---------------------------
for row in [0...numR]
    pos[row] = []
    for col in [0...numC]
      if row is 0 or
         row is numR-1
          pos[row][col] = 2
      else if col is 0 or
          col is numC-1
              pos[row][col] = 2
      else
          pos[row][col] = 0
# 地図生成おわり---------------------

# 掘る-----------------------------
dig = (tC,tR) ->
  posArr.push([tC,tR])
  directions = diShuffle(directions)
  for direction,i in directions
    if pos[tC + directions[i][0]][tR + directions[i][1]] is 0
      #console.log "hi"
      pos[tC + directions[i][0]/2][tR + directions[i][1]/2] = 1
      pos[tC + directions[i][0]][tR + directions[i][1]] = 1
      dig(tC + directions[i][0],tR + directions[i][1])

#方向決定用に配列の順番をシャッフル
diShuffle = (arr) ->
  e = arr.length
  while e
    num = Math.floor(Math.random() * e)
    qwe = arr[--e]
    arr[e] = arr[num]
    arr[num] = qwe
  arr

#最初の一回目はランダムで選ぶ
randomPick = (numR,numC) ->
  ranR = Math.floor(Math.random() * ((numR-1) / 2 + 1)) * 2
  ranC = Math.floor(Math.random() * ((numC-1) / 2 + 1)) * 2
  if ranR is 0
    randomPick(numR,numC)
  else if ranR is (numR-1)
    randomPick(numR,numC)
  else if ranC is 0
    randomPick(numR,numC)
  else if ranC is (numC-1)
    randomPick(numR,numC)
  else
    return [ranR,ranC]

#いよいよ実行
pickRes = randomPick(numR,numC)
pos[pickRes[0]][pickRes[1]] = 1
dig(pickRes[0],pickRes[1])

# enchant.js部分-------
enchant()
window.onload = ->
  game = new Game(312, 312)
  game.preload "chara5.png","map0.png"
  game.onload = ->
    for mapy,iy in pos
      for mapx,ix in mapy
        map = new Sprite(16,16)
        map.x = ix * 8
        map.y = iy * 8
        map.scaleX = 1
        map.scaleY = 1
        map.image = game.assets["map0.png"]
        if mapx is 1
          map.frame = 2;
        else
          map.frame = 3;
        game.rootScene.addChild map
    game.rootScene.addEventListener "enterframe", ->
  game.start()
  console.log game
  return