SlideShare a Scribd company logo
GenerativeArt—MadewithUnity
ティーチャートレーニングデイ
「認定プログラマー編」
ユニティ・テクノロジーズ・ジャパン株式会社
荒川 巧也
1
自己紹介
2
荒川 巧也
ユニティ・テクノロジーズ・ジャパン株式会社所属。
ユニティでは”トレーナー”として主に企業様向けに
Unityに関する導入講義実施や効率的な実装方法
のアドバイスを行っています。
Unity認定プログラマー試験
前提条件の内容:
• Unity を使用したビデオゲームまたは3D インタラクティブコンテンツ
のプ ログラミングの実務経験2 年以上
• C# を含むコンピュータープログラミングの実務経験2 年以上
• 構想から完成までソフトウェア開発ライフサイクル全般に携わった経
験
• ゲーム開発、インタラクティブエンターテイメント、デザインビジュアラ
イゼーションなど、Unity を使用したソフトウェア開発のための専門的な
ア プリケーションの知識
• キャラクターや環境の設定など、Unity でのビジュアル /3D アセット
および アニメーションパイプラインについての基本的な知識
(一部抜粋
3
認定プログラマー試験の試験範囲
   ・プログラミングの核となるインタラクション
   ・アートパイプラインでの作業
   ・アプリケーションシステムの開発
   ・シーンと環境デザインのためのプログラミング
   ・パフォーマンスとプラットフォームの最適化
   ・ソフトウェア開発チームでの作業
4
今回使用するUnityのバージョンなど
Unityのバージョン: Unity2019.4.8f1を使用します。
使用するプロジェクト:BaseProject_2019.4.8.1f
※以下のURLからダウンロード可能です。
https://drive.google.com/file/d/1L3WExri_sPexkMKz-OaJ0mQTLj4v88LH/view?usp
=sharing
5
Profiler
6
アセットストアからダウンロードする
*新規プロジェクトを作成しましょう!
7
新規プロジェクトを作成
8
3D Beginner : Complete Project
9
MainSceneを開く
10
Main Sceneが開く
11
Stats (Statics)
12
FPS :
1秒間に何フレーム処理を行えるか。
CPU:
メインスレッドとレンダリングスレッドに費やした時間
Batches:
Unityが複数のオブジェクトをレンダリングの際にまとめようとします。
Saved by batching :
まとまったバッチ数
SetPass Calls :
CPUからGPUに送られる描画命令(レンダリングパス)の数。
バッチ処理について
オブジェクトをスクリーンに描画するためには、グラフィックスAPI (OpenGL や Direct3D 等) に対してドローコールが必要です。グラフィックス
API はドローコールごとに非常に多くの処理をするため、ドローコールは高負荷で、CPU 側のパフォーマンスオーバーヘッドの原因になりま
す。これは大抵、ドローコール間に状況の変更(例えばマテリアルの切り替えなど) が発生することに起因し、グラフィックスドライバーで高負
荷な検証と変換処理の原因となります。
Unity では、それに対処するために2 つのテクニックが使用されます。
動的バッチ処理: かなり小さいメッシュ用に、その頂点を CPU 上に変換して多数の類似したものを群にし、ひとまとめにして
描画します。
静的バッチ処理: 静的 (つまり、動かない) ゲームオブジェクトを大きなメッシュと結合して、それを高速でレンダリングします。
13
https://docs.unity3d.com/ja/2019.4/Manual/DrawCallBatching.html
静的バッチ処理について
14
静的バッチ処理: 静的 (つまり、動かない)
ゲームオブジェクトを大きなメッシュと結
合して、それを高速でレンダリングしま
す。
Batching Staticにチェックを入れる
15
Batching Staticにチェックを入れた
16
Saved by batchingの値が上がっている
17
Edit → Project Settings
18
Profiler
Profilerを使うことによってCPUやGPU、メモリの負荷など再生することによって確認すること
ができます。「Window → Analysis → Profiler」
19
Profilerの役割
Profilerを使うことで現在のプロジェクトにおける負荷を視覚的に確認する。また Profilerを使うことで
具体的に負荷がかかる箇所を確認することができる。
プロジェクトの制作者は負荷がかかる原因を突き止めて負荷がなるべくかからないように検討するこ
とができる。
20
とりあえずゲームを再生してみます
21
Profilerの構成について
Profiler Modules
詳細
22
時間のかかっている処理を確認する
23
ボトルネックの探し方
処理負荷がかかっており 60FPS以下になっている。
24
Deep Profile
Deep Profileを使用すると、Unity標準の幾つかのAPIだけでなく、もっと深い階層のAPI
負荷も見れるようになります。
25
Deep Profileだと各関数の負荷を確認することもできる
26
モジュールを追加したり減らすことができる
27
実機でテストすることができます
28
おすすめの資料
29
https://www.slideshare.net/UnityTechnologiesJapan/unity-111054310
【CEDEC2018】一歩先のUnityでのパフォーマンス/メモリ計測、デバッグ術
Tips: occlusion culling
オクルージョンカリングは、あるオブジェクトが他のオブジェクトに隠されていて現在カメラに映
らないときに、オブジェクトのレンダリングを無効にする機能です。
https://docs.unity3d.com/ja/2018.4/Manual/OcclusionCulling.html
30
Occluder StaticとOccludee Staticにチェックを入れる
31
Window→Rendering→Occlusion Culling
32
Occlusion Cullingを有効にする
33
Occlusion Cullingのパラメータについて
34
Smallest Occluder:
Occlusion Cullingが有効になるオブジェクトの大きさ
Smallest Hole :
Occlusion Cullingが有効になるオブジェクトの最小の隙間
Backface Threshold:
100以下の値にすると積極的にデータを省こうとする。
Occlusion Cullingの効きを視覚で確認
35
他のオブジェクトに隠されていて現在カメラに映らないときに、オブ
ジェクトのレンダリングを無効にしています。
Backface Thresholdの効果について
36
Backface Thresholdの効果について
37
Tips : Physicsに関するパフォーマンス最適化
Fixed Timestep 設定 (Time ウィンドウ内) を調整して、物理演算の更新に費やす時間を削減できます。 Timestep を高くすると、物理演算の
精度を犠牲にして CPU のオーバーヘッドを削減します。多くの場合、精度を下げることと引き換えに速度を上げるのは許容できるトレードオ
フです。
Time ウィンドウで Maximum Allowed Timestep を 8–10FPS の範囲の設定し、最悪の場合の物理計算に要する時間を制限します。
メッシュコライダーはプリミティブコライダーよりもはるかに高いパフォーマンスオーバーヘッドを持っているため、使用を控えめ目にしてくださ
い。プリミティブコライダー付きの子オブジェクトを使用して、メッシュの形状を近似することが可能な場合もよくあります。子コライダーは、親の
リジッドボディによって単一の複合コライダーとして一括して制御されます。
ホイールコライダーは、厳密にはソリッドオブジェクトの意味でのコライダーではありませんが、それにもかかわらず、高い CPU のオーバー
ヘッドを持っています。
38
https://docs.unity3d.com/ja/2018.4/Manual/iphone-Optimizing-Physics.html (一部抜粋)
CapsuleColliderとMeshColliderの負荷の違いを確認します
新しいシーンを作成します
39
John Lemonをシーン上に追加する
40
John Lemonをシーン上に配置した
41
42
John Lemonを複製してCapsuleColliderとMeshColliderを付ける
Colliderを付けることができたらプレハブ化する
43
ObjInstatiation
MainCameraに追加
44
using UnityEngine;
public class ObjInstatiation : MonoBehaviour
{
public GameObject obj;
void Update()
{
if (Input.GetMouseButtonDown(0))
{
for (int y = 0; y < 10; y++)
{
for (int x = 0; x < 10; x++)
{
GameObject instantiatedObj = Instantiate(obj) as GameObject;
instantiatedObj.AddComponent<Rigidbody>();
instantiatedObj.transform.position = new Vector3(x, y, 0);
}
}
}
}
}
CapsuleColliderを追加したJohnLemonを追加
45
コンテンツを再生して左クリック
CapsuleColliderの追加モデルが生成される
46
同じようにMeshColliderを付けたJohnLemonを追加
47
MeshColliderの追加モデルが生成される
48
Tips: FrameDebugger
フレームデバッガー を使用すると、特定のフレーム上で実行されているゲームの再生を凍結し、
そのフレームをレンダリングするために使用されている個々の ドローコール を表示することがで
きます。同様に、ドローコールをリストとして、デバッガーはまた、それを1つずつ実行することが
できます。だから、シーンが、どのようにそのグラフィックエレメントから構成されていくかをとても
詳細に見ることができます。フレームデバッガウィンドウ (Window > Analysis > Frame
Debugger) は、drawcall 情報が表示され、構築中のフレームの playback を制御することがで
きます。
49
https://docs.unity3d.com/ja/2019.4/Manual/FrameDebugger.html
より詳しく確認できる
50
ベースとなるミニゲーム
(アソシエイト試験対策で制作したゲーム)
51
Object Pool
コンテンツ制作においてオブジェクトを生成(Instantiate)したり削除(Destroy)することは
一般的に行われています。ただし、オブジェクトの生成と削除は負荷がかかります。
Object Poolは一度生成したオブジェクトを非表示にして必要に応じて表示(有効化)して
使いまわす方法です。何度もオブジェクトを生成したり削除する必要がなくなるので負荷
を改善することができます。
52
このベースのミニゲームにObjectPoolを適用する
53
PlayerShootを開きます
→PlayerShootを開きます。
54
PlayerShoot.cs
ベースとなるプロジェクトを確認。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerShoot : MonoBehaviour {
public GameObject bullet; //PrefabのFireを追加
public Transform muzzle; //空のオブジェクトの muzzleを設定
public float bulletSpeed = 1000f;
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
   // 左クリックが押された時に
    if (Input.GetMouseButtonDown(0))
  {
// Fireを生成する  (シンプルにInstantiateをしている。 )
GameObject bullets = Instantiate(bullet) as GameObject;
// Fireの位置を調整する
bullets.transform.position = muzzle.position;
Vector3 bulletDirection;
bulletDirection = gameObject.transform.forward * bulletSpeed;
// Fireに力を加えて発射
bullets.GetComponent<Rigidbody>().AddForce(bulletDirection);
}
}
} 55
今のままだと左クリックの分だけ bulletを生成する
Object Pool 適用:
PlayerShoot
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerShoot : MonoBehaviour {
 public GameObject bullet;
 public Transform muzzle;
 public float bulletSpeed = 1000f;
Animator animator;
List<GameObject> bulletStocks;
// Start関数内でbulletを10個生成する
void Start()
{
animator = GetComponent<Animator>();
bulletStocks = new List<GameObject>();
for (int i = 0; i < 10; i++)
{
GameObject obj = (GameObject)Instantiate(bullet);
obj.SetActive(false);
bulletStocks.Add(obj);
}
}
//左クリックで押された数のBulletを有効化する
void Fire()
{
for (int i = 0; i < bulletStocks.Count; i++)
{
if (!bulletStocks[i].activeInHierarchy)
{
bulletStocks[i].transform.position = muzzle.transform.position;
bulletStocks[i].transform.rotation = muzzle.transform.rotation;
bulletStocks[i].SetActive(true);
Rigidbody bullet = bulletStocks[i].GetComponent<Rigidbody>();
bullet.AddForce(bullet.transform.forward * bulletSpeed);
break;
}
}
}
// Update is called once per frame
void Update () {
// z キーが押された時
if (Input.GetMouseButtonDown(0))
{
animator.SetTrigger("Attack");
Fire();
}
}
}
56
Bulletを開く
ベースとなるプロジェクトを確認。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Bullet : MonoBehaviour {
// Use this for initialization
void Start () {
Destroy(gameObject, 3.0f); //3秒後に削除
}
}
57
3秒後に削除される
Object Pool 適用:
Bullet
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Bullet : MonoBehaviour {
private void OnEnable() //オブジェクトがアクティブになったときに呼び出される
{
transform.GetComponent<Rigidbody>().WakeUp();
Invoke("HideBullet", 3.0f); //3秒後にHideBullet関数を呼び非アクティブ化する
}
void HideBullet()
{
gameObject.SetActive(false);
}
private void OnDisable() //オブジェクトが非アクティブになったときに呼び出される
{
transform.GetComponent<Rigidbody>().Sleep();
CancelInvoke();
}
}
58
EnemyControllerを開く
void OnCollisionEnter(Collision col)
{
if(col.gameObject.tag == "Bullet")
{
Destroy(col.gameObject);
TakeDamage(damageValue);
}
}
59
Bulletがカラスに当たった時に削除する。
EnemyControllerを書き直す
Destroyするかわりにオブジェクトを非アク
ティブ化する。void OnCollisionEnter(Collision col)
{
if(col.gameObject.tag == "Bullet")
{
//Destroy(col.gameObject);
col.gameObject.SetActive(false);
TakeDamage(damageValue);
}
}
60
Fireが生成されるようになった
61
ワークショップ1
カラスが生成される部分をObject Poolのパターンに書き直す
62
ワークショップ1
こちらをまず変更してみましょう
63
using UnityEngine;
using System.Collections;
public class EnemyManager : MonoBehaviour
{
public GameObject enemyPrefab; //Karasuのプレハブを追加する
public Transform[] spawnPoints; //Karasuの生成ポイントを追加する
public float interval = 3.0f; //Karasuの生成インターバル
float time = 0.0f;
void Update()
{
time += Time.deltaTime; //時間をはかる
if(time > interval) //インターバルの時間以上に過ぎれば
{
int spawnPointIndex = Random.Range(0, spawnPoints.Length); //生成ポイントをランダムで選ぶ
GameObject enemy = Instantiate(enemyPrefab,spawnPoints[spawnPointIndex].position,spawnPoints[spawnPointIndex].rotation); //Enemyを生成する
time = 0f; //時間を0秒に戻す
}
}
}
おすすめのチュートリアル
64https://learn.unity.com/tutorial/object-pooling#
コルーチン
我々になじみのあるStart関数やUpdate関数は基本的に順番に実行されて
おり、処理を途中で中断したり待機させたりすることができません。 コルー
チン(Coroutine)は処理を中断したり待機したり終了させることができます。
65
https://docs.unity3d.com/ja/2018.4/Manual/Coroutines.html
コルーチンを使った例using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CoroutineBase : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
StartCoroutine("CoroutineTest");
}
//コルーチン関数を定義
private IEnumerator CoroutineTest() //コルーチン関数の名前
{
Debug.Log("スタート");
yield return new WaitForSeconds(3.0f);
Debug.Log("スタートから3秒後経過した");
}
}
66
コルーチンを使った例
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CoroutineBase : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
StartCoroutine("CoroutineTest");
}
//コルーチン関数を定義
private IEnumerator CoroutineTest() //コルーチン関数の名前
{
//コルーチンの内容
Debug.Log("スタート");
yield return new WaitForSeconds(3.0f);
Debug.Log("スタートから3秒後経過した");
yield return new WaitForSeconds(5.0f);
Debug.Log("スタートから8秒後経過した");
}
}
67
コルーチンを使った例
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CoroutineBase : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
StartCoroutine("CoroutineTest");
}
//コルーチン関数を定義
private IEnumerator CoroutineTest() //コルーチン関数の名前
{
//コルーチンの内容
Debug.Log("スタート");
yield return new WaitForSeconds(3.0f);
Debug.Log("スタートから3秒後経過した");
yield return new WaitForSeconds(5.0f);
Debug.Log("スタートから8秒後経過した");
StartCoroutine("CoroutineCallTest");
}
IEnumerator CoroutineCallTest()
{
yield return new WaitForSeconds(2.0f);
Debug.Log("違うコールチンが呼ばれます");
}
}
68
Tips:Script Execution Order Setting
CallTest.cs
***********************
using UnityEngine;
public class CallTest : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
Debug.Log("ユニティの本社はアメリカにあります ");
}
}
***********************
SecondCall.cs
***********************
using UnityEngine;
public class SecondCall : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
Debug.Log("今日の夕食はカレーです ");
}
}
*********************** 69
異なるクラス間で、どのスクリプトの Start()が先に呼ばれるかを明示的に指定する方法を説明します。
Tips:Script Execution Order Setting
70
Tips:Script Execution Order Setting
「 Script Execution Order」を開きます。
① Edit > Project Settings > Script Execution Orderを開きます。
71
Tips:Script Execution Order Setting
② Script Execution Orderの「+」を押して登録したいスクリプトを選択します。
72
Tips:Script Execution Order Setting
③ スクリプトの実行順を設定します。
④ 実行順は、先に実行したいスクリプトが上で後に実行したいスクリプトは下に移動させます。
(正確には、数値が低い方が優先されます。標準のコンポーネントは実行順は 0です。)
CallTest.csを優先した場合:
73
Tips:Script Execution Order Setting
74
Tips:Script Execution Order Setting
SecondCall.csを優先した場合:
75
↓SecondCallを上にしている。
Tips:Script Execution Order Setting
76
*ここからプロジェクトに戻ります。
77
EnemyController
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI; //名前空間追加
public class EnemyController : MonoBehaviour
{
public int enemyHealth = 10;
public int damageValue = 5;
public Slider HpSlider;
NavMeshAgent nav; //NavimeshAgent型の変数
GameObject target; //ターゲット追加
// Use this for initialization
void Start()
{
nav = GetComponent<NavMeshAgent>(); //自分自身のNavMeshAgentを参照
target = GameObject.FindGameObjectWithTag("Player"); //targetにPlayerを参照
}
void Update()
{
nav.SetDestination(target.transform.position);
}
//*********************************************************************************
78
コルーチンを使った例:
using UnityEngine;
using UnityEngine.AI;
using System.Collections;
public class EnemyController : MonoBehaviour
{
public int enemyHealth = 10;
public int damageValue = 5;
public Slider HpSlider;
NavMeshAgent nav;
Transform target;
// Use this for initialization
void Start()
{
nav = GetComponent<NavMeshAgent>();
target = GameObject.FindGameObjectWithTag("Player").transform;
StartCoroutine(UpdateTargetPath());
}
IEnumerator UpdateTargetPath()
{
float refreshRate = 0.5f;
while (target != null)
{
Vector3 targetPosition = new Vector3(target.position.x, 0, target.position.z);
nav.SetDestination(targetPosition);
yield return new WaitForSeconds(refreshRate);
}
}
//*********************************************************************************
79
シーン移行にコルーチンを使用してみる
80
StartGameを開きます
81
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class StartGame : MonoBehaviour {
public void LoadNewScene()
{
SceneManager.LoadScene(1); //シーンを呼び出す
}
}
ロード確認用のスライダーを追加する
82
StartGameの中身を書き換え
83
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.SceneManagement;
public class StartGame : MonoBehaviour
{
[SerializeField] Slider slider;
AsyncOperation asyncLoad;
// Start is called before the first frame update
void Start()
{
StartCoroutine(LoadScene("Main"));
}
IEnumerator LoadScene(string name)
{
asyncLoad = SceneManager.LoadSceneAsync(name);
asyncLoad.allowSceneActivation = false;
slider.value = 0f;
while (true)
{
yield return null;
slider.value = asyncLoad.progress;
if (asyncLoad.progress >= 0.9f)
{
slider.value = 1f;
}
}
}
public void GoNextScene()
{
asyncLoad.allowSceneActivation = true;
}
}
次のシーンを先に読み込みを行います。
そして、ボタンが押された時には次のシーンを再生するようにしま
す。
Sliderを追加します
84
Scriptable Object
85
Scriptable Object
ScriptableObject は、クラスインスタンスとは無関係に、大量のデータを保存するために使
用できるデータコンテナです。ScriptableObject の主な使用例の 1 つは、値に対し複数の
コピーを避けることによってプロジェクトのメモリ消費を削減することです。これは、プロジェ
クトに、プレハブ (同じデータをアタッチした MonoBehaviour スクリプトに格納します) があ
る場合に便利です。プレハブは、インスタンス化するたびにそれぞれがデータのコピーを作
成します。
https://docs.unity3d.com/ja/2018.4/Manual/class-ScriptableObject.html
86
Scriptable Objectを使うと良いこと
プレハブでは、同じパラメータであっても
10、100と同じオブジェクトが生成
(Instantiate)するたびにこれらの変数がメ
モリに確保されてしまう。例えばパラメータ
の使用メモリが10KBだとしてプレハブが10
体いれば使用メモリは100KBになる。
それに対してScriptableObjectを使えば同
じ100体いても使用メモリは10KBのままで
ある。
87
Scriptable Objectの生成サンプル
using UnityEngine;
[CreateAssetMenu(menuName = "ScriptableObject/Create ParameterTable", fileName = "ParameterTable")]
public class ScriptableSample : ScriptableObject
{
public string name;
public int age;
public string occupation;
}
88
Scriptable Objectを生成する
89
パラメータを追加する
90
Scriptable Objectを読み込む
    ScriptableObjectTest
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ScriptableObjectTest : MonoBehaviour
{
public ScriptableSample sample;
// Start is called before the first frame update
void Start()
{
Debug.Log(sample.name);
Debug.Log(sample.age);
Debug.Log(sample.occupation);
}
}
91
Scriptable Objectを適用させる
92
Resourcesフォルダを作成しそこにScriptable Objectを追加
*動的にScriptable Objectを読み込む
93
動的にScriptableObjectを読み込み
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ScriptableObjectTest : MonoBehaviour
{
// public ScriptableSample sample;
// Start is called before the first frame update
void Start()
{
ScriptableSample sample = Resources.Load<ScriptableSample>("ParameterTable");
Debug.Log(sample.name);
Debug.Log(sample.age);
Debug.Log(sample.occupation);
}
}
94
ScriptableObjectが読み込まれた
95
カラスを複製してマテリアルを適用する
複製: Ctrl + D
Scriptable Objectを使ってカラスのパラメータを複数作ってみる
96
複製したカラスの色違いを作る
97
2種類のカラスプレハブができた
98
準備:EnemyControllerを以下のように変更する
public class EnemyController : MonoBehaviour {
int enemyHealth = 10;
int damageValue = 5;
int enemyScore = 10;
void TakeDamage(int damage)
{
enemyHealth -= damage;
HpSlider.value = (float)enemyHealth /10 ;
if (enemyHealth <= 0)
{
enemyHealth = 0;
ScoreManager.score += 10;
Destroy(gameObject);
}
}
void TakeDamage(int damage)
{
enemyHealth -= damage;
HpSlider.value = (float)enemyHealth /10 ;
if (enemyHealth <= 0)
{
enemyHealth = 0;
ScoreManager.score += enemyScore;
Destroy(gameObject);
}
} 99
CharacterManagerを作成する
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[CreateAssetMenu(fileName = "ScriptableObject/Create NewCharacter", menuName = "NewCharacter")]
public class CharacterManager : ScriptableObject
{
public int enemyHealth;
public int damageValue;
public int enemyScore;
}
100
Scriptable Objectを追加する
101
↑2つ用意する。
以下のようなパラメータにしてみた
102
EnemyControllerにScriptableObjectを読み込むようにする
103
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;
using UnityEngine.UI;
public class EnemyController : MonoBehaviour {
public CharacterManager characterParameter;
int enemyHealth = 10;
int damageValue = 5;
int enemyScore = 10;
int enemyMaxHealth; //EnemyのMaxの値代入するための変数を追加する
public Slider HpSlider;
NavMeshAgent nav;
GameObject target;
private void OnEnable()
{
enemyHealth = characterParameter.enemyHealth;
damageValue = characterParameter.damageValue;
enemyScore = characterParameter.enemyScore;
enemyMaxHealth = enemyHealth;
//enemyHealth = 10;
HpSlider.value = 1;
}
//以下は変更なし
EnemyControllerにScriptableObjectを読み込むようにする
104
void TakeDamage(int damage)
{
enemyHealth -= damage;
HpSlider.value = (float)enemyHealth /enemyMaxHealth ;
if (enemyHealth <= 0)
{
enemyHealth = 0;
ScoreManager.score += enemyScore;
//Destroy(gameObject);
gameObject.SetActive(false);
}
}
EnemyControllerにScriptableObjectに追加する
105
どちらかのカラスが生成されるにする
*実際にはObjectPoolが適用されたものに以下の変更部分を変更して書き直しましょう。
using UnityEngine;
using System.Collections;
public class EnemyManager : MonoBehaviour
{
public GameObject[] enemyPrefab;
public Transform[] spawnPoints;
public float interval = 3.0f;
float time = 0.0f;
void Update()
{
time += Time.deltaTime;
if(time > interval)
{
int enemyIndex = Random.Range(0, enemyPrefab.Length);
int spawnPointIndex = Random.Range(0, spawnPoints.Length);
GameObject enemy = Instantiate(enemyPrefab[enemyIndex],spawnPoints[spawnPointIndex].position, spawnPoints[spawnPointIndex].rotation);
time = 0f;
}
}
}
106
書き換える部分
(人によって書き方が違うと思いますので参考まで)
107
using UnityEngine;
using System.Collections;
using System.Collections.Generic; //追記
public class EnemyManager : MonoBehaviour
{
public GameObject[] enemyPrefab;
public Transform[] spawnPoints;
public float interval = 3.0f;
float time = 0.0f;
List<GameObject> enemyStocks;
private void Start()
{
enemyStocks = new List<GameObject>();
for (int i = 0; i < 10; i++) //10体生成
{
int enemyIndex = Random.Range(0, enemyPrefab.Length);
GameObject obj = (GameObject)Instantiate(enemyPrefab[enemyIndex]); //enemyPrefabを生成
obj.SetActive(false);
enemyStocks.Add(obj);
}
}
EnemyManagerにStrongKarasuとKarasuを追加
108
ランダムで2種類のカラスが生成されるようになる
109
パラメータの違うカラスが生成された
110
ワークショップ2
ScriptableObject読み込んでテキストのタイトルロゴの違う作ってみましょう
111
使用する素材はこちらにある
112
*このようにSciptableObjectを用意して読み込みます
113
Asset Bundle
114
Asset Bundleについて
AssetBundle (アセットバンドル) はランタイムに読み込むプラットフォーム特有のアセッ
ト (モデル、テクスチャ、プレハブ、オーディオクリップ、シーン全体) を含むアーカイブファ
イルです。アセットバンドルは互いの依存関係を示すことができます。例えば、アセットバ
ンドル A のマテリアルはアセットバンドル B のテクスチャを参照できます。ネットワークを
使った効果的な配布のために、アセットバンドルはその使用の要件に応じてビルトイン
のアルゴリズムの中の 1 つで圧縮されます (LZMA と LZ4)。
115
https://docs.unity3d.com/ja/2018.4/Manual/AssetBundlesIntro.html
サンプルでこのアセットをAssetBundle化してみます
116
Unityプロジェクトに取り込みます
117
アセットバンドル化します
118
アセットバンドル名を付ける
119
↑AssetBundleの名前を付けます。
大文字は使えません。
次は全て1つのアセットバンドルにまとめてみます
120
同じ”item”にまとめます
121
EditorフォルダにBuildAssetBundleスクリプトを追加
122
BuildAssetBundle (アセットバンドル化します)
123
using System.IO;
using UnityEditor;
public class BuildAssetBundle
{
// プロジェクト/AssetBundleItem フォルダの下にアセットバンドルビルドする
[MenuItem("Assets/Build AssetBundle")]
public static void Build()
{
var assetBundleDirectory = "./AssetBundleItem";
if (!Directory.Exists(assetBundleDirectory)) {
Directory.CreateDirectory(assetBundleDirectory);
}
BuildPipeline.BuildAssetBundles(assetBundleDirectory, BuildAssetBundleOptions.None, BuildTarget.StandaloneWindows);
// ビルド終了表示
EditorUtility.DisplayDialog("アセットバンドルビルド終了", "アセットバンドルビルドが終わりました。", "OK");
}
}
Assets → AssetBundle
124
アセットバンドルのファイルが生成される
125
LoadAssetBundleを追加する
126
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class LoadAssetBundle : MonoBehaviour
{
IEnumerator Start()
{
//itemアセットバンドルをロードします
var ab = AssetBundle.LoadFromFile("AssetBundleItem/item");
if (ab == null) {
yield break;
}
// ロードしたファイルの中から 4 Side Diamond(プレハブ) をロードして生成する
var prefab = ab.LoadAsset<GameObject>("4 Side Diamond");
Instantiate(prefab);
}
}
4 Side Diamondをロードすることができた
127
今度はアセットバンドルの中身を全てロードする
128
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class LoadAssetBundle: MonoBehaviour
{
IEnumerator Start()
{
var ab = AssetBundle.LoadFromFile("AssetBundleItem/item");
if (ab == null) {
yield break;
}
  //アセットバンドル化されていたプレハブを全て読み込んで生成する
var prefabs = ab.LoadAllAssets<GameObject>();
foreach (var prefab in prefabs)
{
Instantiate(prefab);
}
}
}
オブジェクトがロードされた
129
シーンデータのAssetBundle化について
130
アセットバンドルはオブジェクトだけでなくシーンごとアセットバンドル化できます。
*サンプルシーン Secondを作成します。
Secondシーンを”newscene”アセットバンドル化する
131
シーンを読み込みます
132
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class LoadNewSceneFromAssetBundle: MonoBehaviour
{
IEnumerator Start()
{
var ab = AssetBundle.LoadFromFile("AssetBundleItem/newscene");
if (ab == null) {
yield break;
}
// Secondシーンをロードする
yield return SceneManager.LoadSceneAsync("Second", LoadSceneMode.Additive);
}
}
LoadNewSceneFromAssetBundle
Secondシーンが読み込まれた
133
StreamingAssets
Unity プロジェクトにおける StreamingAssets と呼ばれるフォルダーに配置したファイルは
ビルド先のプラットフォームの、特定のフォルダーにそのまま何も変換されない状態で保持
されます。フォルダー名は Application.streamingAssetsPath プロパティーを取得するこ
とができます。プラットフォームごとに配置されるフォルダーの場所は異なるため、常に
Application.streamingAssetsPath を使用することをお勧めします。
134
https://docs.unity3d.com/ja/2018.4/Manual/StreamingAssets.html
AssetBundleファイルをStreamingAssetsから読み込む
“StreamingAssets”フォルダを作成する
135
テキストをAssetBundleにして読み込んでみる
136
HelloWorldというテキストを追加する
137
アセットバンドル”test”というラベル作成
138
新しい“ExportAssetBundleToStreamingAssets”をEditorフォルダに追加する
139
ExportAssetBundleToStreamingAssets
140
using UnityEngine;
using System.Collections;
using UnityEditor;
using System.IO;
public class ExportAssetBundleToStreamingAssets
{
[MenuItem("Assets/Build AssetBundles To StreamingAssets")]
public static void Build()
{
BuildPipeline.BuildAssetBundles("Assets/StreamingAssets",BuildAssetBundleOptions.None,BuildTarget.StandaloneWindows);
AssetDatabase.Refresh();
// ビルド終了を表示
EditorUtility.DisplayDialog("アセットバンドルの状態","アセットバンドルビルドが終わりました","OK");
}
}
AssetBundleファイルにビルドする
141
LoadAssetBundleFromAS
StreamingAssetsフォルダから読み込む
142
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.IO;
public class LoadAssetBundleFromAS : MonoBehaviour
{
IEnumerator Start()
{
AssetBundle ab = null;
// AssetBundleロード
yield return LoadFromStreamingAssets("test", x => ab = x); //アセットバンドル"test"をロードする
var texts = ab.LoadAllAssets<TextAsset>();
foreach (var text in texts)
Debug.Log(text);
// AssetBundleををアンロードする
ab.Unload(false);
}
IEnumerator LoadFromStreamingAssets(string assetBundleName, System.Action<AssetBundle> callback)
{
string path = Application.streamingAssetsPath + "/" + assetBundleName;
byte[] info = File.ReadAllBytes(path);
AssetBundleCreateRequest req = AssetBundle.LoadFromMemoryAsync(info);
yield return req;
callback(req.assetBundle);
}
}
プロジェクトを再生する
143
おすすめのチュートリアル素材
144
https://learn.unity.com/tutorial/assets-resources-and-assetbundles#
Editor拡張
145
Attribute
Attributeとは、日本語で「属性」という意味になります。クラスや変数に属性を追加する
ことで特別な挙動を追加することができます。
https://docs.unity3d.com/ja/2019.4/Manual/Attributes.html
example :
[SerializeField]
private int count;
146
Range 値の範囲を指定する
using UnityEngine;
using System.Collections;
public class HelloExtension : MonoBehaviour {
[Range(1,100)]
 public int level = 1;
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
Debug.Log (level);
}
}
147
Multilineusing UnityEngine;
using System.Collections;
public class HelloExtension : MonoBehaviour {
[Range(1,100)]
 public int level = 1;
[Multiline(5)]
 public string message;
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
Debug.Log (level);
Debug.Log (message);
}
}
148
[HideInInspector]
using UnityEngine;
using System.Collections;
public class HelloExtension : MonoBehaviour {
[Range(1,100)]public int level = 1;
[Multiline(5)]public string message;
[HideInInspector] public int x = 10;
// Use this for initialization
void Start () {
Debug.Log (x);
}
// Update is called once per frame
void Update () {
Debug.Log (level);
Debug.Log (message);
}
}
149
[SerializeField]
using UnityEngine;
using System.Collections;
public class HelloExtension : MonoBehaviour {
[Range(1,100)]public int level = 1;
[Multiline(5)]public string message;
[HideInInspector] public int x = 10;
[SerializeField] private int y = 5;
// Use this for initialization
void Start () {
Debug.Log (x);
Debug.Log (y);
}
}
150
Spaceusing UnityEngine;
using System.Collections;
public class HelloExtension : MonoBehaviour {
[Range(1,100)]public int level = 1;
[Multiline(5)]public string message;
[HideInInspector] public int x = 10;
[SerializeField] private int y = 5;
[Space(10.0f)]public float figure = 30;
// Use this for initialization
void Start () {
Debug.Log (x);
Debug.Log (y);
}
// Update is called once per frame
void Update () {
Debug.Log (level);
Debug.Log (message);
}
} 151
Header
using UnityEngine;
using System.Collections;
public class HelloExtension : MonoBehaviour {
[Range(1,100)]public int level = 1;
[Multiline(5)]public string message;
[HideInInspector] public int x = 10;
[SerializeField] private int y = 5;
[Header("プレイヤーのスピード ")]
[Space(10.0f)]public float speed = 30;
// Use this for initialization
void Start () {
Debug.Log (x);
Debug.Log (y);
}
// Update is called once per frame
void Update () {
Debug.Log (level);
Debug.Log (message);
}
}
152
エディター拡張
UnityはUnityエディタを自分でカスタマイズすることが可能です。
153
エディター拡張をする準備
“Editor”という特別な名前のフォルダーを作り、そ
の中にエディター拡張用のスクリプトを書いていくよ
うになります。
154
メニューに表示
using UnityEngine;
using UnityEditor;
using System.Collections;
public class CreateObject : EditorWindow {
[MenuItem ("Tools/ CreateObject")]
static void OpenWindow(){
}
}
155
Windowが表示されます
using UnityEngine;
using UnityEditor;
using System.Collections;
public class CreateObject : EditorWindow {
public static CreateObject window;
[MenuItem ("Tools/ CreateObject")] //メニュー項目を作る。
static void OpenWindow(){
window = (CreateObject)EditorWindow.GetWindow(typeof(CreateObject)); //ウィンドウを作る。
window.titleContent = new GUIContent("Create Object"); // ウィンドウ名を設定します。
}
}
156
クリックするとログが出るようにする
using UnityEngine;
using UnityEditor;
using System.Collections;
public class CreateObject : EditorWindow {
public static CreateObject window;
[MenuItem ("Tools/ CreateObject")]
static void OpenWindow(){
window = (CreateObject)EditorWindow.GetWindow(typeof(CreateObject));
window.titleContent = new GUIContent("Create Object"); // ウィンドウ名を設定します。
}
void OnGUI(){
if(GUI.Button(new Rect(0, 0, position.width, position.height), "クリックしてね")){
Debug.Log("クリックされた");
}
}
}
157
Cubeを生成する
using UnityEngine;
using UnityEditor;
using System.Collections;
public class CreateObject : EditorWindow
{
public static CreateObject window;
private GameObject cube;
[MenuItem("Tools/ CreateObject")]
static void OpenWindow()
{
window = (CreateObject)EditorWindow.GetWindow(typeof(CreateObject));
window.titleContent = new GUIContent("Create Object");
}
void OnGUI()
{
if (GUI.Button(new Rect(0, 80, 100, 100), "クリックしてね"))
{
Debug.Log("クリックされた");
}
if (GUI.Button(new Rect(100, 80, 100, 100), "キューブ"))
{
cube = GameObject.CreatePrimitive(PrimitiveType.Cube);
cube.transform.position = new Vector3(Random.Range(-5,5), Random.Range(-5, 5), Random.Range(-5, 5));
}
}
}
158
Cubeが生成されます
159
Unity Studentプランのご紹介
https://store.unity.com/ja/academic/unity-student
Unity Student には、5 シートの Unity Teams Advanced が付属します。
160
もっとUnityを学びたい方へ
https://unity.com/ja/products/unity-learn
161

More Related Content

PDF
【CEDEC2017】Unityを使ったNintendo Switch™向けのタイトル開発・移植テクニック!!
ODP
Unity ネイティブプラグインの作成について
PDF
UE4のローカライズ機能紹介 (UE4 Localization Deep Dive)
PDF
【Unite Tokyo 2018】Audio機能の基礎と実装テクニック
PDF
Unity道場08「絵づくりの基礎」ライティング虎の巻
PDF
ゲームの仕様書を書こう1 仕様書作成の分業とリストの作成
PPTX
Unity ゲーム開発
PDF
Epic Online Services でできること
【CEDEC2017】Unityを使ったNintendo Switch™向けのタイトル開発・移植テクニック!!
Unity ネイティブプラグインの作成について
UE4のローカライズ機能紹介 (UE4 Localization Deep Dive)
【Unite Tokyo 2018】Audio機能の基礎と実装テクニック
Unity道場08「絵づくりの基礎」ライティング虎の巻
ゲームの仕様書を書こう1 仕様書作成の分業とリストの作成
Unity ゲーム開発
Epic Online Services でできること

What's hot (20)

PDF
UnityのMultiplayサービスの得意な事
PDF
PlasticSCMの活用テクニックをハンズオンで一緒に学ぼう!
PDF
[CEDEC2017] 最新モバイルゲームの実例からみるUE4のモバイル向け機能・Tipsを全部まるっとご紹介!
DOCX
UE4でPerforceと連携するための手順
PDF
Unity2018/2019における最適化事情
PPTX
[CEDEC2018] UE4で多数のキャラクターを生かすためのテクニック
PDF
UE4におけるエフェクトの為のエンジン改造事例
PPTX
脱! 俺たちは雰囲気でBPをいじっている
PPTX
UnrealBuildTool勉強会まとめ
PDF
Editor Utility Widgetで色々便利にしてみた。
PDF
猫でも分かる UE4の新しいサンプル「Action RPG」について
PPTX
猫でも分かる UE4のAnimation Blueprintの運用について
PPTX
[4.20版] UE4におけるLoadingとGCのProfilingと最適化手法
PDF
UE4でマルチプレイヤーゲームを作ろう
PPTX
【Unity道場 博多スペシャル 2017】Textmesh proを使いこなす
PDF
ビジュアルスクリプティングで始めるUnity入門1日目 プレイヤーを動かそう
PPTX
アンリアルエンジン4で ノンフォトリアル描画しよう!@UNREAL FEST 2015 YOKOHAMA
PDF
SceneCapture2Dを使って壁の向こうを見る -気になるあの娘の部屋の壁-
PPTX
UE4のためのより良いゲーム設計を理解しよう!
UnityのMultiplayサービスの得意な事
PlasticSCMの活用テクニックをハンズオンで一緒に学ぼう!
[CEDEC2017] 最新モバイルゲームの実例からみるUE4のモバイル向け機能・Tipsを全部まるっとご紹介!
UE4でPerforceと連携するための手順
Unity2018/2019における最適化事情
[CEDEC2018] UE4で多数のキャラクターを生かすためのテクニック
UE4におけるエフェクトの為のエンジン改造事例
脱! 俺たちは雰囲気でBPをいじっている
UnrealBuildTool勉強会まとめ
Editor Utility Widgetで色々便利にしてみた。
猫でも分かる UE4の新しいサンプル「Action RPG」について
猫でも分かる UE4のAnimation Blueprintの運用について
[4.20版] UE4におけるLoadingとGCのProfilingと最適化手法
UE4でマルチプレイヤーゲームを作ろう
【Unity道場 博多スペシャル 2017】Textmesh proを使いこなす
ビジュアルスクリプティングで始めるUnity入門1日目 プレイヤーを動かそう
アンリアルエンジン4で ノンフォトリアル描画しよう!@UNREAL FEST 2015 YOKOHAMA
SceneCapture2Dを使って壁の向こうを見る -気になるあの娘の部屋の壁-
UE4のためのより良いゲーム設計を理解しよう!
Ad

Similar to Unityティーチャートレーニングデイ -認定プログラマー編- (20)

PDF
Unityティーチャートレーニングデイ -認定アソシエイト編-
PPTX
Practical game development with Stingray 2
PDF
Unityティーチャートレーニングデイ -認定3Dアーティスト編-
PDF
そうだプラグイン作ろう =Unityの巻=
PDF
UnityとBlenderハンズオン第8章
PDF
Editor スクリプティング 入門
PDF
徹底比較Unreal engine4&unity5
PDF
Unity2015_No3~Shooting~
PPTX
ゲームツクール!第11回 エディター拡張してみよう
PDF
ビジュアルスクリプティングシステムBoltを使ってみよう 1回目
PPTX
息抜きにUnityであそぼう(3D Game Kit Liteの話)
PDF
Kinect Camp with TMCN / Kinect入門ハンズオン 2015.06.06
PPTX
【Unity道場教育スペシャル】Unity認定プログラマー試験の試験範囲と試験対策方法について
PDF
iOSのUI構築小技集(小さなとこから始められる編)
PDF
UnityによるHoloLensアプリケーション入門
PDF
ノンプログラミングで始めようHoloLensコンテンツ開発
PDF
HoloLensハンズオン:Gaze,Tap And Hold編
PDF
機械学習 (AI/ML) 勉強会 #1 基本編
PDF
ARコンテンツ作成勉強会:Myoを用いたVRコンテンツ開発
PDF
Unityでこんなことができる KLab×博多Tech塾
Unityティーチャートレーニングデイ -認定アソシエイト編-
Practical game development with Stingray 2
Unityティーチャートレーニングデイ -認定3Dアーティスト編-
そうだプラグイン作ろう =Unityの巻=
UnityとBlenderハンズオン第8章
Editor スクリプティング 入門
徹底比較Unreal engine4&unity5
Unity2015_No3~Shooting~
ゲームツクール!第11回 エディター拡張してみよう
ビジュアルスクリプティングシステムBoltを使ってみよう 1回目
息抜きにUnityであそぼう(3D Game Kit Liteの話)
Kinect Camp with TMCN / Kinect入門ハンズオン 2015.06.06
【Unity道場教育スペシャル】Unity認定プログラマー試験の試験範囲と試験対策方法について
iOSのUI構築小技集(小さなとこから始められる編)
UnityによるHoloLensアプリケーション入門
ノンプログラミングで始めようHoloLensコンテンツ開発
HoloLensハンズオン:Gaze,Tap And Hold編
機械学習 (AI/ML) 勉強会 #1 基本編
ARコンテンツ作成勉強会:Myoを用いたVRコンテンツ開発
Unityでこんなことができる KLab×博多Tech塾
Ad

More from Unity Technologies Japan K.K. (20)

PDF
建築革命、更に更に進化!便利さ向上【Unity Reflect ver 3.0 】
PDF
UnityのクラッシュをBacktraceでデバッグしよう!
PDF
Unityで始めるバーチャルプロダクション
PDF
ビジュアルスクリプティング (旧:Bolt) で始めるUnity入門3日目 ゲームをカスタマイズしよう
PDF
ビジュアルスクリプティングで始めるUnity入門2日目 ゴールとスコアの仕組み - Unityステーション
PDF
点群を使いこなせ! 可視化なんて当たり前、xRと点群を組み合わせたUnityの世界 【Interact , Stipple】
PDF
Unity教える先生方注目!ティーチャートレーニングデイを体験しよう
PDF
「原神」におけるコンソールプラットフォーム開発
PDF
FANTASIANの明日使えない特殊テクニック教えます
PDF
インディーゲーム開発の現状と未来 2021
PDF
建築革命、更に進化!デジタルツイン基盤の真打ち登場【概要編 Unity Reflect ver 2.1 】
PDF
Burstを使ってSHA-256のハッシュ計算を高速に行う話
PDF
Cinemachineで見下ろし視点のカメラを作る
PDF
徹底解説 Unity Reflect【開発編 ver2.0】
PDF
徹底解説 Unity Reflect【概要編 ver2.0】
PDF
今だから聞きたい!Unity2017/18ユーザーのためのUnity2019 LTS基礎知識
PDF
【Unity Reflect】無料のViewerに機能が増えた!?~お披露目会編~
PDF
ビジュアルスクリプティングシステムBoltを使ってみよう 2回目
PDF
【Unity Reflect】足りない要素を追加してみよう~開発導入編~
PDF
【Unity Reflect】どんなものか試してみよう〜基礎編〜
建築革命、更に更に進化!便利さ向上【Unity Reflect ver 3.0 】
UnityのクラッシュをBacktraceでデバッグしよう!
Unityで始めるバーチャルプロダクション
ビジュアルスクリプティング (旧:Bolt) で始めるUnity入門3日目 ゲームをカスタマイズしよう
ビジュアルスクリプティングで始めるUnity入門2日目 ゴールとスコアの仕組み - Unityステーション
点群を使いこなせ! 可視化なんて当たり前、xRと点群を組み合わせたUnityの世界 【Interact , Stipple】
Unity教える先生方注目!ティーチャートレーニングデイを体験しよう
「原神」におけるコンソールプラットフォーム開発
FANTASIANの明日使えない特殊テクニック教えます
インディーゲーム開発の現状と未来 2021
建築革命、更に進化!デジタルツイン基盤の真打ち登場【概要編 Unity Reflect ver 2.1 】
Burstを使ってSHA-256のハッシュ計算を高速に行う話
Cinemachineで見下ろし視点のカメラを作る
徹底解説 Unity Reflect【開発編 ver2.0】
徹底解説 Unity Reflect【概要編 ver2.0】
今だから聞きたい!Unity2017/18ユーザーのためのUnity2019 LTS基礎知識
【Unity Reflect】無料のViewerに機能が増えた!?~お披露目会編~
ビジュアルスクリプティングシステムBoltを使ってみよう 2回目
【Unity Reflect】足りない要素を追加してみよう~開発導入編~
【Unity Reflect】どんなものか試してみよう〜基礎編〜

Unityティーチャートレーニングデイ -認定プログラマー編-