2016年6月29日 星期三

Unity

UI Event System

1
UnityAction btnBackAction = () => { onBtnClick(); };
btnBack.onClick.AddListener(btnBackAction);

2
inputField.onEndEdit.AddListener(new UnityAction<string>(onFunc));

3
inputField.onEndEdit.AddListener((string value) =>{ onFunc(value); } );

4
inputField.onEndEdit.AddListener(delegate { onFunc(""); });//參數固定

Message System

Message System is a sub system of event system

這種做法,類似於直接呼叫。

//define a message interface
using UnityEngine.EventSystems;
public interface IMessageSystemHandler : IEventSystemHandler {

    void Message1();
    void Message2();
}

//define a MonoBehaviour class
public class EventSys : MonoBehaviour,IMessageSystemHandler 
{

  public void Message1()
    {
    Debug.Log("Message1");
    }
  public void Message2()
    {
        Debug.Log("Message2");
    }
}

//use EventSys in main flow
using UnityEngine.EventSystems;
public class Main : MonoBehaviour 
{


  void Start () {

  //var eventData = new CustomEventData { publicField = 5.0f };
  //usage 1 ,use real time delegate
  //bad for garbage collection 
  //ExecuteEvents.Execute(gameobject, null,(IMessageSystemHandler ms,
BaseEventData b) => ms.Message1());

  //or
  ExecuteEvents.Execute(gameobject, null, MSH2);
  //or  
  ExecuteEvents.Execute(gameobject, null, MSH2);
  Debug.Log("main end");
  }
 

    private void MSH(IMessageSystemHandler handler, BaseEventData data)
    {
        handler.Message1();
    }

    //delegage this function to MSH2
    private ExecuteEvents.EventFunction MSH2 = delegate (IMessageSystemHandler handler, BaseEventData data)
    {
        handler.Message1();
    };

}

Event Manager

http://wiki.unity3d.com/index.php/CSharpEventManager

using UnityEngine;
using System.Collections;
 
public class TestListener : MonoBehaviour, IEventListener
{
    void Start()
    {
        EventManager.instance.AddListener(this as IEventListener, "TestEvent");
    }
 
    bool IEventListener.HandleEvent(IEvent evt)
    {
        string txt = evt.GetData() as string;
        Debug.Log("Event received: " + evt.GetName() + " with data: " + txt);
        return true;
    }
}

Messenger

http://wiki.unity3d.com/index.php/Advanced_CSharp_Messenger

c# Regular Expression

Regular Expression

Regex regularExpression = new Regex("^[a-zA-Z0-9_]*$");


//contains only upper and lowercase letters, numbers, and underscores.




  • * ^ : start of string
  • [ : beginning of character group
  • a-z : any lowercase letter
  • A-Z : any uppercase letter
  • 0-9 : any digit
  • _ : underscore
  • ] : end of character group
  • * : zero or more of the given characters
  • $ : end of string
  • 2016年5月10日 星期二

    VS Code Setting

    Visaul Studio Code Setting

    MS官方說明安裝

    https://marketplace.visualstudio.com/items?itemName=lukehoban.Go 照著安裝即可

    安裝debug工具 delve

    https//github.com/derekparker/delve

    1. 用git取得delve的repository
    2. install mingw-w64(gcc for win)
    3. mingw-32-make install in delve folder
    4. compiled exe file would be in environment %GO%/bin

    2016年5月3日 星期二

    sequelize- javascript ORM for mySQL....

    Define model

    //column option
    field:'field_name'          //field name
    type:Sequelize.STRING       //data type
    allowNull: true             //
    defaultValue:'value'        //default value
    unique: true                //string value Sequelize.STRING 
    unique: 'compositeIndex'    //string value, 不能相同string
    primaryKey: true
    autoIncrement: true         //auto increament column for integer
    comment: 'this is comment'  //comment
    


    var Foo = sequelize.define('foo', {
     // instantiating will automatically set the flag to true if not set
     flag: { type: Sequelize.BOOLEAN, allowNull: false, defaultValue: true},
    
     // default values for dates => current time
     myDate: { type: Sequelize.DATE, defaultValue: Sequelize.NOW },
    
     // setting allowNull to false will add NOT NULL to the column, which means an error will be
     // thrown from the DB when the query is executed if the column is null. If you want to check that a value
     // is not null before querying the DB, look at the validations section below.
     title: { type: Sequelize.STRING, allowNull: false},
    
     // Creating two objects with the same value will throw an error. The unique property can be either a
     // boolean, or a string. If you provide the same string for multiple columns, they will form a
     // composite unique key.
     someUnique: {type: Sequelize.STRING, unique: true},
     uniqueOne: { type: Sequelize.STRING,  unique: 'compositeIndex'},
     uniqueTwo: { type: Sequelize.INTEGER, unique: 'compositeIndex'}
    
     // The unique property is simply a shorthand to create a unique index.
     someUnique: {type: Sequelize.STRING, unique: true}
     // It's exactly the same as creating the index in the model's options.
     {someUnique: {type: Sequelize.STRING}},
     {indexes: [{unique: true, fields: ['someUnique']}]}
    
     // Go on reading for further information about primary keys
     identifier: { type: Sequelize.STRING, primaryKey: true},
    
     // autoIncrement can be used to create auto_incrementing integer columns
     incrementMe: { type: Sequelize.INTEGER, autoIncrement: true },
    
     // Comments can be specified for each field for MySQL and PG
     hasComment: { type: Sequelize.INTEGER, comment: "I'm a comment!" },
    
     // You can specify a custom field name via the "field" attribute:
     fieldWithUnderscores: { type: Sequelize.STRING, field: "field_with_underscores" },
    
     // It is possible to create foreign keys:
     bar_id: {
       type: Sequelize.INTEGER,
    
       references: {
         // This is a reference to another model
         model: Bar,
    
         // This is the column name of the referenced model
         key: 'id',
    
         // This declares when to check the foreign key constraint. PostgreSQL only.
         deferrable: Sequelize.Deferrable.INITIALLY_IMMEDIATE
       }
     }
    })
    

    也可以reference 其他model

    2016年4月28日 星期四

    javaScript features (ECMAScript6)

    Class

    define

    class Queue {
        _queue;      
      constructor(contents = []) {
        this._queue = [...contents];
      }
      pop() {
        const value = this._queue[0];
        this._queue.splice(0, 1);
        return value;
      }
    

    extends

    class PeekableQueue extends Queue {
      peek() {
        return this._queue[0];
      }
    
    class Account extends Foo {
      constructor(balance) {
        this.balance = balance;
      }
    
      history(done) {
        someLongTask((err, data) => {
          // Do something with data
          done(null, data);
        });
      }
    
      deposit(amount) {
        this.balance += amount;
        return this.balance;
      }
    }
    
    // Currently, you can only declare functions in a class
    Account.types = ['checking', 'savings'];
    

    get,set

    class Account {
      constructor() {
        this.balance = 0;
      }
    
      get underBudget() {
        return this.balance >= 0;
      }
    
      get overBudget() {
        return this.balance < 0;
      }
    }
    
    const myAccount = Account();
    myAccount.balance = 100;
    console.log(myAccount.underBudget); // true
    

    Iterable Class

    可建立iterable class,並且可用generator建立iterator。

    class MyIterable {
      constructor(items) {
        this.items = items;
      }
    
      *[Symbol.iterator]() {
        for (let item of this.items) {
          yield `Hello, ${item}`;
        }
      }
    }
    
    const test = new MyIterable([1, 2, 3, 4, 5]);
    
    for (let item of test) {
      console.log(item); // => Hello, 1...
    }
    

    Map

    let map = new Map(arr);
    
    for (let key of map.keys()) {
      console.log(key);
    }
    
    for (let value of map.values()) {
      console.log(value);
    }
    
    for (let item of map.entries()) {
      console.log(item[0], item[1]
    }
    

    Module

    基本定義與引用

    用ES6 export,就用import;不要用require

    一個文件中不要export與default export一起用

    不要在import中使用*,確保module中有一個default export

    //定義模組 module.js
    
    var privateVar = "privateVar";  
    //不能被外部引用的成員
    export var publicVar = "and this one is public";   
    //export出去,可被外部引用的成員
    
    export function getVar() {
       return privateVar;
    };
    
    //引用模組 use.js
    import { getVar, publicVar } from 'mymodule'; 
    //import getVar及publicVar兩個成員
    console.log(getVar());
    
    //一次引用這個模組的所有可引用成員
    X import 'mm' from 'mymodule';
    X import 'mymodule' as mm;
    //或是這樣
    import * as 'mm' from 'mymodule';  //不建議使用*
    import abc =require('mymodule');
    
    //不一定都有implement
    import defaultMember from "module-name";
    import * as name from "module-name";
    import { member } from "module-name";
    import { member as alias } from "module-name";
    import { member1 , member2 } from "module-name";
    import { member1 , member2 as alias2 , [...] } from "module-name";
    import defaultMember, { member [ , [...] ] } from "module-name";
    import defaultMember, * as name from "module-name";
    import "module-name";
    
    console.log(mm.gerVar());
    

    default export(無命名export) (文件中只有一個成員)

    //------ myFunc.js ------
    export default function () { ... };
    
    //------ main1.js ------
    import myFunc from 'myFunc';
    myFunc();
    
    //------ MyClass.js ------
    export default class { ... };
     
    //------ main2.js ------
    import MyClass from 'MyClass';
    let inst = new MyClass();
    
    

    一個文件中同時有export(一般export)與default export(無命名export)

    //------ underscore.js ------
    export default function (obj) {
        ...
    };
    
    export function each(obj, iterator, context) {
        ...
    }
    export { each as forEach };
    
    //------ main.js ------
    import _, { each } from 'underscore';
    ...
    
    

    default export就是another named export

    //以下兩者相同
    import { default as foo } from 'lib';
    import foo from 'lib';
    
    //以下兩個模組export相同
    //------ module1.js ------
    export default 123;
    
    //------ module2.js ------
    const D = 123;
    export { D as default };
    
    

    commonJS的module

    //------ underscore.js ------
    var _ = function (obj) {
        ...
    };
    var each = _.each = _.forEach =
        function (obj, iterator, context) {
            ...
        };
    module.exports = _;
     
    
    //------ main.js ------
    var _ = require('underscore');
    var each = _.each;
    ...
    
    
    //------ lib.js ------
    var sqrt = Math.sqrt;
    function square(x) {
        return x * x;
    }
    function diag(x, y) {
        return sqrt(square(x) + square(y));
    }
    module.exports = {
        sqrt: sqrt,
        square: square,
        diag: diag,
    };
     
    //------ main.js ------
    var square = require('lib').square;
    var diag = require('lib').diag;
    console.log(square(11)); // 121
    console.log(diag(4, 3)); // 5
    
    
    
    

    2016年3月17日 星期四

    頂點及索引

    Vertex and Index

    頂點 ->索引
    v0 -> 0
    v1 -> 1
    v2 -> 2
    v3 -> 3

    index決定三角形構成方式
    [0,1,2,2,3,0]
    v0->v1->v2
    v2->v3->v0
    決定了兩個三角形構成,
    也就是決定了兩個面

    頂點代表多重意義,基本上是多種屬性的重疊
    一般封裝的方式有兩種:

    struct Vertex {
      Vector3 Position;
      Vector3 Normal;
      Vector3 Color;
    }

    Vector3[] Vertices;
    Vector3[] normals;
    Vector3[] colors;

    Vertex Buffer

    存放vertices的區域,稱為vertex buffer
    在DX/OpenGL中,我們需要
    1 申請vertex buffer
    2 綁定buffer
    3 上傳vertex資料
    4 一個模型對應一個buffer

    在unity中, 這些已經被封裝了

    Gluint vertexbuffer;
    glGenBuffer(1,&vertexbuffer);
    glBindBuffer(GL_ARRAY_BUFFER,vertexbuffer);
    glBufferData(GL_ARRAY_BUFFER,sizeof(g_vertex_buffer_data),g_vertex_buffer_data,GL_STATIC_DRAM);

    Index Buffer

    存放index資料的暫存區,稱為index buffer

    不同的向量方向,構成的三角形不同

    [0,1,2]構成 v0->v1, v1->v2兩個向量
    [2,1,0]構成v2->v1,v1->v2兩個向量
    兩者的法向量不同,所以是不同三角形


     三角形的正面及背面





    Dx以情況A為正向,依據左手系統,法向量朝我方。

    OpenGL以情況B為正向,依據右手系統,法向量朝我方。


    索引的意義


    1 每三個索引,決定一個三角形(面數)
    2 索引順序不同,構成三角形不同
    3 DX預設順時針為正向,OpenGL預設逆時針為正向
    4 索引會決定三角形的正面、背面
    5 索引可表示重複使用的頂點,可減少記憶體使用
    6 索引是簡單整數,有些設備一個物件只支援65535個索引=21845個三角形

    Unity物件頂點數限制65000個,也是從此而來。

    物件頂點數超過65535個,可進行頂點資料及索引拆分,分成兩份資料。

    7 合併緩衝區

    用索引決定渲染

    渲染整個模型,索引從0到最後
    渲染某部分,更改索引起始位置及結束位置

    合併緩衝區

    就是把兩個物件的頂點緩衝區及索引緩衝區合併,當成一個物件處理。

    假設三個物件的vertexBuffer及indexBuffer:
    v0   v1  v2 => 0,1,2
    m0 m1 m2 => 0,1,2
    n0  n1   n2 => 0,1,2

    合併後
    [v0,v1,v2,m0,m1,m2,n0,n1,n2]
    [0,1,2,(0+3),(1+3),(2+3),(0+6),(1+6),(2+6)]

    0+3=4,表示是vertex的第四個=m0
    1+4=5,表示是vertex的第五個=m2

    這就是unity draw call batching的原理
    合併緩衝區在物件是靜態時,效果最好,
    如果非static卻一直合併緩衝區,就適得其反。
    所以unity draw call batching 有分dynamic及static,
    確保物件是static才使用static方法。

    顏色

    顏色表示法


    假設使用向量表示顏色,最小值為0,最大值為1。
    三原色可表示為:

    r=(1,0,0)
    g=(0,1,0)
    b=(0,0,1)

    8位元表示法,最小值為0,最大值為255
    r=(255,0,0)
    g=(0,255,0)
    b=(0,0,255)

    [0,1]對應到[0,255],只要每個分量除255即可。



    顏色運算

    加法

    r+g=(1,0,0)+(0,1,0)=(1,1,0)

    減法

    (1,1,0)-(0,1,0)=(1,0,0)

    數乘

    0.5*(1,1,1)=(0.5,0.5,0.5)

    分量乘法

    (r0,r1,r2)*(g0,g1,g2)=(r0*g0,r1*g1,r2*g2)

    分量乘法應用
    假設c0=(1,1,1) 太陽光
    c1=(0.5,0.25,0.5)  材質反射率

    c0*c1=(0.5,0.25,0.5)
    就是太陽光照射材質後,反射出來的光

    向量點積、向量叉積對顏色無意義


    顏色分量要限縮在0-1之間,超過這個範圍就無意義