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之間,超過這個範圍就無意義




    2016年3月8日 星期二

    射線 平面

    射線

    定義

    定義射線需要起點,方向,長度
    起點p0
    方向=單位向量u
    長度=t

    向量相加為所形成平行四邊形的對角線
    得到射線p(t)=p0+tu


    Unity Raycast API

    public static bool Raycast(Vector3 originVector3 direction, float maxDistance)
    其實就和射線定義相同(起點,方向,長度)


    平面

    定義

    p為平面上任意點,n為平面法向量,p1為法向量交於平面的點

    p-p1向量=p-p1 假設為(ax,ay,az)
    n假設為 (bx,by,bz)
    p-p1與n垂直
    向量點積公式 (a長)*(b長)*Cos(90)=0
    向量點積算法(ax*bx+ay*by+cz*bz)
    得到n.(p-p1)=0


    射線與平面相交


    射線
    p=p0+tu

    平面
    n.(p-p1)=0

    把射線p帶入平面

    n.(p0+tu - p1)=0

    n.p0+n.tu-n.p1=0

    n.tu=n.p1-n.p0

    t=n.p1-n.p0/n.u

    這裡 (.)是點積

    若t>=0,射線與平面相交,且交點為p0+tu
    若t<0,兩不相交

    矩陣

    矩陣運算

    矩陣相加   對應元素相加
    矩陣相減   對應元素相減
    矩陣相乘   每個元素就是兩個矩陣的行與列點積。所以兩個矩陣的行與列維度要相同。
    矩陣數乘   每個元素乘上一個數
    矩陣相等   對應的每個元素相等

    矩陣相乘

    條件

    假設A矩陣*B矩陣
    則A行向量的元素個數=B列向量元素個數
    (大陸橫為行,直為列)
    否則無法相乘


    A=[1- 5 -4]
         [3   2  1]

    B=[2  1  0 ]
         [0  -2  1]
         [-1  2   3]

    AB=[(-1,5,-4).(2,0,-1)   (-1,5,-4).(1,-2,2)   (-1,5,-4).(0,1,3)]
            [(3,2,1).(2,0,1)       (3,2,1).(1,-1,2)      (3,2,1)(0,1,3)]

    行.列  (點積)

    矩陣乘法不滿足交換率

    A*B != B*A

    矩陣乘法滿足結合率

    A(B+C)=AB+AB
    (AB)C=A(BC)


    矩陣除法

    矩陣運算沒有除法

    向量矩陣

    行向量矩陣
    A=[1 3 3]

    列向量矩陣
    B= [2]
          [2]
          [3]

    向量-矩陣乘法

    OpenGL 左乘方式--矩陣在左,向量在右    記憶法(O在左)
    DirectX    右乘方式--矩陣在右,向量在左    記憶法(X在右)

    因為矩陣乘法不反足交換率,所以在左在右結果不同。


    轉置矩陣(Transpose)

    把一個矩陣的行和列互換。mxn的轉置矩陣就是nxm。
    原矩陣的行向量=轉置矩陣的列向量

    A=[1  1  1 ]
         [2  2   2]

    C=A.transpose
    [1 2]
    [1 2]
    [1 2]


    B=[a b c d]

    D=B.transpose
    [a]
    [b]
    [c]
    [d]

    A*B=(D*C).transpose

    範例
    A,B兩向量
    C=A.transpose
    D=B.transpose

    A*B    ↘︎  C*D    =>  A*B=D*C      兩個剛好交錯
    B*A   ↗︎   D*C    =>  B*A=C*D

    矩陣乘以向量

    1 矩陣維度與向量元素個數不需相同

    2 矩陣*向量  =>變成向量

    3 矩陣*向量=向量*矩陣轉置(要自己計算)

    向量 X=(1,2,3,4);

    A=[1  1  1 1]
         [2  2   2 2]
         [3  3  3  3]
         [4  4  4  4]

    A*X=(1111.(1234)  2222.(1234)  3333.(1234)   4444.(1234))

    A.transpose=
    [1 2 3 4]
    [1 2 3 4]
    [1 2 3 4]
    [1 2 3 4]

    X*A.transpose
    ((1234)(1111)   (1234)(2222)  (1234)(3333)  (1234)(4444))


     Unity中矩陣乘以向量

    可以直接矩陣*向量
    不能向量*矩陣  (要自己計算)

    矩陣A
    向量V

    A*V  =>ok
    V*A  =>error


    單位矩陣

    1 是正方形矩陣

    2 中心左上右下斜對角線(back slash)的元素都是1

    3 其他元素都是0

    4 任何矩陣*單位矩陣,結果不變

    5 單位矩陣就是矩陣中的數字1(跟單位向量相同)

    [1  0   0]
    [0  1   0]
    [0  0   1]

    逆矩陣(Inverse)

    1 矩陣運算沒有除法

    2 只有正方形矩陣才能夠逆運算

    3 一個nxn的矩陣的逆矩陣,仍然是nxn的矩陣

    4 不是所有的矩陣都有逆矩陣,有逆矩陣的矩陣稱為可逆

    5 如果有可逆矩陣,這個逆矩陣一定是唯一的

    6 將一個矩陣與他的逆矩陣相乘,結果一定為單位矩陣

    有矩陣A,B,C,且A=B*C,且D為C的逆矩陣
    A=BC
    AD=BDC (DC=1)
    AD=B

    範例

    有一點a
    一矩陣b
    d=b的逆矩陣
    轉換後的點c = a*b

    cd=a*b*d  (bd=1)
    cd=a

    可找到原始的a點

    常用來把點從局部空間轉換到世界空間,
    或從世界空間轉換回局部空間。


    矩陣計算平移

    1 點的位移向量,使用DirectX要寫在矩陣第四行的前三個,
       因為如果寫在前三行,那會被x,y,z乘到
       只能寫在第四行的前三個,經過計算後就分別被x,y,z加

       使用OpenGL則分別寫在前三行的最後一元素

        directX與openGL可使用矩陣轉置來切換

    2 矩陣的每個位置數字都有意義,都是經過設計的

    3 因為3x3不夠用,所以擴充為4x4,自己新增w

    4 當w=0,(x,y,z,0) 就是用來描述向量 =>可得到原始向量

    5 當w=1,(x,y,z,1) 就是用來描述點    =>可算出位移後的點


    DirectX計算(右乘,矩陣在右,向量在左)


    A=[x,y,z,w] 行向量

    M= 單位矩陣
           1  0  0  0
           0  1  0  0
           0  0  1  0
           0  0  0  1

    A*M=

    x*1+y*0+z*0+w*0=x
    x*0+y*1+z*0+w*0=y
    x*0+y*0+z*1+w*0=z
    x*0+y*0+z*0+w*1=w

    假設位移向量B=(tx,ty,tz),則A位移後的點為(x+tx,y+ty,z+tz)
    tx,ty,tz寫在矩陣最下行靠左

    m=
    1  0   0   0
    0  1   0   0
    0   0  1   0
    tx  ty tz  1

    A*m=[x,y,z,w] *m=

    x*1+y*0+z*0+w*tx=x+wtx
    x*0+y*1+z*0+w*ty=y+wty
    x*0+y*0+z*1+w*tz=z+wtz
    x*0+y*0+z*0+w*1=w

    當w=1,結果就是 x+tx,y+ty,z+tz,1
    因為w是我們自己擴充的,所以可設為1

    所以經由以上算法,點A的位移,利用矩陣運算可得到結果。
    矩陣每個位置的數字都有固定意義,都事先設定好的。


    OpenGL計算(左乘,矩陣在左,向量在右 =Unity的系統 )

    A=[x,y,z,w] 行向量

    M= 單位矩陣
           1  0  0  0
           0  1  0  0
           0  0  1  0
           0  0  0  1

    M*A=

    x*1+y*0+z*0+w*0=x
    x*0+y*1+z*0+w*0=y
    x*0+y*0+z*1+w*0=z
    x*0+y*0+z*0+w*1=w

    假設位移向量B=(tx,ty,tz),則A位移後的點為(x+tx,y+ty,z+tz)
    tx,ty,tz寫在矩陣前三行最末位

    m=
    1  0   0   tx
    0  1   0   ty
    0   0  1   tz
    0  0  0    1

    m*A=m*[x,y,z,w] =

    1*x+0*y+0*z+w*tx=x+wtx
    0*x+1*y+0*z+w*ty=y+wty
    0*x+0*y+1*z+w*tz=z+wtz
    0*x+0*y+0*z+w*1=w

    當w=1,結果就是 x+tx,y+ty,z+tz,1
    因為w是我們自己擴充的,所以可設為1

    矩陣計算縮放

    1 縮放就是倍數的關係,所以(x,y,z)要能分別乘以縮放的數字

    2 因此只能放在斜對角線的元素位置上

    sx 0  0  0
    0  sy 0  0
    0  0  sz 0
    0  0  0  0

    假設x放大2,y所小0.5,z放大3,那就是

    2     0  0  0
    0  0.5  0  0
    0     0  3  0
    0     0  0  0

    範例

    矩陣A=
    [1 0  0      0]
    [0  2  0     0]
    [0  0  0.5  0]
    [0  0  0     1]

    向量V=[x,y,z,w]

    v*A=
    x*1+y*0+z*0+w*0=x
    x*0+y*2+z*0+w*0=2y
    x*0+y*0+z*0.5+w*0=0.5z
    x*0+y*0+z*0+w*0=w

    =[x,2y,0.5z,0]
    =x不變,y放大2,z縮小0.5


    矩陣計算旋轉

    1 旋轉要考慮軸

    2 旋轉要考率角度(非弧度)


    假設延n軸旋轉 n=(x,y,z)
    轉 a角度
    c=cos(a)
    s=sin(a)

    矩陣為:

    c+(1-c)*x*x        (1-c)*x*y+s*z      (1-c)*x*z-s*y      0
    (1-c)*x*y-s*z       c+(1-c)*y*y       (1-c)*y*z+s*x     0
    (1-c)*x*z+s*y     (1-c)*y*z-s*x       c+(1-c)*z*z        0
    0                           0                            0                          1

    範例

    假設延x軸旋轉 (1,0,0)

    1   0             0             0
    0  cos(a)   sin(a)      0
    0  -sin(a)    cos(a)    0
    0  0             0              1


    矩陣組合


    1 如果一次要計算三個矩陣(平移矩陣,縮放矩陣,旋轉矩陣),太消耗資源

    2 利用矩陣乘法分配律,可以把三個矩陣先相乘,在跟向量相乘,可以少算2/3次

    3 同時三個矩陣組成一個,也方便處理

    4 組合方式是三個矩陣相乘



    2016年3月6日 星期日

    向量

    向量的意義

    向量是同時具有大小和方向的物理量

    勢能:在某方向上施加一定的作用力
    位移:在某方向上移動的一度距離
    速度:速率和方向

    用來表示方向

    遊戲中角色方向
    多邊形面對的方向
    光線的方向
    反射光的方向

    向量幾何意義

    兩個向量可以:
    確定一個三角形
    確定一個平行四邊形
    確定一個平面

    向量運算

    向量相加  對應的元素相加
    向量相減  對應的元素相減
    向量數乘  每個元素乘上一個數
    向量叉積  就是第三個同時垂直原向量的向量。不含自己,前減後,↘︎↙︎↘︎ 。|A||B|Sin(a)
    向量點積  對應元素相乘,加起來。變成一個數。|A||B|Cos(a)
    向量相等  方向相同,大小相等就是兩個相等向量


    向量計算

    向量計算一定是把向量頭部移到原點
    也就是假設向量從原點出發

    向量加法

    定義

    兩個同維度(2D和2D或3D和3D)的向量相加,
    就是兩個向量的對應分量相加。
    x+x
    y+y
    z+z

    u=(ux,uy,uz)
    v=(vx,vy,vz)
    u+v=(ux+vx,uy+vy,uz+vz)

    幾何意義

    A=(xa,yz)
    B=(xb,yb)
    C=(xc,yc)

    AB=(xb-xa,yb-ya)
    BC=(xc-xb,yc-yb)
    AC=(xc-xa,yc-ya)

    AB+BC=(xb-xa+xc-xb,yb-ya+yc-yb)=(xc-xa,yc-ya)=AC
    頭尾相連的兩個向量相加,結果從頭到尾的那個向量

    AC就是平行四邊形的對角線
    是兩向量行成的夾角內的對角線
    因此兩個向量相加可以確定一個平行四邊形

    AC也是兩向量頭尾相連的三角形的第三邊
    所以可以求第三邊的長度及方向

    平行四邊形面積= 底*高
    所以向量可以算出平行四邊形面積

    三角形面積=平行四邊形面積/2


    結論

    向量加法就是:兩項量移動成頭尾相連,所形成的第三邊。

    因為向量有相等性,可以平移,
    所以任何兩個向量,一定可以平移成頭尾相連。


    向量減法


    定義

    兩個同維度(2D和2D或3D和3D)的向量相減,
    就是兩個向量的對應分量相減。
    x-x
    y-y
    z-z

    u=(ux,uy,uz)
    v=(vx,vy,vz)
    u-v=(ux-vx,uy-vy,uz-vz)

    幾何意義

    AB=(xb-xa,yb-ya)
    AC=(xc-xa,yc-ya)
    BC=(xc-xb,yc-yb)


    AB-AC=(xb-xa-xc+xa,yb-ya-yc+ya)=(xb-xc,yb-yc)=CB

    CB是兩向量形成的平行四邊形的對角線(非兩向量形成的夾角內的對角線)
    所以也可確定一個平行四邊形

    CB是兩向量尾部相連形成的三角形的第三邊
    CB可以求第三邊的長度及方向

    結論

    向量減法就是:兩向量移動成起點相連形成的第三邊
    方向指向被減向量。(減號前方的是被減數)

    向量減法就是向量加法加上負向量,
    所以用向量加法來思考即可。


    向量叉積 

    向量叉積 Cross Product
    向量外積 Outer Product
    向量積Vector Product

    A,B兩向量叉積(A X B) 會得到一個垂直於這兩個向量的第三個向量
    B,A兩向量叉積(B X A) 會得到一個垂直於這兩個向量的第三個向量,但與A X B 方向相反

     B = - A ∧ B 
    各自算出的結果是兩個方向相反,大小相同向量
    就是反交換律

    寫作

    \vec{a}×\vec{b}(有時也被寫成\vec{a}\vec{b},避免和字母x混淆)

    公式

    A X B =|A||B|Sin𝛳
    θ表示\vec{a}\vec{b}之間的角度(0°≤θ≤180°),它位於這兩個矢量所定義的平面上
    \vec{n}是一個與\vec{a}\vec{b}所構成的平面垂直單位矢量
    https://zh.wikipedia.org/wiki/%E5%90%91%E9%87%8F%E7%A7%AF

    直接算法

    A=(ax,ay,az)
    B=(bx,by,bz)

    A x B=(ay*bz - az*by) =x          記憶法 ↘︎  不含自己    前減後
                (az*bx - ax*bz) =y                       ↙︎
                (ax*by - ay*bx) =z                      ↘︎

    幾何意義

    叉積可得到垂直於AB平面的法向量。


    向量點積

    向量點積 Dot Product
    向量內積 Inner Product
    標向量 Scalar Product

     兩向量計算點積會得到一個純量,不帶方向只有大小

    寫作

    \vec{a}\vec{b}

    公式

    A.B=|A||B|cos𝛳

    𝛳是AB間的最小夾角。即0<= 𝛳<=180
    兩個向量必須共起點
    當A,B都是單位向量時,A.B=1*1*cos𝛳=cos𝛳 , => -1<=cos𝛳<=1
    cos𝛳一定大於等於-1,小於等於1

    直接算法

    A=(ax,ay,az)
    B= (bx,by,bz)

    A.B =ax*bx+ay*by+az*bz  =>只有大小  記憶法:分量相乘,加起來

    AB都是單位向量,可推斷出角度

    就可直接得到cos𝛳的值
    若cos𝛳的值是已知的,那就可以知道角度是多少
    ABcos𝛳=0.95 ,𝛳=18
    因為cos(18)=0.95

    幾何意義

    無,但有一些性質

    利用cos𝛳可得到一些性質
    cos𝛳 0度=1
    cos𝛳 90度=0
    cos𝛳 180度=-1

    所以 A.B=0  =>cos𝛳=0  => 𝛳 =90度 => A,B垂直
    所以 A.B>0  =>cos𝛳>0  => 𝛳 <90度 =>A,B夾角小於90度
    所以 A.B<0  =>cos𝛳<0  => 𝛳 >90度 =>A,B夾角大於90度

    平面法線跟光的角度越小,光越強
    平面法線跟光的角度越大,光越弱
    正好符合cos,所以可以用cos(𝛳)來計算光的強弱
    光最後的顏色=光的顏色*cos(𝛳)


    向量大小(長度)

    向量長度符號
    ||U||=√a² +b²

    單位向量符號
    U戴帽子∧

    都是從勾股定理,商高定理(畢氏定理)來的
    Pythagorean theorem

    平面上的直角三角形的兩條直角邊的長度平方和等於斜邊長平方
    勾長 直邊
    股長 底邊
    弦長 斜邊

    來源:
    根據「周髀算經」記載,
    商高對周公說 將一根直尺折成一個直角,
    兩端連結成一個直角三角形,
    如果勾是 3,股是 4, 那麼弦就是 5。

    2D distance

    √(a²   + b²)
    根號(a²+b²)

    3D distance

    √(x²+y²+z²)
    根號(x²+y²+z²)

    空間中的兩個點距離
    A(ax,ay,az)
    B(bx,by,bz)
    √((ax-bx)²+(ay-by)²+(az-bz)²)
     根號((ax-bx)²+(ay-by)²+(az-bz)²)

    a 是利用兩次勾股定理算出

    b 或是利用向量平移,把其中一個點移到原點,
    然後另一個點扣掉平移量之後,跟原點計算距離

    其實就是向量減法的幾何意義

    單位向量驗證
    把長度/長度
    √(x²+y²+z²)/向量長=1/1=1

    C# Coroutine

    Unity Coroutine

    使用的地方

    必須在MonoBehaviour或繼承MonoBehaviour的class中使用

    不可使用的地方

    yield不可在Update
    不可在FixedUpdate中使用

    啟動Coroutine

    StartCoroutine(string methodName)
    StartCoroutine(IEnumeratorroutine)

    停止Coroutine

    StopCoroutine(string methodName)
    StopAllCoroutines()

    三角函數

    三角函數定義


    直角三角形邊的比例關係
    sin
    cos
    tan
    cot
    sec
    csc


              0°90°180°270°
    sinθ   0   1  0   -1
    cosθ  1   0   -1  0
    tanθ  0   x    0   x
    cotθ  x   0    x   0
    secθ 1   x    -1   x
    cscθ  x  1    x   -1

    http://ms1.hcvs.kh.edu.tw/hc3331/pbook/scr/work-1/page3.htm

    假設斜邊為1


    sinθ=對邊/斜邊 =對邊/1=對邊  =>sinθ就是對邊長
    cosθ=對邊/鄰邊=鄰邊/1=鄰邊  => cosθ就是鄰邊長


    正弦比例

    假設一三角形三個角A,B,C對應三邊a,b,c
    a邊的高為ha
    三角形面積=a*ha/2
    sinC=ha/b => ha=b*sinC

    三角形面積= a*b*sinC/2
    同理 a*b*SinC/2 =b*c*SinA/2 =a*c*SinB/2
    => abSinC=bsSinA = acSinB   (全部*2)
    =>  SinC/c=SinA/a=SinB/b       (全部除abc)
    =>  c/SinC=a/SinA =b/SinB     (反過來寫)

    結論  
    每個角的(sin值與對邊)的比相等
    a/sinA=b/SinB=c/SinC
    sinA/a=sinB/b=sinc/C




    直線與圓

    直線斜率

    斜率=y/x


    兩垂直的直線,斜率相成=-1

    圓方程式

    圓上形成直徑的兩點(x1,y1), (x2,y2)
    與圓上的任意一點(x,y),
    可得到圓方程式為:


    (x-x1)(x-x2)+(y-y1)(y-y2)=0

    證明:

    (x,y)與(x1,y1)線段
    (x,y)與(x2,y2)線段,
    兩者的斜率相成=-1。
    (圓周上的三角形對直徑的角是直角)


    (x,y),(x1,y1)斜率=(y-y1)/(x-x1)

    (x,y),(x2,y2)斜率=(y-y2)/(x-x2)

    ((y-y1)/(x-x1) ) * ((y-y2)/(x-x2))=-1
    =>(y-y1)*(y-y2)=-1*(x-x2)*(x-x1)
    =>(y-y1)(y-y2)+(x-x1)(x-x2)=0

    2016年3月4日 星期五

    C# delegete


    C# delegete

    就像是把函式包裝過然後傳給別的函式使用。
    有點像是變數的泛型,因為不確定使用時的什麼類型,所以訂一個通用的類型來用。

    Unity Delegate

    //delegate 定義
    //以下是一個參數為string, 回傳值為int的函式
      delegate int Action(string amount);
    

    //宣告成一個物件,以便使用
      Action action;
    

    //接受傳入delegate物件
    private void UseAction(int money,Action action)
    {
      int n=action(money);
    }
    
    //假設有三個同參數同回傳值的函式
    //一開始不知道要用哪一個
    //就可使用delegate
    private int TestA(int num) {}
    private int TestB(int num) {}
    private int TestC(int num) {}
    
    private void UseA()
    {
      //TestA指定給action,傳進UseAction
      //UseAction接受為派類型為參數
      //TestA必須是int為參數,回傳值為int的函式
      action=TestA;
      //action+=TestA;  也可以這樣用
      UseAction(3,action);
    }
    
    private void UseB()
    {
      //TestA指定給action,傳進UseAction
      action=TestB;
      //action+=TestB;  也可以這樣用
      UseAction(3,action);
    }
    
    private void UseC()
    {
      //TestA指定給action,傳進UseAction
      action=TestC;
     //action+=TestC;  也可以這樣用
      UseAction(3,action);
    }
    

    可以把A的函式委託給B

    或是把B的函式委託給A



    多重呼叫delegate

    delegate一次註冊多個方法,呼叫時所有註冊的都會一起呼叫
    using UnityEngine;
    using System.Collections;
    
    public class MulticastScript : MonoBehaviour 
    {
        delegate void MultiDelegate();
        MultiDelegate myMultiDelegate;
        
    
        void Start () 
        {
            myMultiDelegate += PowerUp;
            myMultiDelegate += TurnRed;
            
            if(myMultiDelegate != null)
            {
                myMultiDelegate();
            }
        }
        
        void PowerUp()
        {
            print ("Orb is powering up!");
        }
        
        void TurnRed()
        {
            renderer.material.color = Color.red;
        }
    }
    

    C# 泛型修飾詞

    C# in out 泛型修飾詞

    out 修飾詞

    MSDN
    out 關鍵字會指定型別參數為 Covariant
    可在泛型介面可使用
    可在委派中可使用
    // Covariant interface.
    interface ICovariant { }
    
    // Extending covariant interface.
    interface IExtCovariant : ICovariant { }
    
    // Implementing covariant interface.
    class Sample : ICovariant { }
    
    class Program
    {
        static void Test()
        {
           // ICovariant iobj = new Sample();
           // ICovariant istr = new Sample();
    
            // You can assign istr to iobj because
            // the ICovariant interface is covariant.
           // iobj = istr;
        }
    }
    

    in 修飾詞

    MSDN
    in 關鍵字會指定型別參數為 Covariant
    可在泛型介面可使用
    可在委派中可使用

    C# 方法參數修飾詞 out ref params

    C# in , out , ref , params


    params 修飾詞

    MSDN
    當傳入array時可用,此時參數的數目不定
    可傳入陣列
    可傳入元素
    可以什麼都不傳,此時陣列長度為0
    在params之後不許有其他參數(params要放在最後一個參數)
    且只能有一個params

    //當有這樣一個陣列
    Object[] ary = new object[3] { 300, 'x', "abc" };
    
    
    //這個方法的參數宣告為params
    private void TestFunc(params Object[] ary)
    
    //我們可以直接傳入一組物件
    TestFunc(200,'d',"xxx");

    完整範例
    public class MyClass
    {
        public static void UseParams(params int[] list)
        {
            for (int i = 0; i < list.Length; i++)
            {
                Console.Write(list[i] + " ");
            }
            Console.WriteLine();
        }
    
        public static void UseParams2(params object[] list)
        {
            for (int i = 0; i < list.Length; i++)
            {
                Console.Write(list[i] + " ");
            }
            Console.WriteLine();
        }
    
        static void Main()
        {
            // You can send a comma-separated list of arguments of the 
            // specified type.
            UseParams(1, 2, 3, 4);
            UseParams2(1, 'a', "test");
    
            // A params parameter accepts zero or more arguments.
            // The following calling statement displays only a blank line.
            UseParams2();
    
            // An array argument can be passed, as long as the array
            // type matches the parameter type of the method being called.
            int[] myIntArray = { 5, 6, 7, 8, 9 };
            UseParams(myIntArray);
    
            object[] myObjArray = { 2, 'b', "test", "again" };
            UseParams2(myObjArray);
    
            // The following call causes a compiler error because the object
            // array cannot be converted into an integer array.
            //UseParams(myObjArray);
    
            // The following call does not cause an error, but the entire 
            // integer array becomes the first element of the params array.
            UseParams2(myIntArray);
        }
    }
    /*
    Output:
        1 2 3 4
        1 a test
    
        5 6 7 8 9
        2 b test again
        System.Int32[]
    */
    

    ref 修飾詞

    MSDN
    把參數用傳參考的方式傳入函式
    在宣告和呼叫的參數前都加上ref
    參數在傳遞前一定要初始化
    被傳入的參數,在函式被修改,也會改到他原本的值
    屬性不能做為ref的參數

    這樣子不構成重載,會報錯
    public void SampleMethod(out int i) { }
    public void SampleMethod(ref int i) { }
    
    這樣子可以
    public void SampleMethod(int i) { }
    public void SampleMethod(ref int i) { }
    

    out 修飾詞

    MSDN
    把參數用傳參考的方式傳入函式
    參數在傳遞錢不一定要初始化
    在宣告和呼叫的參數前都加上out
    被傳入的參數,在函式被修改,也會改到他原本的值
    函式可宣告多個out參數
    在函式中一定要對out參數附值,否則報錯
    直接在函式中修改out參數,就等於是回傳值

    private void Test(out int a, out int b)
    {
         a =3;
         b=5;
    }
    private void Call()
    {
      int x=0;
      int y=4;
    }
    Test(out x, out y);
    

    參數原本的值會被更動
    class OutReturnExample
    {
        static void Method(out int i, out string s1, out string s2)
        {
            i = 44;
            s1 = "I've been returned";
            s2 = null;
        }
        static void Main()
        {
            int value;
            string str1, str2;
            Method(out value, out str1, out str2);
            // value is now 44
            // str1 is now "I've been returned"
            // str2 is (still) null;
        }
    }
    

    int 修飾詞

    傳入的參數不能被更動

    2016年1月20日 星期三

    使用nvm 做 node.js 版本管理教學

    像node.js這種版本更迭快速的引擎,
    為了要測試程式在不同版本的結果,
    常常要安裝很多個版本,
    於是就有了node version manager這類的工具。

    根據作者github,目前不支援homebrew installation,
    要用github 上的安裝指令來裝。

    這是目前的安裝指令:
    curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.30.1/install.sh | bash
    
    目前預設的安裝位置是/user/local/opt/nvm/
    安裝程式會自動把source加到profile裡(~/.bash_profile, ~/.zshrc or ~/.profile)。
    加入這行:
    source /usr/local/opt/nvm/nvm.sh
    你也可以指定要安裝的source,directory,profile,(github上的說明有寫)
    之後,就可安裝你需要的node版本:

    安裝5.0最新版本:
    $nvm install 5
    
    or
    $nvm install v5
    
    或指定明確版本:
    $nvm install v5.10
    
    版本編號可以用這些取代:
    node:安裝node最新版
    iojs:安裝io.js最新版

    安裝最新版本,並且搬移之前的npm版本:
    $nvm install node --reinstall-packages-from=node
    
    安裝指定版本,並且搬移之前npm的指定版本:
    $nvm install v5.0 --reinstall-packages-from=4.2
    
    shell中使用指定版本:
    $nvm use 5.0
    
    直接執行:
    $nvm run 5.0
    

    2016年1月14日 星期四

    來個標註吧 - Java annotation

    Annotation在java裡,是給編譯器看的,
    作用是告訴編譯器去做什麼,或是不做什麼。

    Annotation package:
    import java.lang.annotation.*;
    
    先來看看它的語法,通常長的像這樣:
    @annotation
    
    或是這樣:
    @annotation(value)
    @annotation(element=value)
    
    Annotation可指定element的值,或是直接傳入值。
    它可以針對java的任何元素,
    例如package、class、function、member...等進行標註。
    像是這樣子:
    class smaple{
        @Override
        public function overrideFunc(){
        }
    }
    
    那麼Annotation到底有什麼用,
    我們來看看內建的幾個annotation。

    @Override

    告訴編譯器這個方法要覆蓋父類的方法,
    例如上面的例子就是。
    使用Override可以確保程式一定會覆蓋,
    而不是變成重載。

    @SuppressWarnings

    這是告訴編譯器不要發出警告。
    下面這個程式碼,編譯器會發出falling through warning。
    switch("b"){
        case "a": break;
        case "b": //falling through
        case "c": break;
    }
    
    如果加上@SuperssWarnings annotation就不會發出警告。
    @SuppressWarnings
    private fallingThroughFunc(char x){
        switch(x){
            case "a": break;
            case "b": //falling through
            case "c": break;
        }
    }
    
    常用的參數有這些:
    all
    finally
    unchecked
    serial
    fallthrough
    path
    你可以在命令列下這個指令,查到全部的參數
    javac -X
    

    @Deprecated

    這個是純粹用來說明的,
    告知開發者這個元素不建議使用,
    請使用新的元素。
    @Deprecated
    public void deprecatedFunc(){
    }
    
    

    meta annotation

    meta annotation是註釋的註釋,
    annotation for annotation,好繞口啊。

    @Retention

    它告訴編譯器這個annotation的存在時期。
    下方的例子,是告訴編譯器Deprecated一直到runtime都存在,
    表示程式執行期同樣可以存取到。
    @Retention(value=RUNTIME)
    @Deprecated
    

    Retention的參數有這些:
    import java.lang.annotation.RetentionPolicy.RUNTIME;
    import java.lang.annotation.RetentionPolicy.SOURCE;
    import java.lang.annotation.RetentionPolicy.CLASS;

    @Inherited

    使用Inherited來註釋一個class,
    那麼它的子class也會繼承這個註釋。

    @Documented

    製作javadoc時,
    使用Documented註釋某個annotation,
    那麼這個被註釋的annotation會包含在javadoc中。

    @Target

    Target指明這個annotation可用在哪些元素。
    import java.lang.annotation.ElementType.*;
    
    @Target(ElementType.METHOD)
    public @interface TargetSample{}
    
    表示TargetSample只能用在mehtod。
    @Target可以有多個值,像是這樣。
    import java.lang.annotation.ElementType.*;
    
    @Target(value={ElementType.METHOD,ElementType.TYPE,ElementType.FIELD})
    public @interface TargetSample{}
    

    2016年1月11日 星期一

    軟體架構做什麼用?

    軟體架構在軟體工程上究竟能帶來什麼好處?
    一般來說,只要提到『架構』兩個字,
    地位好像就很崇高,給人一種無法親近的fu,
    軟體架構也是如此,
    所以我們常常會看到開發人員討論某個問題怎麼解?
    但是很少聽到大家研究架構怎麼做。

    舉凡要讓人接受一項新東西,
    不外是威脅或利誘兩種方式。
    專案開發一向講求「以和為貴」,
    我們當然不能用威脅的,
    而是要告訴大家服用後好處多多,
    保證一日雙北,或是30分鐘登上101。

    好的架構能讓開發更快速

    架構定了,開發人員有完成目標,有規範可遵守,
    有方式可合作,整體開發能夠更順利。
    且好架構是適應變化的,
    面對未來的改變,也能有一定的彈性。

    架構明確出團隊的共同目標

    有目標,方向才不會亂。
    團隊有共同的目標,才不會互相掣肘,
    從而發揮1+1>=2的效果。

    架構具體化團隊使用的技術

    團隊中的成員未必都熟悉系統所使用的技術,
    確定出技術後,成員可以提前練習,
    也方便互相研究。

    架構勾勒出每個人的責任

    多人共同開發要順暢有一個重點,
    就是每個人清楚知道自己的責任範圍。
    責任範圍一確認,就能避免重疊和遺漏的部分,
    團隊協力完成預先規劃的全部內容。

    2016年1月9日 星期六

    2016年1月7日 星期四

    Class serialization between smartfox and unity / smartfox 類別序列化教學

    Smartfox 要使用class serialization,有幾個項目要做。

    1 server/client雙邊都要有這個class,且package相同。
    2 java class要實作com.smartfoxserver.v2.protocol.serialization.SerializableSFSType。
    3 java class單獨編譯成jar,放到extensions\__lib__\。
    4 unity c# class要實作Sfs2X.Protocol.Serialization。
    5 unity c#要using Sfs2X.Protocol.Serialization
    及System.Reflection
    且呼叫 DefaultSFSDataSerializer.RunningAssembly = Assembly.GetExecutingAssembly();

    現在來看看它的用法。

    Server Side

    首先我們定義一個要序列化的類別,
    這個類別要實作SerializableSFSType。
    Class編譯成jar,放到extensions\__lib__\。

    package com.sample.model;
    
    import com.smartfoxserver.v2.protocol.serialization.SerializableSFSType;
    
    public class SampleClass implements SerializableSFSType {
    
        public String id="id_from_server";
        public int hitPoints=10;
        public int count = 10;
         
        public SampleClass()
        {
     
        }
    }
    

    把這個類別傳給client端的時候,使用class類型。

    SampleClass sc=new SampleClass();
    ISFSObject resObj=SFSObject.newInstance();
    resObj.putClass("sc", sc);
    send("cmd",resObj, user);
    

    Client Side

    Client也需要一個相同的class,
    client的class package需和java class相同。
    client class要實作Serialization。

    using Sfs2X.Protocol.Serialization;
    using com.smartfoxserver.v2.protocol.serialization.SerializableSFSType;
    namespace example{
        public class SampleClass : SerializableSFSType {
    
            public string id="cid";
            public int hitPoints=0;
            public int count = 0;
        }
    }
    

    Client接收server傳來的class時需要呼叫DefaultSFSDataSerializer,

    DefaultSFSDataSerializer.RunningAssembly = Assembly.GetExecutingAssembly();
    這行通常可放在new SmartfoxServer之後,
    要確保SFSDataSerializer可見到需要處理的class。

    using Sfs2X.Protocol.Serialization;
    using System.Reflection;
    DefaultSFSDataSerializer.RunningAssembly = Assembly.GetExecutingAssembly();
    //other code....
    private  void OnExtensionResponse (BaseEvent evt)
    {
        ISFSObject obj = (SFSObject)evt.Params ["params"];
        SampleClass sc=(SampleClass)obj.GetClass("sc");
        String id=sc.id;   //get field
    }
    

    2016年1月5日 星期二

    java的反射機制 Reflection API

    Reflection簡單的說,當你在寫code的時候,
    有時你並不知道要實體化哪一個class,
    而是在執行階段才決定實體化哪個class,
    這時候就可以使用Reflection API。

    使用反射實體化class

    方法一:
    取得class,然後實體化它。
    這時使用的是預設建構式。

    Class<?> clazz=Class.forName(className);
    Fo fo=(Fo)clazz.newInstance();
    

    方法二:
    如果class 沒有default constructor
    或是有數個constructor,
    而你想指定使用其中一個。

    import java.lang.reflect.Constructor;
    import java.lang.reflect.InvocationTargetException;
    
    Class<?> clazz=Class.forName(className);
    //使用參數型態為String的constructor
    Constructor<?> constructor=clazz.getConstructor(String.class);
    //實體化
    Object obj=constructor.newInstance("hi");


    操作class的Method
    import java.lang.reflect.Method;
    import java.lang.reflect.Modifier;
    import java.lang.reflect.Type;
    
    //取得class
    Class clazz=Class.forName("someClass");
    
    //取得method,並且指定參數類型
    Method method=clazz.getMethod("methodName",String.class,int.class);
    
    //取方法的修飾詞
    int modifier=method.getModifier();
    
    //取方法返回值
    Type type=method.getGenericReturnType();
    
    //取方法參數類型
    Class[] klasses=method.getparameterTypes();
    
    //取得method
    Method med=clazz.getMethod("getInstance",int.class);
    
    //呼叫static method,得到回傳值
    Object resObj=med.invoke(null);
    
    //取得method
    Method noStaticMethod=clazz.getMethod("noStaticMethod",int.class);
    
    //呼叫method,傳入呼叫這個方法的物件及參數,得到回傳值
    Object resObj=noStaticMethod.invoke(clazz.newInstance(),3);