Unity
バージョン依存
- Unity2020.3.0f1(LTS)
- ダークモード
- Unity2019.4.6f1(LTS)
- ヒエラルキーでの非表示機能
- Unity2018.4.22f1(LTS)
- StandardAssets
パッケージ(マネージャー)依存
CinemachinePost ProcessingTextMeshPro
デフォルト設定
- CameraBackgroundColor:#314D79
- MaterialInternalErrorColor:#FF00FF
逆引きTIPS
太字箇所は初期段階で設定しとくべし(副作用はある)
- 開発時シーンの再生が遅い
=>(Configurable Enter Play Mode)を使う
=>編集.プロジェクト設定.再生モード開始時設定:true,ドメインを再ロード:false,シーンを再ロード:false- ※
Reload Domain
=>staticなフィールド/イベントがリセットされないので手動で初期化が必要 - ※
Reload Scene
=>シーンをリロードせず変更されたコンテンツだけリセットされる
=>Awakeが呼ばれなくなる, 初期値の暗黙的なNULLが保証されなくなる
(インスタンスが作成済みになるためListなどの初期値は明示的なNULLを設定する) - https://madnesslabo.net/utage/?page_id=10983
- ※
- デフォルトエディタを変更したい=>Edit.Preference.ExternalTools.ExternalScriptEditor:Browse.SublimeText
- スマホ対応
=> ProjectSetting.Player.WebGL settings- PublishSettings.DecompressionFallbackをチェック
- ?OtherSettings.AutoGraphicsAPIのアンチェック
- GraphicsAPIのWebGL2(OpenGLES3)を削除
- GraphicsAPIにWebGL1(OpenGLES2)を追加
- 画面サイズ変えたい=>GameViewのFreeAspectを調整
- インスペクタ上のパラメータがEditorと一致しない
=>Inspector.ケバブメニュー.Normal=>Debugを選択
=>だめならDocumentかSourceを読め - Spriteがドラックアンドドロップで配置できない
=>SelectAsset.TextureType:Sprite(2D and UI) - Spriteをバラバラにしたい
=>Usage:SelectAsset->SpriteMode:Multiple
https://unity-senpai.hatenablog.com/entry/2019/08/10/235344 - MP4を表示したい
=>Video Playerコンポーネントを追加し、Video Clipに指定 - シーンビューの移動量多い/少ない =>シーンカメラ.
有効視野FOVを調整
Issue/Error
- (Overlay)Canvasの
AdditionalShaderChannel:Mixedに警告が出る
=>Shader channels Normal and Tangent are most often used with lighting, which an Overlay an Overlay canvas does not support. Its likely these channels are not needed.
=>TextMeshProが悪さをしてるっぽい。静的なCanvasならNothingにすれば消せるけど動的なCanvasの場合、生成時に設定しても反映されないし警告レベルなので無視が良さそう
(※全オブジェクト生成後、キー入力をトリガーにして設定したら反映された)
Cinemachineでカメラをブレさせる
- パッケージマネージャーから
Cinemachineを検索し、インストール
PostEffectを使う(Post Processing Stack版)
- パッケージマネージャーから
Post Processingを検索し、インストール
3D移動させたい
void Update(){
if(Input.GetKeyDown(KeyCode.Space)){
this.transform.localPosition=Vector3.zero;
this.transform.rotation=Quaternion.Euler(Vector3.zero);
this.transform.localScale=Vector3.one;
}
if(Input.GetKey(KeyCode.W)) this.transform.Translate (0.0f,0.0f,0.03f,Space.Self);
if(Input.GetKey(KeyCode.S)) this.transform.Translate (0.0f,0.0f,-0.03f,Space.Self);
if(Input.GetKey(KeyCode.A)) this.transform.Translate (-0.03f,0.0f,0.0f,Space.Self);
if(Input.GetKey(KeyCode.D)) this.transform.Translate (0.03f,0.0f,0.0f,Space.Self);
if(Input.GetKey(KeyCode.UpArrow)) this.transform.Translate (0.0f,0.03f,0.0f,Space.World);
if(Input.GetKey(KeyCode.DownArrow)) this.transform.Translate (0.0f,-0.03f,0.0f,Space.World);
if(Input.GetKey(KeyCode.LeftArrow)) this.transform.Rotate(0.0f,-0.25f,0.0f,Space.World);
if(Input.GetKey(KeyCode.RightArrow)) this.transform.Rotate(0.0f,0.25f,0.0f,Space.World);
if(Input.GetKey(KeyCode.PageUp)) this.transform.Rotate(-0.25f,0f,0.0f,Space.Self);
if(Input.GetKey(KeyCode.PageDown)) this.transform.Rotate(0.25f,0f,0.0f,Space.Self);
}
2D移動させたい
void Update(){
//if(Input.GetKeyDown(KeyCode.Space)){ Debug.Log("SPACE"); }
if(Input.GetKey(KeyCode.W)||Input.GetKey(KeyCode.UpArrow)) this.transform.Translate(0.0f,0.03f,0.0f);
if(Input.GetKey(KeyCode.S)||Input.GetKey(KeyCode.DownArrow)) this.transform.Translate(0.0f,-0.03f,0.0f);
if(Input.GetKey(KeyCode.A)||Input.GetKey(KeyCode.LeftArrow)) this.transform.Translate(-0.03f,0.0f,0.0f);
if(Input.GetKey(KeyCode.D)||Input.GetKey(KeyCode.RightArrow)) this.transform.Translate(0.03f,0.0f,0.0f);
}
デバッグ用のCubeオブジェクトがほしい
using UnityEngine;
[ExecuteInEditMode]
public class LineCube : MonoBehaviour{
//[SerializeField]
private Vector3 scale = new Vector3(1f, 1f, 1f);
// [SerializeField] private Material material;
void Start(){
this.transform.position = new Vector3 (0.0f,2.0f,0.0f);
}
void Update(){
this.transform.Rotate (0.1f, 0.1f, 0.1f);
}
private void OnRenderObject(){
// material.SetPass(0);
Vector3 halfScale = scale * 0.5f;
GL.PushMatrix();
GL.MultMatrix(transform.localToWorldMatrix);
drawRectXY(halfScale, -halfScale.z);
drawRectXY(halfScale, halfScale.z);
drawLineZ(halfScale, -halfScale.x, -halfScale.y);
drawLineZ(halfScale, halfScale.x, -halfScale.y);
drawLineZ(halfScale, halfScale.x, halfScale.y);
drawLineZ(halfScale, -halfScale.x, halfScale.y);
GL.PopMatrix();
}
private void drawRectXY(Vector3 halfScale, float z){
GL.Begin(GL.LINE_STRIP);
GL.Vertex(new Vector3(-halfScale.x, -halfScale.y, z));
GL.Vertex(new Vector3(halfScale.x, -halfScale.y, z));
GL.Vertex(new Vector3(halfScale.x, halfScale.y, z));
GL.Vertex(new Vector3(-halfScale.x, halfScale.y, z));
GL.Vertex(new Vector3(-halfScale.x, -halfScale.y, z));
GL.End();
}
private void drawLineZ(Vector3 halfScale, float x, float y){
GL.Begin(GL.LINES);
GL.Vertex(new Vector3(x, y, -halfScale.z));
GL.Vertex(new Vector3(x, y, halfScale.z));
GL.End();
}
}
デバッグ用のPlaneオブジェクトがほしい
using UnityEngine;
[ExecuteInEditMode]
public class LinePlane : MonoBehaviour{
//[SerializeField]
private Vector2 scale = new Vector2(10f, 10f);
//[SerializeField]
private Vector2Int division = new Vector2Int(10, 10);
//[SerializeField] private Material material;
void start(){
//material = new Material (Shader.Find ("Unlit/TransparentShader"));
}
private void OnRenderObject(){
// material.SetPass(0);
Vector2 stepSize = scale / division;
Vector2 halfScale = scale * 0.5f;
GL.PushMatrix();
GL.MultMatrix(transform.localToWorldMatrix);
for (int x = 0; x <= division.x; x++){
GL.Begin(GL.LINES);
for (int z = 0; z < division.y; z++){
GL.Vertex(new Vector3(x * stepSize.x - halfScale.x, 0f, z * stepSize.y - halfScale.y));
GL.Vertex(new Vector3(x * stepSize.x - halfScale.x, 0f, (z + 1) * stepSize.y - halfScale.y));
}
GL.End();
}
for (int z = 0; z <= division.y; z++){
GL.Begin(GL.LINES);
for (int x = 0; x < division.x; x++){
GL.Vertex(new Vector3(x * stepSize.x - halfScale.x, 0f, z * stepSize.y - halfScale.y));
GL.Vertex(new Vector3((x + 1) * stepSize.x - halfScale.x, 0f, z * stepSize.y - halfScale.y));
}
GL.End();
}
GL.PopMatrix();
}
}
キーコードを知りたい
if (Input.anyKeyDown) {
foreach(KeyCode code in System.Enum.GetValues(typeof(KeyCode))){
if (Input.GetKeyDown(code)){
Debug.Log("Code:"+(int)code+", Key:"+code.ToString());
}
}
}
StandardAssets(for Unity2018.4)を使う
/SampleScenes/*
/Standard Assets/
SQLite3を使う(NoCheck)
FadeManager(FadeCamera)
Spineを使う(for 2020.3)
/Spine/*
/Spine Examples/*
(/Assets/Resources/Spine/*)
Exportファイル
skelton.atlas.txt
skelton.json
skelton.png
SpineExportForUnity2020.3
- Export.ExportJSON
- Extension:
.json - Format:
JSON - Pretty print:
true - Output:
Nonessential data,Animation clean up,Warrnings - Texture Atlas.Pack:
true
- Create atlas.Options.アトラス拡張子設定:
.atlas=>.atlas.txtに変更
手動でUnityのSceneへ配置してアニメーション
- SpineからExportしたファイルをAssets配下へ移動
skeleton_SkeletonData.assetをヒエラルキー上にドラッグ&ドロップしSkeltonAnimation- インスペクタ.SkeltonAnimation.Animation Name:
<None>=>アニメーション名 - シーン再生
ScriptでSpineAnimation
////Spine(path="Assets/Resources/Spine/*.asset")
public static GameObject UiSpine(GameObject canvas,string path,string animation=null){
GameObject obj=_.Obj(canvas,"_spine");
obj.AddComponent<SkeletonGraphic>();
SkeletonGraphic skeletonGraphic=obj.GetComponent<SkeletonGraphic>();
skeletonGraphic.skeletonDataAsset=AssetDatabase.LoadAssetAtPath(path,typeof(SkeletonDataAsset)) as SkeletonDataAsset;
skeletonGraphic.Initialize(true);
if(animation!=null){
skeletonGraphic.AnimationState.SetAnimation(0, animation, true);
}
return obj;
}
public static GameObject Spine(GameObject parent,string path,string animation=null){
GameObject obj=_.Obj(parent,"_spine");
obj.AddComponent<SkeletonAnimation>();
SkeletonAnimation skeletonAnimation=obj.GetComponent<SkeletonAnimation>();
skeletonAnimation.skeletonDataAsset=AssetDatabase.LoadAssetAtPath(path,typeof(SkeletonDataAsset)) as SkeletonDataAsset;
skeletonAnimation.ClearState();
skeletonAnimation.Initialize(true);
if(animation!=null){
skeletonAnimation.loop=true;
skeletonAnimation.AnimationName=animation;
}
return obj;
}
SubstancePainter
- SubstancePainter
- Asset@Substance in Unity ※Substance.Substance Sourceを利用することで所持マテリアルが
/Materials/*.sbsarとしてダウンロードできる
Unity-Chan素材を使う
※UCLロゴ、もしくはライセンス表記が必要(詳細はガイドラインで確認)
UnityでNuGetパッケージマネージャーを使う(NoCheck)
uGUIでGifを表示する(NoCheck)
(Usage:Canvas.RawImage=>Attach&Setting:UniGifImage,UniGifImageAspectController)
- レポジトリの
Assets/UniGifをプロジェクト内にコピー - Gifアニメを再生させたいGameObjectに
Uni Gif ImageとRawImage,Uni Gif Image Aspectのコンポーネントを追加 Uni Gif ImageのRaw ImageとImg Aspect CrlにRawImage,Uni Gif Image Aspectを設定 (シーン再生からGif再生させたい場合は「Load On Start」にチェックをいれる)Load On Start Urlに再生させたいGifアニメのファイル名(Ex:xxxx.gif)を指定する/StreamingAssetsディレクトリにgif画像を配置
簡易Skyboxを作る
https://qiita.com/aike@github/items/cf4a8289fef65c9652a7
- 1024x1024のPNGを作ってAssetsフォルダに入れる
- 画像プロパティをTexture Shape:Cube->Apply
- Assets.Create.Materialで新規マテリアル作成。
- マテリアルプロパティをShader:Skybox/Cubemap、Cubemapに作成した画像を指定
- Window.Rendering.Lighting Settingsを開く
- Environment.Skybox Materialに作成したマテリアルを指定
認証にJWTを使う
static protected string host="HOSTNAME";
protected string jwt_token;
static protected string jwt_login="http://"+host+"/jwt/";
static protected string jwt_test="http://"+host+"/jwt/test";
void Start () {
StartCoroutine(LoginJWT());
}
IEnumerator LoginJWT() {
var uwr = new UnityWebRequest(jwt_login, "POST");
byte[] bodyRaw = Encoding.UTF8.GetBytes("{\"user\":\"guest\",\"password\":\"password\"}");
uwr.uploadHandler = (UploadHandler) new UploadHandlerRaw(bodyRaw);
uwr.downloadHandler = (DownloadHandler) new DownloadHandlerBuffer();
uwr.SetRequestHeader("Content-Type", "application/json");
yield return uwr.SendWebRequest();
JWT jwt = JsonUtility.FromJson<JWT> (uwr.downloadHandler.text);
//Debug.Log("Token:"+jwt.token);
jwt_token=jwt.token;
}
//StartCoroutine(TestJWT());
IEnumerator TestJWT(){
UnityWebRequest uwr = UnityWebRequest.Get(jwt_test);
uwr.SetRequestHeader("Authorization", "Bearer " + jwt_token);
yield return uwr.SendWebRequest();
if (uwr.isNetworkError){
Debug.Log(uwr.error);
}else{
Debug.Log("Received:"+uwr.downloadHandler.text);
}
}
[Serializable]
public class JWT{
public string token;
}
Jsonを扱う
/Script/Json/demo.json
/Script/Json/JsonDemo.cs
/Script/Json/JsonReaderDemo.cs
////JsonReaderDemo.cs
using System;
using System.IO;
using System.Text;
using System.Collections;
using UnityEngine;
public class JsonReaderDemo : MonoBehaviour{
void Start(){
////Resources/Json/demo.json
//inputString = Resources.Load<TextAsset>("Json/demo").ToString();
string inputString = "";
FileInfo fi = new FileInfo(Application.dataPath + "/Scripts/Json/demo.json");
using (StreamReader sr = new StreamReader(fi.OpenRead(), Encoding.UTF8)){
inputString += sr.ReadToEnd();
}
Debug.Log(inputString);
JsonDemo inputJson = JsonUtility.FromJson<JsonDemo>(inputString);
Debug.Log("[0].key:"+inputJson.keyval[0].key);
Debug.Log("[0].val:"+inputJson.keyval[0].val);
}
}
////JsonDemo.cs
using System;
using UnityEngine;
[Serializable]
public class JsonDemo{
public KeyValDemo[] keyval;
public VarDemo[] var;
public string[] list;
public string comment;
}
[Serializable]
public class KeyValDemo{
public string key;
public string val;
}
[Serializable]
public class VarDemo{
public string name;
public string type;
public string value;
}
{
"comment": "COMMENT#demo.json",
"list": [
"item"
],
"keyval": [
{ "key":"key1","val":"val1" },
{ "key":"key2","val":"val2" }
],
"var": [
{"name": "sample", "type": "text", "value": "value"}
]
}
ネットワーク通信にWebSocketを使う
WebSocket(websocket-sharp)
Unable to open Assets/Plugins/websocket-sharp.dll: Check external application preferences.
(※DLLに関連付けがされてない場合の警告?=>再起動で解決)
https://github.com/sta/websocket-sharp
/Plugins/websocket-sharp.dll
WebSocketforWebGL(unity-websocket-webgl)
プロジェクトのターゲットプラットフォームに基づいて、ブラウザまたはネイティブ実装を自動的にコンパイルします。
https://github.com/jirihybek/unity-websocket-webgl
(/Scripts/WebSocketDemo.cs)
/Plugins/WebSocket.cs
/Plugins/WebSocket.jslib
////WebSocketDemo.cs
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using UnityEngine;
// Use plugin namespace
// https://github.com/jirihybek/unity-websocket-webgl
using HybridWebSocket;
public class WebSocketDemo : MonoBehaviour {
protected string websocket_server="ws://echo.websocket.org:80/";
protected WebSocket ws;
void Start () {
// Create WebSocket instance
ws = WebSocketFactory.CreateInstance(websocket_server);
// Add OnOpen event listener
ws.OnOpen += () =>{
Debug.Log("WS Connected Status:"+ws.GetState().ToString());
WsSubmit();
};
// Add OnMessage event listener
ws.OnMessage += (byte[] msg) =>{
Debug.Log("WS received message: " + Encoding.UTF8.GetString(msg));
//ws.Close();
};
// Add OnError event listener
ws.OnError += (string errMsg) =>{
Debug.Log("WS error: " + errMsg);
};
// Add OnClose event listener
ws.OnClose += (WebSocketCloseCode code) =>{
Debug.Log("WS closed with code: " + code.ToString());
};
// Connect to the server
ws.Connect();
}
// Update is called once per frame
void Update () {
if(Input.GetKeyDown(KeyCode.Space)){
WsSubmit();
}
}
void WsSubmit() {
DateTime now=DateTime.Now;
ws.Send(Encoding.UTF8.GetBytes(now.ToString()));
}
}
uGUIテキストで「Font Awesome」のアイコンを使う
Reference:https://answers.unity.com/questions/1434980/how-to-add-font-awesome-into-unity-using-textmesh.html
(/Fonts/fontawesome-webfont.ttf)
(/TextMesh Pro/)
/Fonts/fontawesome-webfont SDF.asset
- https://fontawesome.com/v4.7.0/get-started/から
font-awesome-4.7.0.zipをダウンロード font-awesome-4.7.0/fonts/fontawesome-webfont.ttfをプロジェクト内(/Fonts/fontawesome-webfont.ttf)へ移動Window.TextMeshPro.Font Asset Creatorを起動Import TMP Essentialsを行う(Import EMP Examples & Extrasは不要)- AssetCreatorFontSettings
- Font Source :
fontawesome-webfont - Font Size :
Auto Sizing - Font Padding :
5 - Packing method :
Fast (or Optimum, as you want) - Atlas Resolution :
2048 x 2048 (4096 x 4096 crashed my Unity) - Charactter Set :
Custom Range - Character Sequence :
61440-62176 (See bottom note to understand why these values) - Font Style :
Normal, 2 - Rendering mode :
SDF16
- Font Source :
Generate Font AtlasSaveし/Fonts/fontawesome-webfont SDF.assetで保存UI.Canvasを作成UI.Text - TextMeshProのフォントにfontawesome-webfont SDFを設定- テキストにUnicode(Ex:
\U0000f259)を設定
※https://fontawesome.com/v4.7.0/icons/で確認
(※TextUnicode.csを入れる必要あるかも)
using System.Globalization;
using System.Text.RegularExpressions;
namespace UnityEngine.UI
{
public class TextUnicode : Text
{
private bool disableDirty = false;
private Regex regexp = new Regex( @"\\u(?<Value>[a-zA-Z0-9]{4})" );
protected override void OnPopulateMesh( VertexHelper vh )
{
string cache = text;
disableDirty = true;
text = Decode( text );
base.OnPopulateMesh( vh );
text = cache;
disableDirty = false;
}
private string Decode( string value )
{
return regexp.Replace( value, m => ( ( char )int.Parse( m.Groups[ "Value" ].Value, NumberStyles.HexNumber ) ).ToString() );
}
public override void SetLayoutDirty()
{
if ( disableDirty ) return;
base.SetLayoutDirty();
}
public override void SetVerticesDirty()
{
if ( disableDirty ) return;
base.SetVerticesDirty();
}
public override void SetMaterialDirty()
{
if ( disableDirty ) return;
base.SetMaterialDirty();
}
}
}