Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.
みくみくまうすの紹介
&
Unityにおけるコーディングノウハウ
とりすーぷ
12/20
プログラミング生放送勉強会
自己紹介
とりすーぷ (@toRisouP)
• 25歳
• 某Web企業でエンジニアやってる
• 趣味でいろいろ開発してる
– 一番得意な言語はC#
– 最近はずっとUnityいじってる
– あとUniRxが最近のマイトレンド
過去に作ったもの
交通事故・渋滞シミュレータ
(sm16238908)
NITORI BOX
(東方2次創作ゲーム)
ユニティちゃんゴーストマンション
(OculusGameJam2014)
今作ってるもの
みこバト~レ
• 東方2次創作ゲーム
• UnityとPhotonCloudを使ったネット対戦ゲーム
• プログラマは自分1人だけ(いろいろツライ)
本題
今回話すこと
• 「みくみくまうす」の紹介
• コーディングする上で意識すべきこと
• Unity開発で活用できるC#の機能
みくみくまうす
• ニコ生の配信支援ツール
• MMDモデルがニコ生のコメントを読み上げてくれる
• 配信ツールでクロマキー合成して映像に合成して使う
ゲーム配信で使ったり
プログラミング生放送で使ってみたり
たくさん配置してみたり
生放送を盛り上げるためのツール
みんなニコ生しようぜ
機能
• コメントの読み上げ
– 棒読みちゃんの設定次第でボイスロイドも使用可能
• コメントの感情解析
– コメントの内容でキャラクタのリアクションが変わる
• 複数キャラの同時使用
– コメントカラーで読み上げのフィルタリングができる
• ...
作った経緯
知人同士でニコ生を配信し、
自身のニコニココミュニティのレベルを
目標値まで先に上げた人が勝ち
(コミュニティレベルは自分をお気に入り登録した人の数で決まる)
※優勝者は鰻が奢りになるから「鰻レース」と呼んでた
作った経緯2
女性の方のコミュレベルがどんどん上がっていく
(ただ顔出し放送するだけで入れ食い状態)
おっさんがただ配信するだけでは華がなく絶対に勝てない
だったら画面に女の子がいれば華があって人がくる?
あと自分はエンジニアなのでそこは武器に...
しくみ
コメビュ
(やりますアンコちゃん/NCV)
棒読みちゃん
• みくみくまうす用プラグインを作成
• ニコ生からコメントを取得
• コメントのフィルタリング/解析
• 口パクと発声依頼
• 実際に読み上げる
• VoiceroidTalk...
つかったもの
• Unity Pro 4.6(βのころから使ってた)
• ユニティちゃん(とそのアニメーション)
• MMD4Mecanim
• MeCab(NMeCab)
• LitJSON
みくみくまうすは「ユニティちゃんライセンス」で提供...
ここまでは概要
この場は「プログラミング生放送勉強会」
実装の話を少しします
実装について話すこと一覧
• MMDモデルのインポート
• コメビュとの通信
• 口パク
• コメントの感情解析
• 設定ファイルの読み書き
• デスクトップマスコットモード
実装について話すこと一覧
• MMDモデルのインポート
• コメビュとの通信
• 口パク
• コメントの感情解析
• 設定ファイルの読み書き
• デスクトップマスコットモード
MMDのインポート
• MMD4Mecanimを使用すると簡単にインポートできる
– 付属のスクリプトがかなり充実している
– ただしモデルの動的ロードには対応していない
• 後述のライセンスの問題もある
MMDモデルのライセンス
• ゲームで使用して良いかは作者への確認が必要
– 作者によってライセンスがバラバラ
– Readmeに明記されていないことが多い
実装について話すこと一覧
• MMDモデルのインポート
• コメビュとの通信
• 口パク
• コメントの感情解析
• 設定ファイルの読み書き
• デスクトップマスコットモード
コメビュとの通信
• コメビュ用プラグインを作って導入
– TCP接続で待ち受ける(コメビュ側がホスト)
– 複数クライアントの同時接続に対応
– コメント情報のデータフォーマットはJSON
• コメビュとの通信Componentも作成
– コ...
Unityでニコ生のコメントを取得したいとき
• CommentViewer2Unity
– コメビュプラグインからコメントを取得するComponent
– 使用にはLitJSONが必要
– https://github.com/TORISOU...
【余談】UnityでJsonを使う
• Unityでは標準ではJsonが扱えない
• Jsonライブラリを入れる必要がある
– MiniJSON
– JSONObject
– LitJSON ← 自分はこれを使ってる
そもそもJsonとは
• JavaScript向けに作られたデータ記述言語
– 数値
– 文字列
– Boolean
– 配列
– 連想配列
– Null
※要するに各値をテキストデータに変換する時のフォーマットの一つ
LitJSONの使い方
• オブジェクトをJSON化する
LitJSONの使い方
• JSONからオブジェクトに変換する
ToObject<T>()を使えば良い
ただし
• 変換に失敗すると例外が飛ぶ
• floatは使えない(doubleを使うこと)
• 値の中身がnullだった時の扱い(null許...
Jsonで値が送られてこなかった時の判別方法
• Null許容型
構造体(値型)にnullが入ることを許容する
「Jsonの中身にNoの要素が無かった」
・非Null許容型int → 0で初期化(0が送られてきたのか判断不能)
・Null許容型...
実装について話すこと一覧
• MMDモデルのインポート
• コメビュとの通信
• 口パク
• コメントの感情解析
• 設定ファイルの読み書き
• デスクトップマスコットモード
口パク
• MMD4MecanimSpeechHelperで簡単にできる
– MMDモデルはこのスクリプトで口パクできる
– ただしこのSpeechHelperはMMDモデルにのみ使える
– ユニティちゃんは別にスクリプトを自作して対応
• ク...
口パク機構の管理
• インターフェースを用いて呼び出し元の処理を統一
SpeechTextController
読み上げるコメントの
管理を行う
MMD4MecanimSpeechHelper
MMD向け口パクComponent
インターフェー...
口パク用のコメントひらがな変換
• 口パクさせる為にコメントのひらがな化を行う
– NMeCabを使ってひらがな化
– KakasiはGPLライセンスだったので避けた
実装について話すこと一覧
• MMDモデルのインポート
• コメビュとの通信
• 口パク
• コメントの感情解析
• 設定ファイルの読み書き
• デスクトップマスコットモード
コメント感情解析
• コメントの内容に応じてリアクションが変化する
リアクションするキーワードの例
• 挨拶 (「わこつ」、「初見」など)
• 挙手 (ノ)
• 笑い (wを含むコメント、「吹いた」「ワロス」など)
• 絶叫 (あああああ! など)
• ツッコミ (「おまえが言うな」「やめてー><」など)
• ...
コメント感情解析の仕組み
• ニコニコ動画コメント@ばっちりサーチ.net
– こちらのnode.js用モジュールをC#に移植
• https://github.com/TORISOUP/CommentAnalyzerCSharp
– 中身は鬼...
実装について話すこと一覧
• MMDモデルのインポート
• コメビュとの通信
• 口パク
• コメントの感情解析
• 設定ファイルの読み書き
• デスクトップマスコットモード
設定パネル
設定ファイル
• パラメータをJsonでテキストに保存(.NETの機能)
– PlayerPrefsはレジストリに保存されるので使いたくない
– バイナリにシリアライズして保存すると後から変更しにくい
– 読み込み時にバリデーションを入れる必要...
実装について話すこと一覧
• MMDモデルのインポート
• コメビュとの通信
• 口パク
• コメントの感情解析
• 設定ファイルの読み書き
• デスクトップマスコットモード
デスクトップマスコットモード
• こちらのAssetを使わせて頂きました
• オススメです
みくみくまうすのまとめ
• ニコ生配信支援ツール
• フリーソフトとして配布中
• 生放送を盛り上げるのに使ってね!!!
• プログラミング生放送でも使おう!!
• 使うときは「みくみくまうす」のタグを付けてくれるとエゴサしやすくて助かります
ステッカー
• 調子に乗ってステッカーも作りました
– 数に限りがあるので欲しい人は1人1枚お持ち下さい
– 割りと安い(100枚刷って4000円くらい)
くぎり
• みくみくまうすについての質問とかあれば
続いて「コーディングする上で意識すべきこと」→
コーディングする上で
意識すべきこと
おしながき
• 名前
• 機能の分離
• SOLID原則
• MVCパターン
おしながき
• 名前
• 機能の分離
• SOLID原則
• MVCパターン
名前
わかりやすい名前をつけろ!!!!!
例)メソッド名
• メソッド名から処理内容が判断できるべき
– メソッド名が長くなるのは構わない(限度はあるが)
– 例)GetNearestEnemyFromPlayer
• 誤解される名前をつけるな
– Get*()なのに副作用がある
• ...
おすすめの本
リーダブルコード ―より良いコードを書くためのシンプ
ルで実践的なテクニック
おしながき
• 名前
• 機能の分離
• SOLID原則
• MVCパターン
機能の分離
• Unityに依存しないコードを書こう
– なんでもかんでもMonoBehaviourを継承させない
– Unityからゲームロジックを分離する
– Unity以外でもそのまま使えると良い
– 単体テスト書きやすくなる
おしながき
• 名前
• 機能の分離
• SOLID原則
• MVCパターン
SOLID原則
• オブジェクト指向開発を行う上での5つの原則
– 単一責任の原則(SRP)
– オープン・クローズドの原則(OCP)
– リスコフの置換原則(LSP)
– 依存関係逆転の原則(DIP)
– インターフェース分離の原則(ISP)...
SOLID原則
• 単一責任の原則(SRP)
• オープン・クローズドの原則(OCP)
• リスコフの置換原則(LSP)
• 依存関係逆転の原則(DIP)
• インターフェース分離の原則(ISP)
単一責任の原則
「クラスを変更する理由は1つ以上存在してはならない」
「一つのクラスに複数の責務を持たせるな」
• 馬鹿でかいクラスは管理しにくい
• 1つのクラスにあれこれ機能を詰め込むな
• クラス名以上の責務は負わせるな
悪い例
• PlayerController(プレイヤキャラクタの制御)
– Inputの受け付け
– キャラクタの移動処理
– キャラクタの攻撃処理
– キャラクタの体力の管理
– アニメーション再生の管理
– エフェクト再生の管理
– 効果...
適切に分離しよう
• PlayerInputManager
– Inputの受け付け
• PlayerController
– キャラクタの移動処理
– キャラクタの攻撃処理
– キャラクタの体力の管理
• PlayerView
– アニメーシ...
SOLID原則
• 単一責任の原則(SRP)
• オープン・クローズドの原則(OCP)
• リスコフの置換原則(LSP)
• 依存関係逆転の原則(DIP)
• インターフェース分離の原則(ISP)
オープン・クローズドの原則
「モジュールの振る舞いの拡張に対してオープンである」
「モジュールの振る舞いの修正に対してクローズドである」
• 機能追加は簡単にできる
• 機能追加によって他のコードを書き換える必要はない
• 要するに「ポリモーフ...
オープン?クローズド?
• あとから簡単に機能追加できるようにしろ
– インターフェースを実装すれば機能追加できる(オープン)
– 実クラスが増えても元のコードに変更はなし(クローズド)
SpeechTextController
読み上げるコメ...
オープン?クローズド?
• あとから簡単に機能追加できるようにしろ
– インターフェースを実装すれば機能追加できる(オープン)
– 実クラスが増えても元のコードに変更はなし(クローズド)
SpeechTextController
読み上げるコメ...
オープン?クローズド?
• あとから簡単に機能追加できるようにしろ
– インターフェースを実装すれば機能追加できる(オープン)
– 実クラスが増えても元のコードに変更はなし(クローズド)
SpeechTextController
読み上げるコメ...
オープン?クローズド?
• あとから簡単に機能追加できるようにしろ
– インターフェースを実装すれば機能追加できる(オープン)
– 実クラスが増えても元のコードに変更はなし(クローズド)
SpeechTextController
読み上げるコメ...
SOLID原則
• 単一責任の原則(SRP)
• オープン・クローズドの原則(OCP)
• リスコフの置換原則(LSP)
• 依存関係逆転の原則(DIP)
• インターフェース分離の原則(ISP)
リスコフの置換原則
「派生クラスは基底クラスで定めたルールを破ってはいけない」
• 基底クラスで定義された部分は派生クラスと置換可能である
• 派生クラスは基底クラスと全く同じ仕事ができなくてはいけない
リスコフの置換原則に違反した例
例)移動メソッドMove(Vector3 direction)
基底クラス:引数に方向ベクトルを与える(長さ1のベクトル)
移動速度は内部の状態に基づいて決まる
派生クラス:引数に速度ベクトルを与える
移動速度は...
SOLID原則
• 単一責任の原則(SRP)
• オープン・クローズドの原則(OCP)
• リスコフの置換原則(LSP)
• 依存関係逆転の原則(DIP)
• インターフェース分離の原則(ISP)
依存関係逆転の原則
「上位モジュールは下位モジュールに依存してはならない。
どちらのモジュールもインターフェースに依存すべきである」
• インターフェースを使え
• 実クラスへの参照を無くしてインターフェースに依存させろ
関係の逆転?
• 上位から下位に依存した関係(ダメな例)
– 上位モジュールが下位モジュールに依存
– 実クラスそのものを参照してしまっている
– 実クラスの変更の影響を上位モジュールが受けやすい
InputManager
入力を管理する
Pl...
関係を逆転させる
• 下位から上位に依存させる
– 上位のレイヤにインターフェースを作成
– 上位モジュールはインターフェースを参照する
– オープン・クローズドの原則も同時に満たされる
InputManager
入力を管理する
PlayerR...
SOLID原則
• 単一責任の原則(SRP)
• オープン・クローズドの原則(OCP)
• リスコフの置換原則(LSP)
• 依存関係逆転の原則(DIP)
• インターフェース分離の原則(ISP)
インターフェース分離の原則
「クライアントにクライアントが本来依存しないメソッドへの依存性を強制して
はならない」
• 不必要なメソッドまでクライアントに提供しない
• インターフェースを適切に分割して提供しろ
インターフェース分離の原則に違反した例
InputManager
入力を管理する
PlayerReimu
プレイヤ(霊夢)
PlayerMarisa
プレイヤ(魔理沙)
PlayerYoumu
プレイヤ(妖夢)
インターフェース
IPlayer...
• IPlayerInputインターフェースを各クラスが実装
– PlayerMarisaに「盗む Steal()」を増やしたい
– IPlayerInputに追加してしまった
インターフェース分離の原則に違反した例
InputManager
...
• 関係の無い他のクラスまで影響を受けてしまう
– 使わないのに実装しないといけない
インターフェース分離の原則に違反した例
InputManager
入力を管理する
PlayerReimu
プレイヤ(霊夢)
PlayerMarisa
プレイヤ...
インターフェースを分離する
InputManager
入力を管理する
PlayerReimu
プレイヤ(霊夢)
PlayerMarisa
プレイヤ(魔理沙)
PlayerYoumu
プレイヤ(妖夢)
インターフェース
IPlayerInput
...
SOLID原則のまとめ
• 機能は分割して作れ
• インターフェースを使え
• モジュールの依存関係を疎結合にしろ
UnityとSOLID原則
• Componentは機能単位で分割して作るべき
– クラス名以上の責務は負わせるべきではない
– コードの記述量は増えるが、わかりやすくなる
• Componentはインターフェースを介してやりとりするべき
– ...
おしながき
• 名前
• 機能の分離
• SOLID原則
• MVCパターン
MVCパターン
• Model View Controller
– GUIを持つアプリケーションで用いられるデザインパターン
– 機能を以下の3つに分離する
Controller
(ユーザからの入力)
Model
(実データやロジック)
Vie...
UnityとMVC
• プレイヤの制御がMVCパターンと相性がいい
– プレイヤ制御を以下のMVCに分離してしまう
Controller
(ユーザからの入力)
Model
(実データやロジック)
View
(描画処理)
Input周りの処理
•...
プレイヤ制御とMVC
• MVC分割のメリット
– Componentの責務が明確になる(単一責任の原則)
– 入力機器の差異をControllerの差し替えで対応できる
– ネットワーク同期も簡単になる
MVC分割でSOLID原則を満たすなら
• インターフェースを切ってそこに依存させる
Controller
(ユーザからの入力)
Model
(実データやロジック)
View
(描画処理)
インターフェース
IPlayerController
...
実例
• ユニティちゃんゴーストマンション
– MVCが分離されているのでそれぞれ個別に開発できる
– ゲームジャムで役に立った
←Controller
←Model
←View
←ネットワーク同期用
スクリプト
「意識するべきこと」まとめ
• わかりやすさ最優先でコードを書くべき
• Unityへの依存は断ち切ろう
• SOLID原則を意識した設計にしよう
• インターフェースを活用しよう
• MVCパターンは割りと使えるかもしれない
Unityで活用できる
C#の機能
おしながき
• 拡張メソッド
• LINQ
• UniRx(※ C#の機能では無い)
おしながき
• 拡張メソッド
• LINQ
• UniRx
拡張メソッド
• クラスに外からインスタンスメソッドを追加する
– staticメソッドを「あたかもそのクラスが持っているメソッド」を呼び出す
かの様に記述できるようになる機能
– 実際はただのstaticメソッドの呼び出し
static cl...
拡張メソッドを使うと便利な例
• Vector3のy成分を無視した水平面での方向を計算
– 進行方向にプレイヤを向かせるときに使うことが多い
• y成分を含ませると身体が傾く
進行方向
鉛直方向を無視した
水平面での方向ベクトル
拡張メソッド)水平面での方向ベクトルを取得
• Vector3型への拡張メソッドとして定義する
– 拡張メソッドを収めるstatic classを定義
– その中にstaticメソッドを追加
– 第一引数のVector3にthisを付ける
拡張メソッド)実際に使ってみる
• Vector3に最初から生えているメソッドとして振る舞う
– Vector3を継承することなく、Vector3をカスタマイズできた
拡張メソッドまとめ
• 標準で足りない機能をガンガン追加していこう
– Vector3とかMomoBehaviourとかに追加すると便利になる
– 自分なりにカスタマイズしてしまおう
• 拡張メソッドの定義はわかりやすくしておく
– どこに定義...
拡張メソッド
• 自分が追加した拡張メソッド群(一部)
– Vector3
• ベクトルの要素ごとの積
• 2点間の距離の計算
• 水平面での距離の計算
• 水平面での方向ベクトルの計算
• x,y,zそれぞれの上書き
– Transform
...
おしながき
• 拡張メソッド
• LINQ
• UniRx
LINQ
• 統合言語クエリ(LINQ)
– 様々なデータソースに対する操作を統合的に記述するもの
– 特にLINQ to Objects(コレクション)がよく使われる
– せっかくのC#なのになぜLINQ使わないのか!?!?!?!?
LINQ to Objectで何ができるか?
• コレクションに対する操作を簡単に記述できる
– コレクション(配列、リスト、ディクショナリとか)
– 複雑な処理をわかりやすく記述できる
LINQメソッドの例 処理の内容
Where 条件を満た...
例)LINQを使わずに書く
• TagがEnemy
• 指定座標から半径10m未満
• Transformのリスト
をGameObject配列から取得するメソッドをLINQを使わずに定義
例)LINQを使わずに書く
• TagがEnemy
• 指定座標から半径10m未満
• Transformのリスト
をGameObject配列から取得するメソッドをLINQを使わずに定義
本当に正しいかの確認が大変
これを毎回読み解くのか?
例)LINQを使った場合
例)LINQを使った場合
1. gameObjectArrayに対して
2. TagがEnemyのものだけ
3. 指定座標から10m未満のものだけ
4. Transformに変換して
5. List形式にまとめて返す
• 順番に上から読むだけで...
LINQまとめ
• C#を使ってるなら是非使うべき機能
– ちゃんと使えばコード中からfor文を無くせる
– LINQを使わずして何がC#か
• 普通にループを書くより処理速度は落ちる
– LINQによって実行速度が問題になるようなことはほぼ無...
おしながき
• 拡張メソッド
• LINQ
• UniRx
Rx(UniRx)
• ReactiveExtensions(Rx)
– LINQの概念を「非同期」「イベント」に拡張したもの
– 時間を跨いだ処理を簡単に記述できる
– UniRxはRxのUnity移植版(neueccさん作)
• ちゃんと解...
UnityでRxを使う
Rxの概念
• イベントをストリームとして扱う
– イベントって時間軸に並んだコレクションじゃね?
– コレクションならLINQで扱えるんじゃね?
t
Rxの使い道
• イベントの代わりに使う(ストリームを作る)
– Subject<T>を使えばストリームが作れる
– 既存のEventの上位互換(むしろEventはレガシー)
• ストリームの終了、エラーを通知できる
• イベントの複雑な処理
...
UniRxの例
• マウスのダブルクリックの検知
– 普通に書くと煩雑な処理がたった数行で終わった
– 状態の一時保管用のフィールドの定義不要
Rxのまとめ
• 時間やフレームを跨いだ処理を簡単に記述できる
• 使いこなすとUpdate()の中身が短くなる
• 学習コストは高め
とにかく便利なので使ってみるべし
「C#の機能」まとめ
• C#には便利な機能がたくさんある
– C#っぽくない書き方のコード多くて悲しい
– 使いこなすと強力な武器になるので使うべし
• Rx楽しい
– 本当に便利なのでもっと流行るべき
最後にまとめ
• みくみくまうす使ってね
– みんな生放送やろうぜ
– せっかく作ったんだから使って欲しい
• Unityの開発力は最終的にコーディング能力に行き着く
– 複雑なことやるには結局スクリプトを書かないといけない
– プログラミング...
ありがとうございました
みくみくまうすについて&Unity で使えるコーディングノウハウ
Upcoming SlideShare
Loading in …5
×

みくみくまうすについて&Unity で使えるコーディングノウハウ

7,195 views

Published on

2014/12/20 プログラミング生放送勉強会 第32回@GMO Yours で発表した講演資料です

・ニコ生配信支援ツール「みくみくまうす」についての紹介

・コーディングする上で意識すべきこと
-名前の付け方
-機能の分離
-SOLID原則
-MVCパターンとUnity

・C#の便利機能
-拡張メソッド
-LINQ
-UniRx

Published in: Technology
  • Be the first to comment

みくみくまうすについて&Unity で使えるコーディングノウハウ

  1. 1. みくみくまうすの紹介 & Unityにおけるコーディングノウハウ とりすーぷ 12/20 プログラミング生放送勉強会
  2. 2. 自己紹介 とりすーぷ (@toRisouP) • 25歳 • 某Web企業でエンジニアやってる • 趣味でいろいろ開発してる – 一番得意な言語はC# – 最近はずっとUnityいじってる – あとUniRxが最近のマイトレンド
  3. 3. 過去に作ったもの 交通事故・渋滞シミュレータ (sm16238908) NITORI BOX (東方2次創作ゲーム) ユニティちゃんゴーストマンション (OculusGameJam2014)
  4. 4. 今作ってるもの みこバト~レ • 東方2次創作ゲーム • UnityとPhotonCloudを使ったネット対戦ゲーム • プログラマは自分1人だけ(いろいろツライ)
  5. 5. 本題 今回話すこと • 「みくみくまうす」の紹介 • コーディングする上で意識すべきこと • Unity開発で活用できるC#の機能
  6. 6. みくみくまうす • ニコ生の配信支援ツール • MMDモデルがニコ生のコメントを読み上げてくれる • 配信ツールでクロマキー合成して映像に合成して使う
  7. 7. ゲーム配信で使ったり
  8. 8. プログラミング生放送で使ってみたり
  9. 9. たくさん配置してみたり
  10. 10. 生放送を盛り上げるためのツール みんなニコ生しようぜ
  11. 11. 機能 • コメントの読み上げ – 棒読みちゃんの設定次第でボイスロイドも使用可能 • コメントの感情解析 – コメントの内容でキャラクタのリアクションが変わる • 複数キャラの同時使用 – コメントカラーで読み上げのフィルタリングができる • デスクトップマスコットモード – ウィンドウからキャラクタが独立して表示される
  12. 12. 作った経緯 知人同士でニコ生を配信し、 自身のニコニココミュニティのレベルを 目標値まで先に上げた人が勝ち (コミュニティレベルは自分をお気に入り登録した人の数で決まる) ※優勝者は鰻が奢りになるから「鰻レース」と呼んでた
  13. 13. 作った経緯2 女性の方のコミュレベルがどんどん上がっていく (ただ顔出し放送するだけで入れ食い状態) おっさんがただ配信するだけでは華がなく絶対に勝てない だったら画面に女の子がいれば華があって人がくる? あと自分はエンジニアなのでそこは武器になるのでは? MMDモデルがコメントを読み上げてくれるツールを作ろう
  14. 14. しくみ コメビュ (やりますアンコちゃん/NCV) 棒読みちゃん • みくみくまうす用プラグインを作成 • ニコ生からコメントを取得 • コメントのフィルタリング/解析 • 口パクと発声依頼 • 実際に読み上げる • VoiceroidTalkPlusを使えばボイスロ イドでも読み上げできる TCP Socket TCP Socket
  15. 15. つかったもの • Unity Pro 4.6(βのころから使ってた) • ユニティちゃん(とそのアニメーション) • MMD4Mecanim • MeCab(NMeCab) • LitJSON みくみくまうすは「ユニティちゃんライセンス」で提供されています
  16. 16. ここまでは概要 この場は「プログラミング生放送勉強会」 実装の話を少しします
  17. 17. 実装について話すこと一覧 • MMDモデルのインポート • コメビュとの通信 • 口パク • コメントの感情解析 • 設定ファイルの読み書き • デスクトップマスコットモード
  18. 18. 実装について話すこと一覧 • MMDモデルのインポート • コメビュとの通信 • 口パク • コメントの感情解析 • 設定ファイルの読み書き • デスクトップマスコットモード
  19. 19. MMDのインポート • MMD4Mecanimを使用すると簡単にインポートできる – 付属のスクリプトがかなり充実している – ただしモデルの動的ロードには対応していない • 後述のライセンスの問題もある
  20. 20. MMDモデルのライセンス • ゲームで使用して良いかは作者への確認が必要 – 作者によってライセンスがバラバラ – Readmeに明記されていないことが多い
  21. 21. 実装について話すこと一覧 • MMDモデルのインポート • コメビュとの通信 • 口パク • コメントの感情解析 • 設定ファイルの読み書き • デスクトップマスコットモード
  22. 22. コメビュとの通信 • コメビュ用プラグインを作って導入 – TCP接続で待ち受ける(コメビュ側がホスト) – 複数クライアントの同時接続に対応 – コメント情報のデータフォーマットはJSON • コメビュとの通信Componentも作成 – コメビュからコメントを取得する – 実際の通信を行う機構はUnityと分離してある
  23. 23. Unityでニコ生のコメントを取得したいとき • CommentViewer2Unity – コメビュプラグインからコメントを取得するComponent – 使用にはLitJSONが必要 – https://github.com/TORISOUP/CommentViewer2Unity
  24. 24. 【余談】UnityでJsonを使う • Unityでは標準ではJsonが扱えない • Jsonライブラリを入れる必要がある – MiniJSON – JSONObject – LitJSON ← 自分はこれを使ってる
  25. 25. そもそもJsonとは • JavaScript向けに作られたデータ記述言語 – 数値 – 文字列 – Boolean – 配列 – 連想配列 – Null ※要するに各値をテキストデータに変換する時のフォーマットの一つ
  26. 26. LitJSONの使い方 • オブジェクトをJSON化する
  27. 27. LitJSONの使い方 • JSONからオブジェクトに変換する ToObject<T>()を使えば良い ただし • 変換に失敗すると例外が飛ぶ • floatは使えない(doubleを使うこと) • 値の中身がnullだった時の扱い(null許容型を使う)
  28. 28. Jsonで値が送られてこなかった時の判別方法 • Null許容型 構造体(値型)にnullが入ることを許容する 「Jsonの中身にNoの要素が無かった」 ・非Null許容型int → 0で初期化(0が送られてきたのか判断不能) ・Null許容型int → Nullかどうかで値が送られてないと判断できる
  29. 29. 実装について話すこと一覧 • MMDモデルのインポート • コメビュとの通信 • 口パク • コメントの感情解析 • 設定ファイルの読み書き • デスクトップマスコットモード
  30. 30. 口パク • MMD4MecanimSpeechHelperで簡単にできる – MMDモデルはこのスクリプトで口パクできる – ただしこのSpeechHelperはMMDモデルにのみ使える – ユニティちゃんは別にスクリプトを自作して対応 • クエリちゃんは対応できんかった……
  31. 31. 口パク機構の管理 • インターフェースを用いて呼び出し元の処理を統一 SpeechTextController 読み上げるコメントの 管理を行う MMD4MecanimSpeechHelper MMD向け口パクComponent インターフェース ISpeechController UnitychanLipController ユニティちゃん専用 口パクComponent
  32. 32. 口パク用のコメントひらがな変換 • 口パクさせる為にコメントのひらがな化を行う – NMeCabを使ってひらがな化 – KakasiはGPLライセンスだったので避けた
  33. 33. 実装について話すこと一覧 • MMDモデルのインポート • コメビュとの通信 • 口パク • コメントの感情解析 • 設定ファイルの読み書き • デスクトップマスコットモード
  34. 34. コメント感情解析 • コメントの内容に応じてリアクションが変化する
  35. 35. リアクションするキーワードの例 • 挨拶 (「わこつ」、「初見」など) • 挙手 (ノ) • 笑い (wを含むコメント、「吹いた」「ワロス」など) • 絶叫 (あああああ! など) • ツッコミ (「おまえが言うな」「やめてー><」など) • 命令 (~しろ! など) • 疑問 (語尾に「?」が付いているなど) • 感動 (「泣けてきた」「切ない」など) • 賛美 (「ありがとう」「才能の無駄遣い」など) • 返答 (「おこ?」「ですよねー」など) • 興奮 (「おおぉぉぉぉぉ!」など) • 賞賛 (「すごい!」など) ※ただしそこまで精度はよくない
  36. 36. コメント感情解析の仕組み • ニコニコ動画コメント@ばっちりサーチ.net – こちらのnode.js用モジュールをC#に移植 • https://github.com/TORISOUP/CommentAnalyzerCSharp – 中身は鬼のような正規表現 – 正直どのコメントが何に判定されるかわからない
  37. 37. 実装について話すこと一覧 • MMDモデルのインポート • コメビュとの通信 • 口パク • コメントの感情解析 • 設定ファイルの読み書き • デスクトップマスコットモード
  38. 38. 設定パネル
  39. 39. 設定ファイル • パラメータをJsonでテキストに保存(.NETの機能) – PlayerPrefsはレジストリに保存されるので使いたくない – バイナリにシリアライズして保存すると後から変更しにくい – 読み込み時にバリデーションを入れる必要がある(平文保存のため)
  40. 40. 実装について話すこと一覧 • MMDモデルのインポート • コメビュとの通信 • 口パク • コメントの感情解析 • 設定ファイルの読み書き • デスクトップマスコットモード
  41. 41. デスクトップマスコットモード • こちらのAssetを使わせて頂きました • オススメです
  42. 42. みくみくまうすのまとめ • ニコ生配信支援ツール • フリーソフトとして配布中 • 生放送を盛り上げるのに使ってね!!! • プログラミング生放送でも使おう!! • 使うときは「みくみくまうす」のタグを付けてくれるとエゴサしやすくて助かります
  43. 43. ステッカー • 調子に乗ってステッカーも作りました – 数に限りがあるので欲しい人は1人1枚お持ち下さい – 割りと安い(100枚刷って4000円くらい)
  44. 44. くぎり • みくみくまうすについての質問とかあれば 続いて「コーディングする上で意識すべきこと」→
  45. 45. コーディングする上で 意識すべきこと
  46. 46. おしながき • 名前 • 機能の分離 • SOLID原則 • MVCパターン
  47. 47. おしながき • 名前 • 機能の分離 • SOLID原則 • MVCパターン
  48. 48. 名前 わかりやすい名前をつけろ!!!!!
  49. 49. 例)メソッド名 • メソッド名から処理内容が判断できるべき – メソッド名が長くなるのは構わない(限度はあるが) – 例)GetNearestEnemyFromPlayer • 誤解される名前をつけるな – Get*()なのに副作用がある • 副作用=状態を変化させてしまう動作 • Get()は何度実行しても結果が同じになるべき(べき等性) – GetSize()なのに計算量がO(n) • GetSize()はO(1)であるべき • O(n)なら「Count()」にしたほうがまだわかる
  50. 50. おすすめの本 リーダブルコード ―より良いコードを書くためのシンプ ルで実践的なテクニック
  51. 51. おしながき • 名前 • 機能の分離 • SOLID原則 • MVCパターン
  52. 52. 機能の分離 • Unityに依存しないコードを書こう – なんでもかんでもMonoBehaviourを継承させない – Unityからゲームロジックを分離する – Unity以外でもそのまま使えると良い – 単体テスト書きやすくなる
  53. 53. おしながき • 名前 • 機能の分離 • SOLID原則 • MVCパターン
  54. 54. SOLID原則 • オブジェクト指向開発を行う上での5つの原則 – 単一責任の原則(SRP) – オープン・クローズドの原則(OCP) – リスコフの置換原則(LSP) – 依存関係逆転の原則(DIP) – インターフェース分離の原則(ISP) • あくまで原則である – 必ず守る必要はない – 守ったほうが良い場合の方が多い – Unity開発も例外ではなく守った方が良い
  55. 55. SOLID原則 • 単一責任の原則(SRP) • オープン・クローズドの原則(OCP) • リスコフの置換原則(LSP) • 依存関係逆転の原則(DIP) • インターフェース分離の原則(ISP)
  56. 56. 単一責任の原則 「クラスを変更する理由は1つ以上存在してはならない」 「一つのクラスに複数の責務を持たせるな」 • 馬鹿でかいクラスは管理しにくい • 1つのクラスにあれこれ機能を詰め込むな • クラス名以上の責務は負わせるな
  57. 57. 悪い例 • PlayerController(プレイヤキャラクタの制御) – Inputの受け付け – キャラクタの移動処理 – キャラクタの攻撃処理 – キャラクタの体力の管理 – アニメーション再生の管理 – エフェクト再生の管理 – 効果音再生の管理 – カメラの制御 処理多すぎィ!!!!! だが初心者はやりがち
  58. 58. 適切に分離しよう • PlayerInputManager – Inputの受け付け • PlayerController – キャラクタの移動処理 – キャラクタの攻撃処理 – キャラクタの体力の管理 • PlayerView – アニメーション再生の管理 • CameraController – カメラの制御 • EffectManager – エフェクト再生の管理 • SoundManager – 効果音再生の管理
  59. 59. SOLID原則 • 単一責任の原則(SRP) • オープン・クローズドの原則(OCP) • リスコフの置換原則(LSP) • 依存関係逆転の原則(DIP) • インターフェース分離の原則(ISP)
  60. 60. オープン・クローズドの原則 「モジュールの振る舞いの拡張に対してオープンである」 「モジュールの振る舞いの修正に対してクローズドである」 • 機能追加は簡単にできる • 機能追加によって他のコードを書き換える必要はない • 要するに「ポリモーフィズム」となるようにしろ
  61. 61. オープン?クローズド? • あとから簡単に機能追加できるようにしろ – インターフェースを実装すれば機能追加できる(オープン) – 実クラスが増えても元のコードに変更はなし(クローズド) SpeechTextController 読み上げるコメントの 管理を行う MMD4MecanimSpeechHelper MMD向け口パクComponent インターフェース ISpeechController
  62. 62. オープン?クローズド? • あとから簡単に機能追加できるようにしろ – インターフェースを実装すれば機能追加できる(オープン) – 実クラスが増えても元のコードに変更はなし(クローズド) SpeechTextController 読み上げるコメントの 管理を行う MMD4MecanimSpeechHelper MMD向け口パクComponent インターフェース ISpeechController UnitychanLipController ユニティちゃん専用 口パクComponent
  63. 63. オープン?クローズド? • あとから簡単に機能追加できるようにしろ – インターフェースを実装すれば機能追加できる(オープン) – 実クラスが増えても元のコードに変更はなし(クローズド) SpeechTextController 読み上げるコメントの 管理を行う MMD4MecanimSpeechHelper MMD向け口パクComponent インターフェース ISpeechController UnitychanLipController ユニティちゃん専用 口パクComponent ユニティちゃんを 簡単に追加できる (オープン)
  64. 64. オープン?クローズド? • あとから簡単に機能追加できるようにしろ – インターフェースを実装すれば機能追加できる(オープン) – 実クラスが増えても元のコードに変更はなし(クローズド) SpeechTextController 読み上げるコメントの 管理を行う MMD4MecanimSpeechHelper MMD向け口パクComponent インターフェース ISpeechController UnitychanLipController ユニティちゃん専用 口パクComponent 呼び出し側に修正不要 (クローズド)
  65. 65. SOLID原則 • 単一責任の原則(SRP) • オープン・クローズドの原則(OCP) • リスコフの置換原則(LSP) • 依存関係逆転の原則(DIP) • インターフェース分離の原則(ISP)
  66. 66. リスコフの置換原則 「派生クラスは基底クラスで定めたルールを破ってはいけない」 • 基底クラスで定義された部分は派生クラスと置換可能である • 派生クラスは基底クラスと全く同じ仕事ができなくてはいけない
  67. 67. リスコフの置換原則に違反した例 例)移動メソッドMove(Vector3 direction) 基底クラス:引数に方向ベクトルを与える(長さ1のベクトル) 移動速度は内部の状態に基づいて決まる 派生クラス:引数に速度ベクトルを与える 移動速度は与えられたベクトルで従う 基底クラスと派生クラスで振る舞いが違う
  68. 68. SOLID原則 • 単一責任の原則(SRP) • オープン・クローズドの原則(OCP) • リスコフの置換原則(LSP) • 依存関係逆転の原則(DIP) • インターフェース分離の原則(ISP)
  69. 69. 依存関係逆転の原則 「上位モジュールは下位モジュールに依存してはならない。 どちらのモジュールもインターフェースに依存すべきである」 • インターフェースを使え • 実クラスへの参照を無くしてインターフェースに依存させろ
  70. 70. 関係の逆転? • 上位から下位に依存した関係(ダメな例) – 上位モジュールが下位モジュールに依存 – 実クラスそのものを参照してしまっている – 実クラスの変更の影響を上位モジュールが受けやすい InputManager 入力を管理する PlayerReimu プレイヤ(霊夢) PlayerMarisa プレイヤ(魔理沙)
  71. 71. 関係を逆転させる • 下位から上位に依存させる – 上位のレイヤにインターフェースを作成 – 上位モジュールはインターフェースを参照する – オープン・クローズドの原則も同時に満たされる InputManager 入力を管理する PlayerReimu プレイヤ(霊夢) PlayerMarisa プレイヤ(魔理沙) PlayerYoumu プレイヤ(妖夢) インターフェース IPlayerInput
  72. 72. SOLID原則 • 単一責任の原則(SRP) • オープン・クローズドの原則(OCP) • リスコフの置換原則(LSP) • 依存関係逆転の原則(DIP) • インターフェース分離の原則(ISP)
  73. 73. インターフェース分離の原則 「クライアントにクライアントが本来依存しないメソッドへの依存性を強制して はならない」 • 不必要なメソッドまでクライアントに提供しない • インターフェースを適切に分割して提供しろ
  74. 74. インターフェース分離の原則に違反した例 InputManager 入力を管理する PlayerReimu プレイヤ(霊夢) PlayerMarisa プレイヤ(魔理沙) PlayerYoumu プレイヤ(妖夢) インターフェース IPlayerInput Move() Attack() Jump() Move() Attack() Jump() Move() Attack() Jump() Move() Attack() Jump() • IPlayerInputインターフェースを各クラスが実装 – PlayerMarisaに「盗む Steal()」を増やしたい
  75. 75. • IPlayerInputインターフェースを各クラスが実装 – PlayerMarisaに「盗む Steal()」を増やしたい – IPlayerInputに追加してしまった インターフェース分離の原則に違反した例 InputManager 入力を管理する PlayerReimu プレイヤ(霊夢) PlayerMarisa プレイヤ(魔理沙) PlayerYoumu プレイヤ(妖夢) インターフェース IPlayerInput Move() Attack() Jump() Steal() Move() Attack() Jump() Move() Attack() Jump() Steal() Move() Attack() Jump()
  76. 76. • 関係の無い他のクラスまで影響を受けてしまう – 使わないのに実装しないといけない インターフェース分離の原則に違反した例 InputManager 入力を管理する PlayerReimu プレイヤ(霊夢) PlayerMarisa プレイヤ(魔理沙) PlayerYoumu プレイヤ(妖夢) インターフェース IPlayerInput Move() Attack() Jump() Steal() Move() Attack() Jump() Steal() Move() Attack() Jump() Steal() Move() Attack() Jump() Steal()
  77. 77. インターフェースを分離する InputManager 入力を管理する PlayerReimu プレイヤ(霊夢) PlayerMarisa プレイヤ(魔理沙) PlayerYoumu プレイヤ(妖夢) インターフェース IPlayerInput • IStealインターフェースを新しく作る – 必要としているクラスだけがそのインターフェースを実装する インターフェース ISteal
  78. 78. SOLID原則のまとめ • 機能は分割して作れ • インターフェースを使え • モジュールの依存関係を疎結合にしろ
  79. 79. UnityとSOLID原則 • Componentは機能単位で分割して作るべき – クラス名以上の責務は負わせるべきではない – コードの記述量は増えるが、わかりやすくなる • Componentはインターフェースを介してやりとりするべき – Componentが複雑に関係しあう時は特に意識すべき – Componentの差し替えが楽になる • SOLID原則をいちいち守ってると逆に非効率なこともある – 小さい規模なら無視して作ったほうがぶっちゃけ早い – 大規模開発になった時はSOLID原則は重要になる
  80. 80. おしながき • 名前 • 機能の分離 • SOLID原則 • MVCパターン
  81. 81. MVCパターン • Model View Controller – GUIを持つアプリケーションで用いられるデザインパターン – 機能を以下の3つに分離する Controller (ユーザからの入力) Model (実データやロジック) View (描画処理)
  82. 82. UnityとMVC • プレイヤの制御がMVCパターンと相性がいい – プレイヤ制御を以下のMVCに分離してしまう Controller (ユーザからの入力) Model (実データやロジック) View (描画処理) Input周りの処理 • キーボード入力 • マウス入力 メイン処理 • 移動 • ダメージ判定 • 攻撃 出力系の処理 • アニメーションの再生 • エフェクトの再生 • 効果音の再生
  83. 83. プレイヤ制御とMVC • MVC分割のメリット – Componentの責務が明確になる(単一責任の原則) – 入力機器の差異をControllerの差し替えで対応できる – ネットワーク同期も簡単になる
  84. 84. MVC分割でSOLID原則を満たすなら • インターフェースを切ってそこに依存させる Controller (ユーザからの入力) Model (実データやロジック) View (描画処理) インターフェース IPlayerController インターフェース IPlayerStatus Move() Attack() Jump() OnGround IsRunning IsDead
  85. 85. 実例 • ユニティちゃんゴーストマンション – MVCが分離されているのでそれぞれ個別に開発できる – ゲームジャムで役に立った ←Controller ←Model ←View ←ネットワーク同期用 スクリプト
  86. 86. 「意識するべきこと」まとめ • わかりやすさ最優先でコードを書くべき • Unityへの依存は断ち切ろう • SOLID原則を意識した設計にしよう • インターフェースを活用しよう • MVCパターンは割りと使えるかもしれない
  87. 87. Unityで活用できる C#の機能
  88. 88. おしながき • 拡張メソッド • LINQ • UniRx(※ C#の機能では無い)
  89. 89. おしながき • 拡張メソッド • LINQ • UniRx
  90. 90. 拡張メソッド • クラスに外からインスタンスメソッドを追加する – staticメソッドを「あたかもそのクラスが持っているメソッド」を呼び出す かの様に記述できるようになる機能 – 実際はただのstaticメソッドの呼び出し static class ExtensionMethods { public static 返り値の型 メソッド名(this 追加対象の型,引数1…) { 処理… } }
  91. 91. 拡張メソッドを使うと便利な例 • Vector3のy成分を無視した水平面での方向を計算 – 進行方向にプレイヤを向かせるときに使うことが多い • y成分を含ませると身体が傾く 進行方向 鉛直方向を無視した 水平面での方向ベクトル
  92. 92. 拡張メソッド)水平面での方向ベクトルを取得 • Vector3型への拡張メソッドとして定義する – 拡張メソッドを収めるstatic classを定義 – その中にstaticメソッドを追加 – 第一引数のVector3にthisを付ける
  93. 93. 拡張メソッド)実際に使ってみる • Vector3に最初から生えているメソッドとして振る舞う – Vector3を継承することなく、Vector3をカスタマイズできた
  94. 94. 拡張メソッドまとめ • 標準で足りない機能をガンガン追加していこう – Vector3とかMomoBehaviourとかに追加すると便利になる – 自分なりにカスタマイズしてしまおう • 拡張メソッドの定義はわかりやすくしておく – どこに定義したかわからなくなる事態は避ける – 作った拡張メソッド群は資産として再利用可能
  95. 95. 拡張メソッド • 自分が追加した拡張メソッド群(一部) – Vector3 • ベクトルの要素ごとの積 • 2点間の距離の計算 • 水平面での距離の計算 • 水平面での方向ベクトルの計算 • x,y,zそれぞれの上書き – Transform • Photon ViewIDの取得 • Photon IsMineの取得 • キャラクタの中心座標を補正して取得 • CharacterControllerから速度を取得 – Animator • 値オブジェクトからAnimatorのパラメータに反映 • Animatorパラメータ書き換えと同時に差分を保存(ネットワーク同期用)
  96. 96. おしながき • 拡張メソッド • LINQ • UniRx
  97. 97. LINQ • 統合言語クエリ(LINQ) – 様々なデータソースに対する操作を統合的に記述するもの – 特にLINQ to Objects(コレクション)がよく使われる – せっかくのC#なのになぜLINQ使わないのか!?!?!?!?
  98. 98. LINQ to Objectで何ができるか? • コレクションに対する操作を簡単に記述できる – コレクション(配列、リスト、ディクショナリとか) – 複雑な処理をわかりやすく記述できる LINQメソッドの例 処理の内容 Where 条件を満たす要素のみにフィルタリング Select 要素を別の形式に変換 Any 条件を満たす要素が1つもであるか All 全ての要素が条件を満たすか First 最初に見つかった条件を満たす要素を返す Count 条件を満たす要素の数を数える
  99. 99. 例)LINQを使わずに書く • TagがEnemy • 指定座標から半径10m未満 • Transformのリスト をGameObject配列から取得するメソッドをLINQを使わずに定義
  100. 100. 例)LINQを使わずに書く • TagがEnemy • 指定座標から半径10m未満 • Transformのリスト をGameObject配列から取得するメソッドをLINQを使わずに定義 本当に正しいかの確認が大変 これを毎回読み解くのか?
  101. 101. 例)LINQを使った場合
  102. 102. 例)LINQを使った場合 1. gameObjectArrayに対して 2. TagがEnemyのものだけ 3. 指定座標から10m未満のものだけ 4. Transformに変換して 5. List形式にまとめて返す • 順番に上から読むだけで処理の内容が理解できる – 単純に「やりたい事だけ」を記述すれば良い – ループやif文が無く、バグが入り込む余地がない
  103. 103. LINQまとめ • C#を使ってるなら是非使うべき機能 – ちゃんと使えばコード中からfor文を無くせる – LINQを使わずして何がC#か • 普通にループを書くより処理速度は落ちる – LINQによって実行速度が問題になるようなことはほぼ無い – コードの読みやすさ>>>>>速度 – 下手に凝ったループを書いてバグを生むのとどっちが良いか? • iOSでのLINQは不具合がある – 詳しくはショートセッションで
  104. 104. おしながき • 拡張メソッド • LINQ • UniRx
  105. 105. Rx(UniRx) • ReactiveExtensions(Rx) – LINQの概念を「非同期」「イベント」に拡張したもの – 時間を跨いだ処理を簡単に記述できる – UniRxはRxのUnity移植版(neueccさん作) • ちゃんと解説すると1時間はかかる – 今回は説明を放棄
  106. 106. UnityでRxを使う
  107. 107. Rxの概念 • イベントをストリームとして扱う – イベントって時間軸に並んだコレクションじゃね? – コレクションならLINQで扱えるんじゃね? t
  108. 108. Rxの使い道 • イベントの代わりに使う(ストリームを作る) – Subject<T>を使えばストリームが作れる – 既存のEventの上位互換(むしろEventはレガシー) • ストリームの終了、エラーを通知できる • イベントの複雑な処理 – 特定のイベントのみ処理する – 前のイベントの値と組み合わせる
  109. 109. UniRxの例 • マウスのダブルクリックの検知 – 普通に書くと煩雑な処理がたった数行で終わった – 状態の一時保管用のフィールドの定義不要
  110. 110. Rxのまとめ • 時間やフレームを跨いだ処理を簡単に記述できる • 使いこなすとUpdate()の中身が短くなる • 学習コストは高め とにかく便利なので使ってみるべし
  111. 111. 「C#の機能」まとめ • C#には便利な機能がたくさんある – C#っぽくない書き方のコード多くて悲しい – 使いこなすと強力な武器になるので使うべし • Rx楽しい – 本当に便利なのでもっと流行るべき
  112. 112. 最後にまとめ • みくみくまうす使ってね – みんな生放送やろうぜ – せっかく作ったんだから使って欲しい • Unityの開発力は最終的にコーディング能力に行き着く – 複雑なことやるには結局スクリプトを書かないといけない – プログラミングスキルは高めるべき • 動き続けるプログラムが正義 – 「動けばいいや」ではダメ – Unityは特に適当に書いても動くので注意が必要 – 保守性やメンテナンス性も考えた開発をやろう
  113. 113. ありがとうございました

×