カテゴリー別アーカイブ: Unity

Blender to Unity 01 Terrain

標準

Blender LandscapeをUnity Terrainに適用するまで

A.Blender作業

1)LandScapeを利用して地形をつくる(パラメータをいろいろいじってみる)

左下に出てくるオプションで、Subdivisionは256に設定しておくと十分細かい地形を作ることが出来る。

landscape01

2)ギザギザが気になるようなら、スカルプトモードでShiftを押しながら、少しなめらかにする。

3)マテリアルを追加。色は白。Shadelessをチェック。

landscape02

4)テクスチャをBlendタイプで追加。

landscape03

5)カメラ設定。真上から。

landscape04

6)レンダリング画像設定。16bitのグレースケールになるように。また、2の2乗に1ピクセル足した大きさになるように。レンダリングしたものを保存。png形式でよい。

landscape05

7)レンダリング結果画像(png)

2049

B. Krita作業

Blenderで出力したpngファイルをそのまま、Unityで読ませようとしてうまくいかなかったので、Kritaでデータ変換する。r16形式データにするだけ。

landscape06

C.Unity作業

1)Unityで新規Terrain追加。

マテリアルがテラテラ反射していたので、適当なマテリアルに変更。

landscape07

Import Rawというボタンをクリックし、先ほど保存しておいた、Kritaで作成した、.r16ファイルをインポートする。その際、作成した大きさとMacで作成したか、Winで作成したかを確認。高さが極端に高くなるのを抑えるため、読み込み時のheightの値を少し下げるとよい(例えば、600になっていたら、それを200にするなど)

2)あとは普通のTerrainとして、樹木追加も可能、ブラシによる変更も可能。Terrainコライダーも無事についている。

landscape08

画像の縁の部分がなぜか、1ピクセル分、立ち上がっているので修正する必要があるかも。

 

UnityチュートリアルSpaceShooterその6「サウンド得点完成へ」

標準

9.サウンド

Unityには3つのサウンド関係のキーワードがある。
1)Audio Clips, 2)Audio Sources, 3)Audio Listener
オーディオクリップは、サウンドファイルが収納されている音のデータである。

Audio Clipを選択すると、インスペクターには、プレビューとして、波形、試聴ボタン、ループボタンが現れる。さらにそのクリップの詳細がプレビュー画面の下に現れる。

1)オーディオクリップの3Dサウンドを無効にする(相対位置によって、聞こえ方が変わる効果)

2)クリップをプレファブオブジェクトにドラッグすると、自動的にオーディオソースコンポーネントが追加され、サウンドクリップを指定することが出来る。

Play On Awakeがチェックされていることを確認する。explosion_asteroidとexplosion_playerのプレファブに、それぞれのサウンドを入れる。

3)Playerが武器を発射したときのサウンドを入れる。ドラッグしただけだと、オーディオソースコンポーネントのPlay On Awakeが有効になってしまうので、無効にする。

4)Playerが武器を発射したときだけサウンドを出したいので、PlayerControllerスクリプトに書き加える。

ちょうど、武器(shot)をインスタンス化する部分に音をいれればいいことがわかる。
(ビデオでは、audio.となっているが、GetComponetを使わないとUnity5では動かない)

https://oc.unity3d.com/index.php/s/rna2inqWBBysn6l?_ga=1.260994632.411228565.1453178645

↑Unityチュートリアル提供、変更点一覧

private AudioSource audioSource;

void Start(){ 関数内に

audioSource=GetCompornent<AudioSource>();

を追加。

サウンドプレイするには、
 audioSource.Play();

10.バックグラウンドミュージック

バックグラウンドミュージックは、GameControllerゲームオブジェクトに持たせるのがいいであろう。サウンドをドラッグする。

Play On AwakeとLoopの欄を有効にする

11.音量調節

Playerについている武器発射の音量を 0.5にする。

GameControllerについている背景音楽の音量を 0.5にする

12.スコア表示

新規GameObjectを追加し、Score Textと名前変更する。Add ComponentからRendering→GUIText を選ぶ

Transformのポジションを0.5,0.5,0にすると、画面中央に文字を出せる。(つまり、ビューポートは、左下を(0,0)、右上を(1,1)とする座標上に位置する。

スクリーンスペース ピクセル単位
ビューポートスペース 左下が(0,0) 右上が(1,1)

GameControllerスクリプトを開き、スコア入力の仕組みをつくる。

public GUIText scoreText;
 public int score; (publicとなっているが、実際には別のクラスからいじるので、箱として見えないほうがいい。したがって、あとでprivate
に変更する)
void UpdateScore()
 {
 scoreText.text = "Score: " + score;
 }

準備が出来たら、ゲームスタートするときと、障害物を破壊したときに、上記UpdateScore関数が動くようにする。

1) Start()関数内に

score=0;
UpdateScore();

2) GameControllerが小惑星破壊を知ることは出来ないが、小惑星そのものに、自分が破壊されたタイミングをGameController内のpublic関数に伝えることができる。

GameController関数内にpublic関数追加

public void AddScore(int newScoreValue)
{
   score += newScoreValue;
   UpdateScore();
}

小惑星プレファブを確認すると、プレイヤーが小惑星を破壊するのは、DestroyByContactスクリプトで行っている。したがって、そのスクリプトにGameControllerのAddScoreを呼ばせる。DestroyByContactスクリプトに

public int ScoreValue;

を追加しておき、GameControllerクラスの変数 gameControllerを作成する。

private GameController gameController;

その上で、破壊が起きたあとに、AddScoreを呼び出す。

gameController.AddScore(scoreValue);

また、Start()のところに、

   GameObject gameControllerObject = GameObject.FindWithTag ("GameController");
        if (gameControllerObject != null)
        {
            gameController = gameControllerObject.GetComponent <GameController>();
        }
  }

を記述する。

unityチュートリアルSpaceShooterその5「ゲーム化」

標準

その4で作成できた小惑星に、弾を動かすのに作ったMoverというスクリプトを適用し、スピードに-5を入力する。これで小惑星が落ちてくる。

出来上がった小惑星は、プレファブ化し、シーン上から削除する。

6.ゲームコントローラーの追加

1)空のGameObjectを追加し、GameControllerと名前変更する。タグとしてプリメイドのGameControllerをつける。リセットは必ずしも必要ないが、一応場所、回転、拡縮をリセットする。

2)新規スクリプト GameControllerを追加

3)GameControllerで行いたいことは、まず、小惑星(障害物~hazard)を枠外からランダムポジションで落としてくること。

これをSpawnWavesという関数で実現することにする。
public GameObject hazard;

void SpawnWaves(){

}

Start関数で、この関数を呼び出す
void Start(){

SpwanWaves();

}

4)SpawnWaves関数で何をしたいかというと、障害物を実体化すること。

Instantiate(hazard, spawnPosition,spawnRotation);

ひとまず、関数の中で上記を正しく表現するために、

void SpawnWaves()
{
Vector3 spawnPosition = new Vector3();
Quaternion spawnRotation = new Quaternion();

Instantiate(hazard, spawnPosition, spawnRotation);
}

としておく。

このhazardは、publicで設定できるが、spawnPositionとspawnRotationはどうすればいいか。

5)positionは、Vector3変数であるので、
public Vector3 =new spawnValues;

を宣言しておいて、xは-6から6までの乱数。yは0。zは、範囲外に出ている16とする。

SpawnWaves関数のほうで、spawnPositionの設定を行う。

Vector3 spawnPosition = new Vector3(Random.Range(-spawnValues.x,spawnValues.x),spawnValues.y,spawnValues.z);

6)回転のほうは、どうするかというと、クォータニオンは扱いがやっかいであるが、ここでは、初期値(回転なし)でいいので、ちょうど Quaternion.identityというのがあるので、それで定義しなおす。

Quaternion spawnRotation = Quaternion.identity;

7.小惑星が次々に現れる設定を作る

たくさん小惑星を落としたいからといって、単純にコピペを繰り返しても、同時に落ちてくるだけなので、うまくいかない。

とはいえ、繰り返しのために、for文を記述しておく。

public int hazardCount;

for (int i=0;i<hazardCount;i++){

繰り返したい内容;

}

コピペよりはプログラムはすっきりしたが、このままでは小惑星は同時にあらわれて、最初の段階でお互いに衝突して爆発してしまう。

小惑星が落ちてくる「間隔」が必要になる。

そこで、public float spawnWait;

を追加し、実体化のコマンドの下の行に、

WaitForSeconds(spawnWait);

を記述する。論理的には、これで合っているのだが、C#ではこれは動作しない。

時間を止めて、別の関数を走らせるためには、コルーチンをしかけなければならない。

コルーチンの場合、関数は、voidではなくなる。必ず、IEnumerator にする。

IEnumeratore spawnWaves(){ ~~~ }

そして、WaitForSeconds( ); の前に必ず、yield return new を追加する必要がある。

yield return new WaitForSeconds(spawnWait);

呼び出しも、単に関数名では呼び出せないので、Start関数の中は、呼び出す関数名をStartCoroutine関数で指定する。

StartCoroutine(soawnWaves());

すぐにスタートするのではなく、少しの間だけゲームスタートを待つほうが親切であるので、public float startWait;

を作っておくといい。これをspawnWaves()関数の最初で 少し待つというコマンドで実現する。

yield new WaitForSeconds(startWait);

また、小惑星の次の集団(hazardCountによる)が落下するまでの間を少し空けるために、

public float waveWait;

を作成する。これは、while(true)を使って、無限にループするようにする。

全体のプログラムは次のようになっている。


using UnityEngine;
using System.Collections;

public class GameController : MonoBehaviour
{
public GameObject hazard;
public Vector3 spawnValues;
public int hazardCount;
public float spawnWait;
public float startWait;
public float waveWait;

void Start ()
{
StartCoroutine (SpawnWaves ());
}

IEnumerator SpawnWaves ()
{
yield return new WaitForSeconds (startWait);
while (true)
{
for (int i = 0; i < hazardCount; i++)
{
Vector3 spawnPosition = new Vector3 (Random.Range (-spawnValues.x, spawnValues.x), spawnValues.y, spawnValues.z);
Quaternion spawnRotation = Quaternion.identity;
Instantiate (hazard, spawnPosition, spawnRotation);
yield return new WaitForSeconds (spawnWait);
}
yield return new WaitForSeconds (waveWait);
}
}
}


8.爆発の残りを消去する

ゲームをスタートすると、VFXのexplosionが画面にいつまでも残っている。

そこで、DestroyByTimeというスクリプトを書く

public float lifeTime;

void Start(){

Destroy(gameObject,lifeTime);

}

このスクリプトを、VFXフォルダ内プレファブの、explositon(3タイプとも)にコンポーネントとして追加しておく。

unityチュートリアルSpaceShooterその4「境界と敵」

標準

https://saitottammas.wordpress.com/2016/11/24/unity-spaceshooter3/ の続き

Unity5バージョンでの変更点一覧(Unity提供)
https://oc.unity3d.com/index.php/s/rna2inqWBBysn6l?_ga=1.260994632.411228565.1453178645

3.ゲームエリアの境界作成

ゲームエリアをBoxで作り、弾がその境界外に出たら、削除するように設定する。

1)新規にCubeを追加。実際にはコライダーのみ必要であるが、設置するまで、mesh render等も有効にしておく。名前は Boundaryにしておく。

2) カメラが直交投影に設定されている場合、プレイ画面長さは、カメラのOrthographicサイズの2倍なので、カメラ位置中心に設置するため、場所を0,0,5に置く。x方向にスケール15, y方向にスケール20にする。

3)大きさが設定できたら、mesh renderを無効にする。

4)C#スクリプト DestroyByBoundaryを新規追加。AssetのScriptフォルダなどに格納し、Boudaryにアタッチする。
————

using UnityEngine;
using System.Collections;

public class DestroyByBoundary : MonoBehaviour
{
void OnTriggerExit(Collider other)
{
Destroy(other.gameObject);
}
}


Triggerに関わるマニュアルからTriggerExitを調べると、ちょうどサンプルとして出ているコード。

5)確認してうまく弾が消えるなら、OK。Boundaryから不要なMesh Filter とMesh Render コンポーネントを削除する。

4.障害物(小惑星)の追加

1)空のゲームオブジェクトをAsteroidという名前にし、位置をリセットする。試しに前方(y)に8の場所に置く。

2)3つの小惑星が準備されているので、最初のものを選び、ゲームオブジェクトにドラッグする。場所をリセットする。

3)Asteroidにリジッドボディコンポーネントを追加し、重力を無効にする。

4)カプセルコライダーコンポーネントを追加する。edit collider ボタンをクリックし、シーンビュー上でカプセルの大きさを小惑星にあわせる。

5)C#スクリプト追加 RandomRotater

using UnityEngine;
using System.Collections;

public class RandomRotator : MonoBehaviour
{
public float tumble;
private Rigidbody rb;

void Start ()
{
rb=GetComponent<Rigidbody>();
rb.angularVelocity = Random.insideUnitSphere * tumble;
}
}

tumbleを5に設定し、ゲームプレイごとに違う角度で回転する小惑星を手に入れた。

6)AsteroidのRigibodyのDrag角度(Angular Drag)に初期値0.05が設定されているので、これを 0 にする。

7)弾と小惑星はTrigger同士なので、当たり判定はスクリプトを書く必要がある。
小惑星が何か(おそらく弾)にあたるとDestroyされればよい。

8)DestroyByContactスクリプト

void OnTriggerEnter(Collider other) 
    {
        Debug.log(other.name)
        Destroy(other.gameObject);
        Destroy(gameObject);
    }

として確認してみると、最初にBoundaryにぶつかっていて、Boundaryと一緒に小惑星が消えてしまう現象が確認できた。

それではまずいので、Boundaryには、タグBaundaryをつけて、そのタグのときは、無視されるように変更する。

void OnTriggerEnter(Collider other) 
    {
        if (other.tag == "Boundary") { return; }
        Destroy(other.gameObject);
        Destroy(gameObject);
    }

5.爆発効果の追加

小惑星が破壊された場合と自機が破壊された場合

1)VFXのプレファブを、衝突のタイミングで実体化すればよい。

DestroyByContact に追加

public GameObject explosion;
void OnTriggerEnter(Collider other) 
    {
        if (other.tag == "Boundary") { return; }
        Instantiate(explosion,transform.position,transform.rotation);
        Destroy(other.gameObject);
        Destroy(gameObject);
    }

2)自機が小惑星にぶつかったときにも、同じ爆発になってしまうので、タグPlayerを利用して、そのときは、別のVFXを出す。

public class DestroyByContact : MonoBehaviour
{
 public GameObject explosion;
 public GameObject playerExplosion;

 void OnTriggerEnter(Collider other) 
 {
 if (other.tag == "Boundary")
 {
 return;
 }
 Instantiate(explosion, transform.position, transform.rotation);
 if (other.tag == "Player")
 {
 Instantiate(playerExplosion, other.transform.position, other.transform.rotation);
 }
 Destroy(other.gameObject);
 Destroy(gameObject);
 }
}
Unityシーンに戻り、Playerには、Playerタグをつける。Playerタグは最初から準備されているので、タグの新規追加する必要はない。

unityチュートリアルSpaceShooterその3「攻撃」

標準

https://saitottammas.wordpress.com/2015/11/14/unity-spaceshooter1/

https://saitottammas.wordpress.com/2015/11/16/unity-spaceshooter2/

に続く第三弾

1.shot(弾)を作る。

1)画面上のPlayer(飛行艇)が邪魔になるので、インスペクターのPlayer前のチェックをはずして「非表示」にする。

2)Empty GameObjectを作成し(shift-CTRL-N)、名前を「Bolt」に変更する。リセットして位置を原点に戻す。

3)新規にQuadを作り、名前を「VFX」に変更する。場所をリセットする。

4)このVFXをドラッグしてBoltの下(childとして)に持っていく。

5) シーンビューで見ると、Quadの向きがカメラに水平になっているので、x軸で90度回転し、上から見て表面が見えるようにする。

6) ダウンロードしたアセットのテクスチャフォルダから、レーザーオレンジの画像を出す。

7) 単にテクスチャをドラッグする方法もあるが、今回は、マテリアル作成をしてみる。マテリアルフォルダを選択しておいてから、ヒエラルキーのcreateメニューから、create new materialを選ぶ。

名前をFX Bolt Orangeに変更する。

8)マテリアルのインスペクターウィンドウで、アセットピッカー(右上)を使い、テクスチャを選ぶか、テクスチャフォルダから画像をインスペクターフィールドにドラッグする。

9) 作成したマテリアルを、シーンビューのQuadにドラッグする。

10) このままでは、画面上に黒い四角が見えているので 、Shaderの変更をする必要がある。

デフォルトのDiffuseというのは、色を表示するShaderなので、代わりに、Particle→additiveを選ぶ。これは黒を透明にし、白を強調してくれる。他にも、mobile→particle→additiveでも良い。

mobile Shaderは、モバイルゲームでなくても有効である。

11)さて、Boltには現在何のコンポーネントも付いていないが、衝突計算も必要なため、rigidコンポーネントとコライダコンポーネントが必要になる。

まず、Rigidコンポーネントを追加し、重力を非選択する。

12) VFXオブジェクトを確認すると、mesh コライダーが自動的に付いているが、これは不要なので、removeコンポーネントする。

親のBoltオブジェクトに戻り、カプセルコライダーを追加する。カプセルの軸をy軸でなく、z軸にして弾の向きに合わせる。サイズも合わせて、隙間のないようにする。(真上からみると、半径0.03あたり、高さ0.5あたりが良さそうである)

13)コライダーコンポーネント設定で、Triggerのチェックをオンにする。

14) c#スクリプトを追加し、Moverと名づけて編集する。

using UnityEngine;
using System.Collections;

public class Mover : MonoBehaviour
{
private Rigidbody rb;
public float speed;

void Start ()
{
rb=GetComponent<Rigidbody>();
rb.velocity = rb.transform.forward * speed;
}
}

15)このBoltをヒエラルキーのPrefabsフォルダ(なければ作成する)にドラッグして、プレファブ化する。

16) 初期画面からBoltを削除し、ゲームプレイ中にこのプレファブをヒエラルキーウィンドウにドラッグすると、まっすぐに飛んでいくBoltを確認できる。

 

2.Fireボタンをクリックで発射

1)Shot(弾)は、プレファブ化したのだから、それをゲーム内で実体化する必要がある。

これをするのが、Instantiate(インスタンス化)である。ファイアボタン(マウス左ボタンか左コントロールキーに割り当てられている)
をクリックしたら弾が発射するようにする。これは、単にUpdate()関数の中に記述すればよい。

Instantiateの使い方:
public static Object Instantiate(Object original, Vector3 position, Quaternion rotation);

ここでは、プレファブ化したBoltをVector3の位置とクォータにオン回転角度 で指定する。
これらの情報はどこで確認すればいいかというと、Inspectorの一番上にTransformというコンポーネントに
コンパクトに格納されている。

2)プレファブ化されているのは、Bolt(弾)であるから、それを使うとして、位置については、Player機の子供として
取り付けた、Shot Spawnを指定する。空(から)のGame Objectを追加し、Shot Spawnと名前を変更する。位置回転をリセットしたら、
これをPlayerオブジェクトの子供としてとりつける(Playerにドラッグする)。

3)弾が放出される場所を見つける。Shot SpawnはPlayerとの相対的な位置関係で座標が表示されるので、Z方向(機の前方)へずらし、適切な位置を探る。ここでは、Z位置が1.25ぐらいでちょうどよさそうである。BoltプレファブをShot Spawnの子供として配置して
みるとイメージしやすい(あとで削除するが)。

4)PlayerControllerスクリプトの修正

まず、public gameObject shot; 追加
public gameObject shotSpawn; のかわりに、 public Transform shotSpawn; 追加

void Update(){

Instantiate(shot, shotSpawn.position, shotSpawn.rotation);

}

このまま、Boltをshotの欄に、Shot SpawnをshotSpawnの欄にドラッグしてゲームスタートすると、連続して発射するプレイヤー機が見られる。

5)Fireボタンを押すと発射

コマンドマニュアルを開くと、サンプルコードが見られるので、それをコピペしてもいいのだが、
Input.GetButton(“Fire1”)
というコマンドはUnityに最初から設定済みである。

if(Input.GetButton(“Fire1”)を追加すると、左Ctrlキーかマウス左ボタンを押すと連続弾が発射される。

6)発射間隔を制限する工夫

fireRateという、射撃間隔を導入する。

それから計算すると、次の射撃は、nextFire = Time.deltaTime + fireRate になる。

public float fireRate;
private float nextFire;

void Update () {
if (Input.GetButton(“Fire1”) && Time.time > nextFire)
{
nextFire =Time.time+ fireRate;
Instantiate(shot, shotSpawn.position, shotSpawn.rotation);
}
}

fireRate の初期設定は秒当たり4発ぐらいでよさそうなので、0.25にする。

このままでは、実体化したBoltが山ほど溜まってしまうので、次の章では、境界線を超えたら、削除(destroy)するというプログラムを書く

ーーーーーーーーー

PlayerControllerに追加し、弾を撃てるようにする。

using UnityEngine;
using System.Collections;

[System.Serializable]
public class Boundary
{
public float xMin, xMax, zMin, zMax;
}

public class PlayerController : MonoBehaviour
{
public float speed;
public float tilt;
public Boundary boundary;
private Rigidbody rb;

public GameObject shot;
public Transform shotSpawn;
public float fireRate;

private float nextFire;

void Start () {
rb = GetComponent<Rigidbody>();
}

void Update ()
{
if (Input.GetButton(“Fire1”) && Time.time > nextFire)
{
nextFire = Time.time + fireRate;
Instantiate(shot, rb.shotSpawn.position, rb.shotSpawn.rotation);
}
}

void FixedUpdate ()
{
float moveHorizontal = Input.GetAxis (“Horizontal”);
float moveVertical = Input.GetAxis (“Vertical”);

Vector3 movement = new Vector3 (moveHorizontal, 0.0f, moveVertical);
rb.velocity = movement * speed;

rb.position = new Vector3
(
Mathf.Clamp (rb.position.x, boundary.xMin, boundary.xMax),
0.0f,
Mathf.Clamp (rb.position.z, boundary.zMin, boundary.zMax)
);

rb.rotation = Quaternion.Euler (0.0f, 0.0f, rb.velocity.x * -tilt);
}
}

ーーーーーーー