actionScript書きの日記

アラフォーFlashデベロッパのブログ。actionscriptやobjective-cを経て、現在はUnity、Spine、AfterEffectsがメイン。

Unityちゃん (2D)を使用して、2Dゲームを作ってみる 番外編その2 Unity 2018におけるUnityちゃん(2D)のエラーに関して

 

Unityを2018.2.0f12にバージョンアップして使用していたら、以下のエラーが出た。

error CS0234: The type or namespace name `LoadLevel' does not exist in the namespace `Application'. Are you missing an assembly reference?*1

 

上記エラーに関しては、

Application.LoadLevel(nextLevel);

このソースを

SceneManager.LoadScene(nextLevel);

に書き換えれば解消するようだ。

ScenManagerを使用するためには、ヘッダ部で以下の設定も必要となる。

using UnityEngine.SceneManagement;

 

調べればすぐ出てきたが、突然でちょっとびっくりしたので、メモ。

*1:Unity5の時点で「Application.LoadLevel()」は非推奨になっていたっぽいですね。

Unityちゃん (2D)を使用して、2Dゲームを作ってみる その5 床を配置する

一通りキャラクターの動き等やユーザー入力の受付が出来たので、いよいよ実際のゲームステージの作成の準備に入る。まずは、床の作成方法を確認していく。

 

固定床の作成

こちらは簡単に作成が可能になっている。Unityちゃん付属のドキュメントにも記載はあるが、こちらでもまとめておきたい。

まず、床として配置したいオブジェクトを作成する。任意のコライダーが付与されていれば、床として機能させることが可能だ。

 

今回は機能確認のみだったので、空のGameObjectを作成し、そのGameObjectにBoxCollider2Dを付与した。視認できるように、GameObject内にCubeを配置している。GameObjectの名称は「Floor」とした。 

f:id:goodbyegirl1974:20180422213050p:plain

 床として機能させるオブジェクトは、レイヤーをGroundに設定する必要がある。

自分はUnityちゃんのデータをインポートしたらレイヤーに「Ground」が自動で追加されていたが、ない場合は主導で追加する。

f:id:goodbyegirl1974:20180422213045p:plain

最後に、配置したPrefab「UnityChan2D」に付与されている「UnityChan2DController」のプロパティ「whatIsGround
」にレイヤー名「Ground」を設定する。

f:id:goodbyegirl1974:20180422213959p:plain

これで、設置した床に、Unityちゃんが着地するようになる。

移動床の作成

次に、移動する床をどのように設定するかを見ていきたい。

プラットフォーマーにおける移動床は、80年代の初代マリオから実装されている機能であるが、Unityちゃん2Dで移動床を実装しようとしたら個人的にはかなり苦戦した。色々試行錯誤した結果実装は可能になったが、改めて見てみると「なんでこんな単純な内容にあんなに苦戦したのか」と自分の能力のなさを嘆くばかりである。

ただ、そうした内容を記載しておくのも何かの役には立つかもしれないので、ここにそのプロセスを記載しておくことにする。

RigidBody2Dを使用する

まず、RigidBody2Dを床に付与し、そのRigidBody2D内のvelocityに任意の移動用のVector2の値を渡すという方法を試みた。以下のような処理。

public Rigidbody2D Rb2d;
void Start () {
   Vector2 vec = new Vector2();
   vec.x = 0.0f;
   vec.y = -3.0f;
   Rb2d.velocity = vec;
}

これで床は下降するようになるが、下降しはじめの際にキャラが一瞬浮いてしまう。


physics

床が方向転換して下降に転ずる際に、一瞬キャラのジャンプのアニメが再生されている。キャラクターの重力落下よりも床の下降速度が早いために、こうした現象が起こる。

次に 床に「SliderJoint2D」を付与し、そのMotorSpeedの値を変化させることで上昇・下降を制御しようとしたが、これも同様の現象が起こり、断念せざるを得なくなった。

そもそもがUnityChan2Dに付与されているRigidBody2Dの「Mass」(質量)の値をかなり小さくしないと、Unityちゃんが床に乗った際に床が揺れるなどの影響が出てしまう。意図的にそうした影響を出しているのならばよいが、意図しないものが出てしまうのはまずい。ことここに至って、RigidBody2Dを使用した物理演算によって床を動かすという方法は断念せざるを得なくなった。

ただ、Unity2017からはプラットフォーマーでの床を実装するための「Platform Effector 2D」なるコンポーネントが実装されている。 こうした機能が充実していけば、移動床に関するコンポーネントも早晩出てくるかもしれない。

Transformを使用して動かす

RIgidBody2Dを使えないとなると、Transformを使用して動かすしかない。具体的には、床に付与したスクリプトの「Update」関数内で、Transform.Translateを実行する。

「Start」関数内
vec = Vector3.up * 0.03f;
「Update」関数内
trf.Translate(vec);
    if(trf.position.y > 3.0f)
    {
        vec = Vector3.down * 0.03f;
    }
    else if (trf.position.y < -3.0f)
    {
        vec = Vector3.up * 0.03f;
    } 

「Start」関数内でvecの初期値を設定した後、「Update」関数内でvecを引数としてTranslateを実行し、必要に応じて方向転換の処理を入れる。これで床は動くようになるが、毎フレーム床はテレポートしているような状態になるので、物理演算の影響下には置かれなくなる。

この状態だと、やはり下降する際にキャラが浮いたりするので、キャラが床に着地した際にキャラの親オブジェクトを床に設定する。今回は床側のScriptに以下の処理を入れたが、本来はキャラの側のScriptに入れるのが筋だろう

//trfは床のTransform
private void OnCollisionEnter2D(Collision2D collision)
{
   collision.gameObject.transform.SetParent(trf);
}

private void OnCollisionExit2D(Collision2D collision)
{
   collision.gameObject.transform.SetParent(trf.parent);
}

この場合、「collision.gameObject」がキャラとなり、その親に床(のtransform)を設定する。床とキャラが離れた際には、キャラの親を元に戻している。

本来は、衝突判定が発生した相手がキャラであることを、タグやレイヤーなどを使用して確認、分岐する必要があるが、今回は確認用のファイルで床とキャラのみを配置している状態だったので、そのまま書いた。

この処理を入れることで、縦・横両方向の動きに対応する。床とともにキャラクターも移動してくれる形となる。

次回は、これらの床の機能を使用して、ゲームステージを設計してみる。

エフェクト考 その1

前回のブログで「主にパーティクルのエフェクトに関して、その画像素材をいかにして作成するか」というような内容を書いたが、もう少しそこに補足をしておきたい。

大前提として、制作者が以下の状態であるとする。

 

 

この条件で、一体自分に何が出来るか、どのように学習を進めていくべきかを考える必要がある。

 

まず、最初に検討したいのは、基本図形のみでどこまでのエフェクトが作成可能なのか、という点である。ここでいう基本図形とは「円(楕円含む)」「四角」「三角」「その他多角形」およびそこから作成されるグラデーション、ということになる。

前回もアップしたが、最もシンプルな形態となるとこのような形になるだろう。

 

youtu.be

 

業務でshurikenを使用してみて実感するが、意外とこの「グラデの掛かった円」というパーティクルは利用シーンが広く、侮れないという印象。こうした基本図形のみでどこまでエフェクトを作成できるのかということは、突き詰めて考えていくべきだろう。また、この手のエフェクトはある程度の作例がネットでも公開をされている。

 

次に検討したいのが、PhotoshopおよびAfterEffectsに搭載されたフィルタを使用した素材作りである。

個人的には、絵の描けない人間はここに全振りするしかなかろうと思うのだが、ネット上にはこれに関する情報があまり見当たらない(あるいは自分の調べ方が悪いのかもしれないが)。

取っ掛かりが難しいという印象があるのだが、全く何もない状態から使用できる主だったフィルタは、大別すると以下の二つのみとなる。

  • 雲模様
  • ノイズ

また、このあたりを足がかりに作成した画像に対して多用されるフィルタとして

あたりが挙げられるかと思う。まずはこのあたりの組み合わせからどのようなエフェクトを生成できるか、を考えていくのが出発点となるだろう。

今回は、以下の手順で簡単なテクスチャ画像を作成し、エフェクトに使用してみた。

白と黒の二色で、1024px四方のサイズで雲模様を実行

その画像を256*256のサイズに縮小

中心から周囲にかけてグラデーションでマスク

これにより作成した画像が以下のようになる。

f:id:goodbyegirl1974:20180310103703p:plain

f:id:goodbyegirl1974:20180310103706p:plain

二枚目は、上記の画像にノイズを加え、斜め方向にブラーをかけたものとなる。

これらを組み合わせて作成した炎のエフェクトが以下になる。

 

youtu.be

 

最初のエフェクトに比べて、幾ばくか情報量が増えているのがお分かりいただけるだろうか。

 

最後に、簡単な絵を描く、という選択肢があるのだが、これはいったん後回しとしたい。まずは前の2つに関して、いろいろと試行錯誤していきたいと思う。

エフェクト考 その0

前回からまた間が空いた。2Dゲームの課題ファイル自体は作成して授業で使用はしたものの、記事にするだけの時間的余裕がなく、一時中断となった。

今回のタイトルは「エフェクト考」である。2Dゲームは少し置いておいて、自分の業務上でエフェクト作成と向き合う必要が出てきたため、こうしたタイトルで新たに記事を起こした。

2017年より自分の業務に本格的にUnityが入ったが、そこでのメインの業務はshurikenを使用したエフェクトの作成だった。

既存コンテンツにおいてエフェクトを作成している間は、有り物から複数のパーツを引っ張ってきて並べるだけでもなんとかなっていたのだが、新規コンテンツの制作が入るかも、という段階になって、それだけではたち行かなくなってきた。

加えて、新たにエフェクト部分のマネージャーとして参画して来た方が非常に優秀な方で、AfterEffectsやMayaをしっかり使いこなしてエフェクトを作成する方なので、これまでの流用メインでの方法論では早晩限界が来てしまい、自分自身で再度自分の業務内容を見つめ直す必要が出た。

自分自身が業務委託のフリーランス扱いなので、いつまで現在の業務に従事するかも分からないのだが、職を変わるにしても、エフェクトに関して学習し、まとめておくのも、無駄ではないだろう。

というわけでエフェクト考なのだが、今回は通し番号に0をつけた。これは、実際のエフェクト作成に関してではなく、その前段階、学習開始の段階で自分が迷ったり困ったりしていることを書いておこうと思ったからである。

 

エフェクト作成に関して、普段使用しているUnityのshuriken、およびこれから使用するであろうAfterEffectsに関する情報をWebで集めていくとき、一番情報が不足するのは、「エフェクトで使用する素材画像の作成方法」だ。

例えば炎のエフェクトを作成する場合、最も初歩的なケースだと、中心部から外縁部にかけて白からオレンジに変化するグラデーションをかけた円の画像を用意して、それを乗算で重ねて表示することで炎を表現する、ということになるだろう。例えば、以下の様なものだ。


youtu.be

 

このくらいなら、いくら自分でも素材を作成することは可能である。まあ上記の映像を見ても分かる通り色使いのセンスは目を覆う感じではあるけれども、作例としては成立する程度にはなるだろう。

では、以下の動画のエフェクトであればどうだろうか。

 

youtu.be

 

もし、このレベルを抵抗なく独力で作成することが出来る方であれば、この記事を読むのは時間の無駄であるので、他のブログに当たられたい。

さて、仮に独力でこのレベルを作成することが難しいとしよう。ではこの作り方を独力で学ぼう、と考えて、その方法は二つある。何か参考書などの資料を購入するか、ネットで検索するか、だ。だが、どちらのケースでも大きな問題が発生する。使用するテクスチャの画像である。

ネット上のチュートリアルでも、エフェクト作成を解説した参考書・技術書であっても、テクスチャの画像に関してはほとんどの場合、作成方法が記述されないのである。エフェクト作成のプロセスの中でしれっと、例えば次のように著される。

続いて画像を用意する。今回は以下の画像を使用した。

 

f:id:goodbyegirl1974:20180216220342p:plain

 いやいやいや、ちょっと待って下さいよ、と言いたくなる。その画像が作成できたんだったら、後はUnityのマニュアル見てshurikenで表示しますよ。そこが作れないから困っているわけだし、そこが作れないから「よし、勉強しよう!」となってるのに。君は一体何しちゃってるんですか、と。料理番組なら、下ごしらえの部分を全部端折って、フライパンとガスコンロの使い方で番組を埋めてるようなもんだろ、と思うわけです。

しかし、逆に考えれば、この公開しない部分こそが、エフェクトデザイナーと呼ばれる人々のおそらくは「飯の種」なんだろうと思う。そう考えれば、そりゃ自分の飯の種を無料でネットで公開したりはしないわな、と思う。

つまり、ネット上になかなか直接的な情報が出ず、なおかつ自分がエフェクト学習の際に困っている部分こそが、エフェクト作成の一番の肝なのだろう。

というわけで、備忘録的に、自分がこの肝の部分をどのように学習していくかを書いていきたいと思う。もちろん、自分にとってもこれが「飯の種」になる可能性はあるわけで、その場合はぼかしながらの記載にはなるであろうが。

取り急ぎ、上記のような画像を作成するには、毎度おなじみ雲模様を使用するのが定番である。加えて、AfterEffectsだとPhotoshopよりも更にいろいろといじれるようでもある。取っ掛かりとして、このあたりを手がかりに学習を進めていきたいと思う。

Unityちゃん (2D)を使用して、2Dゲームを作ってみる 番外編1

2Dのキャラの動かし方をずっといろいろ試していたんだけど、初めて気がついて詰まってしまった点があったので、備忘録として。

 

「GameManager」というクラスを実装すると同時に、2Dアクションゲームの敵役として「missile_horizonal」というプレハブを用意しておく。

この「missile_horizonal」には同名のスクリプトファイルがAdd Componentされており、プレハブは「GameManager」から動的に生成できるように「Resources」フォルダ内に配置されている。

「GameManager」内で「createMissile」という関数を実行している。ここで動的に「missile_horizonal」のインスタンスを生成し、画面に表示している。

ここで問題になるのが、関数「createMissile」内で「missile_horizonal」内の「init」という関数を実行していることだ。


GameObject missile = (GameObject)Resources.Load ("missile_horizonal");
int dir = Random.Range (0, 2);

//中略

Instantiate (missile, position, Quaternion.identity);
missile_horizonal mh = missile.GetComponent ();
mh.init (dir);

要は変数「dir」の値に応じて挙動を変更したいために、生成したインスタンス内の関数「init」を外部から実行しようとしている。


bool setFlg = false;

//中略

void Update ()
{
	if (!setFlg) {
		return;
	}
	//中略
}

//中略

public void init (int dir)
{
	Debug.Log ("missile_init");
	dirVec = Vector2.left;
	if (dir == 1) {
		this.transform.Rotate (new Vector3 (0.0f, 180.0f, 0.0f));
	}
	setFlg = true;
}

関数「init」の中身はこんな感じ。
ここで問題になるのが、変数「setFlg」の中身なのだが、各関数の実行順を見てみると、

  1. 「missile_horaizonal」内の「Awake」
  2. 外部から実行される、「missile_horaizonal」内の「Init」
  3. 「missile_horaizonal」内の「Start」

という順番になっており、どうやらこの「Start」の段階で変数の中身が初期化されてしまうらしい。 つまり関数「init」内でtrueが代入された変数「setFlg」の値が、関数「Start」内で初期化されて再度falseに戻ってしまうようなのだ。

従ってUpdateのreturn文以降の処理はいつまでたっても実行されず。。。。ちょっと予想していない挙動だったので、念のために書き留めておく。

Unityちゃん (2D)を使用して、2Dゲームを作ってみる その 4 GetAxis

前回はキー入力の受付処理を書いたが、Unityちゃん2Dのサンプルにおいては、別の形でキー入力をキャラの移動に反映させている。


float x = Input.GetAxis("Horizontal");
bool jump = Input.GetButtonDown("Jump");
Move(x, jump);
jumpに関しては「GetButtonDown」を使用しているが、GetKey系とGetButton系の処理の違いに関しては、以下の記事がよくまとめてくださっている。

http://qiita.com/RyotaMurohoshi/items/688fe33f44de8339c497

GetButton系の処理の方が、キーアサインをユーザーも上書きできる点が優れている、ということのようだ。

続いて、GetAxisに関して見ていきたい。 これは、事前に設定したキー操作に応じて-1〜1の間で変化する値を取得する関数である。 Inputの設定画面は、「Edit」→「Project Settings」→「Input」から呼び出す。

f:id:goodbyegirl1974:20170401183806p:plain

呼び出されたInputの設定画面を確認すると、Axisに関しては既に設定がされている。

f:id:goodbyegirl1974:20170404085708p:plain

「Horizonal」の欄を見ると、「Negative Button」に「left」、「Positive Button」に「right」が設定されている。 これによって、対応する値が-1から1の間で変化する。左矢印を押せば値が減り、右矢印を押せば値が増加する。 この辺りは、ゲーム制作への使用を前提とした機能と言えるだろう。便利だが、初見ではちょっと分かりにくい。

ユニティちゃん2Dのサンプルファイルでは、この「GetAxis」が使用されている。

Unityちゃん (2D)を使用して、2Dゲームを作ってみる その3 ユーザー入力の受付

前回までで画像の設定とアニメーションの作成方法を一通り見たので、そのようにして作成したGameObjectを、ユーザーからの入力に応じて動かしてみることにする。

今回はPCでの入力を主に見ていくが、スマートホンなどのケースも少しずつ触れていくことにする。

■PCでの入力受付

PCでの入力というと、メインとなるのは

  • キー入力
  • マウス入力
  • の二つとなるだろう。これらをそれぞれ見ていくこととする。

    キー入力

    キー入力の場合、やり方が複数ある。順を追って見ていくことにする。

    Input.GetKey, GetKeyDown , GetKeyUp

    指定したキーが該当する状態にあるかどうかを確認するための関数。戻り値はBooleanか?

    名前状態
    Input.GetKeyキーを押している間は常にtrue
    Input.GetKeyDownキーが押されていない状態から押した際にtrue
    InputGetKeyUpキーを押している状態から離した際にtrue

    これらのメソッドを用いて、キーの状態を取得することになる。 具体的に見てみよう。

    クラス「InputManager.cs」を作成し、前回生成したキャラクターのGameObjectにアタッチする。 クラス内の関数「update」内に、キー入力を受け付けるための処理を記述していく。

    void Update () {
    	if (Input.GetKey (KeyCode.RightArrow)) {
    	Debug.Log ("右矢印が押された");
    	}
    }
    

    右矢印キーが押されている間ずっと反応させたい場合、上記のような形になる。 この形で矢印キーによるキャラの移動を実装してみる。

    
    float horizonalSpeed;
    float horizonalMaxSpeed = 6.0f;
    int horizonalDir;
    Rigidbody2D rb2d;
    
    const int DIR_RIGHT = 1;
    const int DIR_LEFT = -1;
    const int DIR_NONE = 0;
    const int DIR_TOP = 1;
    const int DIR_BOTTOM = -1;
    
    const string MOVE_TYPE_HORIZONAL = "horizonal";
    const string MOVE_TYPE_VERTICAL = "vartical";
    
    
    // Update is called once per frame
    void Update ()
    {
    	if (Input.GetKeyDown (KeyCode.RightArrow)) {
    		horizonalDir = DIR_RIGHT;
    	}
    	if (Input.GetKeyDown (KeyCode.LeftArrow)) {
    		horizonalDir = DIR_LEFT;
    	}
    	//キーを離した際の処理。
    	if (Input.GetKeyUp (KeyCode.RightArrow)) {
    		if (!Input.GetKey (KeyCode.LeftArrow)) {
    		stop(MOVE_TYPE_HORIZONAL);
    		}
    	}
    	else if (Input.GetKeyUp (KeyCode.LeftArrow)) {
    		if (!Input.GetKey (KeyCode.RightArrow)) {
    		stop(MOVE_TYPE_HORIZONAL);
    		}
    	}
    	move (horizonalDir, jumpFlg);
    }
    
    /// 
    /// 移動停止処理
    /// 
    /// Type.
    void stop(string type)
    {
    	if (type == MOVE_TYPE_HORIZONAL) {
    		horizonalDir = DIR_NONE;
    		horizonalSpeed = 0.0f;
    	}
    }
    		
    
    /// 
    /// キャラを移動させる関数。
    /// 
    /// Dir.
    void move (int dir, bool jumpFlg)
    {
    	horizonalSpeed += accelSpeed * dir;
    	if (horizonalSpeed > horizonalMaxSpeed) {
    		horizonalSpeed = horizonalMaxSpeed;
    	} else if (horizonalSpeed < -horizonalMaxSpeed) {
    		horizonalSpeed = -horizonalMaxSpeed;
    	}
    	rb2d.velocity = new Vector2 (horizonalSpeed, 0);
    }
    

    これでキャラを矢印キーで左右に動かすことが可能になる。

    Unityちゃんのサンプル内では、ちょっと違った処理を行っている。次回はその処理を解析する。