読者です 読者をやめる 読者になる 読者になる

hayateasdf's blog

C#,javascript,pythonなどいろいろ。広く浅く

Unity シーンを管理してトランジションを行う。uGUI

設計

シーン遷移する前にデータ読み込み(通信処理)でコルーチンを使うと思うので、トランジションはIEnumeratorで書く。

とりあえず適当にインターフェイスとか定義

using System.Collections;
using UnityEngine;

public interface ITransition
{
    IEnumerator onStartTransition();
    IEnumerator onEndTransition();
}
public abstract class ATransition : MonoBehaviour, ITransition
{
    public abstract IEnumerator onStartTransition();
    public abstract IEnumerator onEndTransition();
}

シーンマネージャで各シーンから遷移処理の呼び出し

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Linq;

public class SceneManager : MonoBehaviour
{
    #region singleton
    private static SceneManager instance = null;
    public static SceneManager Instance
    {
        get
        {
            if (instance == null)
                instance = (SceneManager)FindObjectOfType(typeof(SceneManager));
            return instance;
        }
    }
    void Awake()
    {
        if (SceneManager.Instance != this)
            Destroy(this);
    }
    #endregion

    [SerializeField]
    List<ATransition> cache;
    public T Cache<T>() where T : ATransition
    {
        return (T)cache.FirstOrDefault(x => (x as T) != null);
    }

    public void Transition(ATransition now, ATransition next)
    {
        StartCoroutine(_Transition(now, next));
    }
    private IEnumerator _Transition(ATransition now, ATransition next)
    {
        if (now != null)
            yield return now.onEndTransition();

        yield return next.onStartTransition();

        Debug.Log(string.Format("transition: end -> {0}, start -> {1}", now == null ? "null" : now.GetType().Name, next.GetType().Name));
    }
}

遷移用にScene1,Scene2クラス作成

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Scene1 : ATransition
{
    public override IEnumerator onStartTransition()
    {
        gameObject.SetActive(true);
        yield return null;
    }
    public override IEnumerator onEndTransition()
    {
        gameObject.SetActive(false);
        yield return null;
    }
    public void onclick()
    {
        var next = SceneManager.Instance.Cache<Scene2>();
        SceneManager.Instance.Transition(this, next);
    }
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Scene2 : ATransition
{
    public override IEnumerator onStartTransition()
    {
        gameObject.SetActive(true);
        yield return null;
    }
    public override IEnumerator onEndTransition()
    {
        gameObject.SetActive(false);
        yield return null;
    }
    public void onclick()
    {
        var next = SceneManager.Instance.Cache<Scene1>();
        SceneManager.Instance.Transition(this, next);
    }
}

ヒエラルキー

  1. canvas作成。
  2. canvas内でCreate Empty > 名前をScene1に変更。その子でボタン作成。
  3. Scene1にScene1.csをadd compenent。ボタンにonclickを登録。
  4. canvas内でCreate Empty > 名前をScene2に変更。その子でボタン作成。
  5. Scene2にScene2.csをadd compenent。ボタンにonclickを登録。

  6. 適当にCreate Empty > SceneManager.csをadd component。

  7. SceneManager.csのインスペクターのキャッシュの部分に上記で作成したScene1,Scene2を追加。
  8. 適当にエントリーポイント用のスクリプト作って開始。※Scene1,Scene2は非アクティブ状態にしておく。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class EntryPoint : MonoBehaviour {
    void Start() {
        var next = SceneManager.Instance.Cache<Scene1>();
        SceneManager.Instance.Transition(null, next);
    }
}

ボタンを押せば遷移するようになる。

シーンにCanvasGroupをadd componentして、alphaのアニメーションなどを行えばそれっぽくなる。

[SerializeField]
CanvasGroup group;

public override IEnumerator onStartTransition() {
    gameObject.SetActive(true);
    yield return startAnimation();
}
public override IEnumerator onEndTransition() {
    yield return endAnimation();
    gameObject.SetActive(false);
}

private IEnumerator startAnimation() {
    group.blockRaycasts = false;
    var start = Time.time;

    var now = start;
    while (now - start < 1.0f) {
        group.alpha = Mathf.Lerp(0f, 1f, now - start);
        yield return null;
        now = Time.time;
    }

    group.alpha = 1f;
    group.blockRaycasts = true;
}
private IEnumerator endAnimation() {
    group.blockRaycasts = false;
    var start = Time.time;

    var now = start;
    while (now - start < 1.0f) {
        group.alpha = Mathf.Lerp(1f, 0f, now - start);
        yield return null;
        now = Time.time;
    }
    
    group.alpha = 0f;
    group.blockRaycasts = true;
}

avastがskypeをブロックしていた件

avast .. 無料アンチウイルスソフト

最近skypeの動きが重い(というか止まっている)ので、skypeをアンインストール→再インストールとかしてみたが変わらず。

試しにavastを無効にしてskypeを起動したら通常通りの動きに戻った。
一応まとめておく
右下のタスクバーからアバストのアイコンをクリック。
設定 > 一般 > スキャンからの除外
C:\Users\Administrator\AppData\Roaming\Skype\* ※Administratorの部分は現在のユーザ名のフォルダになります
C:\Program Files (x86)\Skype\Browser\*
の2つを追加
skype再起動

unity Anima2D test

f:id:hayateasdf:20170321183007p:plain

階層

  • skeletal_human

skeltal_human

root要素
animator,PoseManagerなど全体制御のスクリプトを保持

Bones


(白い部分)

SpriteMesh

画像素材
ポリゴンと重み付け
骨との連動
(緑の部分)

IKs

Inverse Kinematics
ターゲットの骨が回転した時、親の骨も動くようになる。
(青丸の部分)

作り方

画像を探す 棒人間

各パーツに分解する f:id:hayateasdf:20170321183023p:plain

Unityで読み込んでSprite Mode -> Multipleに変更し、Applyして、SpriteEditorを開いて、さっき分けた部分を適当に矩形に分割していく。

f:id:hayateasdf:20170321183108p:plain

Projectタブでさっきの画像を右クリックし、Create > Anima2D > SpriteMesh

で、出てきたパーツをSceneタブに追加していき、棒人間を組み立てる。(元が白色なので骨の色とカブり、見づらいので適当な色に変えておく)

レイヤーはInspector > Sprite Mesh Instance > Order in Layerで変えれた。

その後、骨を付けていく。
各画像(SpriteMesh)のInspector > Sprite Mesh Instance > Bonesの部分に骨を追加していく。

Unity > Window > Anima2D > SpriteMesh Editorを開く。

f:id:hayateasdf:20170321183127p:plain

SpriteMesh EditorBindを押して骨を関連付ける。
あとは適当にSliceテッセレーションとかいじってポリゴン増やしたり、Weight toolauto,Smoothを適当に重み付け。

これを各パーツで行い、腕、足にIKを追加したら完成。

f:id:hayateasdf:20170321183118p:plain

※ 骨の部分とかSpriteMesh EditorとかIKとかの部分をだいぶハショっているので、詳しくはAnima2DのUserGuide.pdfを読んでください。

f:id:hayateasdf:20170321183139p:plain

動かすと身体が切れるので、各パーツの付け根部分を衣服とかで隠せば自然な感じになると思われる。

f:id:hayateasdf:20170321183159g:plain

windowsでgit bash使ってfind-xargs-grep検索

例) jsonファイルで文字列"100"を検索

find . -type f -name "*.json" -print0 | xargs -0 grep "100"

pythonでテンプレート自作 (json読み込みからhtml出力)

ヒアドキュメントとreplace

ヒアドキュメントとreplaceの合わせ技で特定のキーワードに対して必要なデータに変換してぶっこむことが出来る。 たとえば

 s = """hello {name}!""".replace("{name}", "hoge")

のようにじっこうすると{name}の部分がhogeに変換される。
hello hoge!

このようにやれば正規表現知らなくても特定のキーワードさえ決めてしまえば変換して流し込める。jsonを読み込んで、htmlに流し込むことも可能。もちろん、ajax使ってjavascriptでやってもいいけどね。

test.json

{
    "user_data": {
        "#": "ユーザデータ", 
        "id": "int(11) id", 
        "name": "varchar(256) ユーザー名",
        "description": "varchar(256) 説明", 
        "update_time": "datetime 更新日時", 
        "create_time": "datetime 作成日時"
    }, 
    "stone_data": {
        "#": "ストーンデータ", 
        "id": "int(11) id", 
        "name": "varchar(256) 販売表示名称 ", 
        "limit_count": "int(11) 上限回数", 
        "description": "varchar(256) 説明", 
        "update_time": "datetime 更新日時", 
        "create_time": "datetime 作成日時"
    }
}

test.py

# -*- coding: utf-8 -*-
import sys
import json

def html_src():
    return """
<html>

<head>
    <script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
    <meta charset="utf-8">
</head>

<body>
    <style>
        .in { display: inline; padding-left: 1em; }
    </style>

    <input type="text" id="text"><br>
    <content id="content">
    {html_template}
    </content>

<!-- logic -->
    <script>
    var onToggle = function() {
        var id = "#" + $(this).attr("name");
        if ($(id).is(":visible")) {
            $(id).hide();
        } else {
            $(id).show();
        }
    };
    $(document).ready(function() {
        var changeVisible = function(elem, flag) {
            if (flag) {
                elem.show();
            } else {
                elem.hide();
            }
        };
        var changeText = function() {
            str = $(this).val();
            strs = str.split(" ");
            $("#content > div > h2").each(function() {
                var visible = true;
                for(var i = 0; i < strs.length; ++i) {
                    var name = $(this).html();
                    if (name.indexOf(strs[i]) === -1) {
                      visible = false;
                      break;
                    }
                }
                var id = "#" + name.split(" ")[0] + "-table";
                changeVisible($(id), visible);
            });
        };
        $("#text").each(function() {
            $(this).bind("keyup", changeText);
        }); 

        {js_template}
    });
    </script>
</body>
</html>
    """

def table_template(table_str, comment_str, list_hash):
    list_template = ""
    for k, v in list_hash.items():
        list_template += "<li>{0} - {1}</li>".format(k.encode('utf_8'), v.encode('utf_8'))

    template = """
    <div id="{table}-table">
        <button id="{table}-button" name="{table}">on</button>
        <h2 class="in">{table} #{comment}</h2><br>
        <div id={table}>
        <ul>
            {list}
        </ul>
        </div>
    </div>
    """.replace("{table}", table_str.encode('utf_8')).replace("{comment}", comment_str.encode('utf_8')).replace("{list}", list_template)
    return template

def read_json(path):
    f = open(path, 'r')
    json_data = json.load(f)
    f.close()
    return json_data

if __name__ == '__main__':
    json_data = read_json('test.json')

    html_tables = ""
    for k, v in json_data.items():
        table_name = k
        comment = v.pop("#")
        list = v
        html_tables += table_template(table_name, comment, list)

    js_tables = ""
    for k,v in json_data.items():
        table_name = k
        js_tables += """
            $("#{0}-button").on("click", onToggle);
            $("#{0}").hide();
        """.replace("{0}", table_name)

    t = html_src()
    new_html = t.replace("{html_template}", html_tables).replace("{js_template}", js_tables.encode('utf_8'))
    f = open("test.html", "w")
    f.write(new_html)
    f.close()

electron テンプレート生成の自動化

cheat.sh

#!/bin/bash

# $1 作成ディレクトリ
new_dir=${1:-hoge}

mkdir $new_dir

pushd $new_dir

npm init -y
npm i -D electron-prebuilt

cat << EOS > index.html
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>sample</title>
</head>
<body>
  <p>Hello World</p>
</body>
</html>
EOS

cat << EOS > index.js
'user strict';
const electron = require("electron");
const app = electron.app;
const BrowserWindow = electron.BrowserWindow;
let mainWindow;

app.on('window-all-closed', function() {
  if (process.platform != 'darwin') {
      app.quit();
  }
});

app.on('ready', function() {
  mainWindow = new BrowserWindow({width: 800, heigth: 600});
  mainWindow.loadURL('file://' + __dirname + '/index.html');
  mainWindow.on('closed', function() {
      mainWindow = null;
  });
});
EOS

popd

electron ./$new_dir

qiita.com