Presentation is loading. Please wait.

Presentation is loading. Please wait.

2016 API for Game Development

Similar presentations


Presentation on theme: "2016 API for Game Development"— Presentation transcript:

1 2016 API for Game Development
Clean Code Functions Masaki Hayashi

2 Functions... int ABCFunction( int input, string params ) { ...........
return value; } Function is a very basic form of program. It could be method (member). It does something taking arguments and returns value. What we concern is: Function names Argument names How many arguments Length of main body Function itself (its scope) etc...

3 The bad example... public void Closeup( object target, E_CAMERA_TARGET targettype , float speed , E_PARSER_PARAMETER_TYPE speedType , bool dolly , bool track , E_CAMERA_TYPE type , E_CAMERA_TRANSITION transition , float adjx, float adjy, float adjz, float adjrx, float adjry, float adjrz, float adjvangle , float adjpan, float adjtilt, float adjzoom, bool skipscript) { float minx, miny, minz, maxx, maxy, maxz, d; minx=miny=minz=maxx=maxy=maxz=d=0.0f; float sx, sy, sz, tx, ty, tz, dist; float pp, tt; float distCloseupDolly; // dolly=trueのときのキャラとカメラの距離. float closeupAdjustY = 0.0f; // 顔の大きさに対するカメラ注視位置のyずれの比率(人の場合ちょ・ニしたをねら・トバストショットにするため). float closeupAdjustZoom = 0.0f; // 画面上で顔の大きさを少し小さくする。closeupAdjustZoomは画面い・マいに対する比率. Vector3 v0, v1, v2, v3, v4, v5; v0 = Vector3.zero; v1 = Vector3.zero; v2 = Vector3.zero; v3 = Vector3.zero; v4 = Vector3.zero; v5 = Vector3.zero; const float aspectRatio = 4.0f/3.0f; // 画面アスペクトが4:3(横:縦). cammove.closeup.target = target; cammove.closeup.targettype = targettype; cammove.closeup.speed = speed; cammove.closeup.speedType = speedType; cammove.closeup.dolly = dolly; cammove.closeup.track = track; cammove.closeup.type = type; cammove.closeup.adjx = adjx; cammove.closeup.adjy = adjy; cammove.closeup.adjz = adjz; cammove.closeup.adjrx = adjrx; cammove.closeup.adjry = adjry; cammove.closeup.adjrz = adjrz; cammove.closeup.adjvangle = adjvangle; cammove.closeup.adjpan = adjpan; cammove.closeup.adjtilt = adjtilt; cammove.closeup.adjzoom = adjzoom; initmove(E_PARSER_PARAMETER_IS.EPPI_SPECIFIED , E_PARSER_PARAMETER_IS.EPPI_SPECIFIED , speed , speedType); if(targettype == E_CAMERA_TARGET.ECT_CHARACTER) { distCloseupDolly=2.0f; closeupAdjustY = 0.27f; //0.27f closeupAdjustZoom = 1.65f;

4 The bad example... TCharacter actor = (TCharacter)target;
actor.getHeadAlignment2(ref v0, ref v1, ref v2, ref v3, ref v4, ref v5, ref d); } else if(targettype == E_CAMERA_TARGET.ECT_PROP) { distCloseupDolly=2.0f; closeupAdjustY = 0.0f; closeupAdjustZoom = 1.0f; TProp prop = (TProp)target; prop.getAlignment(ref minx, ref miny, ref minz, ref maxx, ref maxy, ref maxz, ref d); v0.x = minx; v0.y = miny; v0.z = minz; v1.x = minx; v1.y = maxy; v1.z = maxz; v2.x = maxx; v2.y = miny; v2.z = minz; v3.x = minx; v3.y = miny; v3.z = maxz; v4.x = maxx; v4.y = maxy; v4.z = minz; v5.x = maxx; v5.y = maxy; v5.z = maxz; }else{ return;} // 頭のバウンディングボックスの中点を求める. tx = (v0.x + v5.x) * 0.5f; ty = (v0.y + v5.y) * 0.5f; tz = (v0.z + v5.z) * 0.5f; cammove.closeup.tx = tx; cammove.closeup.ty = ty; cammove.closeup.tz = tz; if(dolly == true) // キャラの前方distCloseupDollyにカメラを持・トくる(2m). { sx = tx + distCloseupDolly*Mathf.Sin(( f/180.0f)*d); sy = ty; sz = tz + distCloseupDolly*Mathf.Cos(( f/180.0f)*d); else // 現在のカメラ位置のまま. sx = camdata.x; sy = camdata.y; sz = camdata.z; // カメラのパンとチルトを計算して、頭中心にカメラを向ける. dist = Mathf.Sqrt((sx-tx)*(sx-tx) + (sy-ty)*(sy-ty) + (sz-tz)*(sz-tz)); pp = -(180.0f/ f) * Mathf.Atan2((tx-sx), (sz-tz)); tt = (180.0f/ f) * Mathf.Asin((sy- ty)/dist); Matrix4x4 mtx = Matrix4x4.identity; Vector3 vt0, vt1, vt2, vt3, vt4, vt5; vt0 = new Vector3(); vt1 = new Vector3(); vt2 = new Vector3(); vt3 = new Vector3(); vt4 = new Vector3(); vt5 = new Vector3();

5 The bad example... TMath.setRotationMatrixX(ref mtx, tt); // (3)rx回転する(チルト) TVMLのカメラの回転方向はワールドに対してだとrxとrzは逆になるので、符合にマイナスが付かない. TMath.setRotationMatrixY(ref mtx, -pp); // (2)ry回転して(パン). TMath.setTranslationMatrix(ref mtx, -sx, -sy, -sz); // (1)ワールドを(sx,sy,sz)移動して. vt0.x = v0.x; vt0.y = v0.y; vt0.z = v0.z; // ワールドにおける頂点のベクトルをセットする(6つ分). vt1.x = v1.x; vt1.y = v1.y; vt1.z = v1.z; vt2.x = v2.x; vt2.y = v2.y; vt2.z = v2.z; vt3.x = v3.x; vt3.y = v3.y; vt3.z = v3.z; vt4.x = v4.x; vt4.y = v4.y; vt4.z = v4.z; vt5.x = v5.x; vt5.y = v5.y; vt5.z = v5.z; TMath.transformVect(mtx, ref vt0); // カメラ位置&姿勢におけるローカル・Wかもヘた6つの頂点ベクトルの値(・W)を計算する. TMath.transformVect(mtx, ref vt1); TMath.transformVect(mtx, ref vt2); TMath.transformVect(mtx, ref vt3); TMath.transformVect(mtx, ref vt4); TMath.transformVect(mtx, ref vt5); float[] xx = new float[8]; float[] yy = new float[8]; // 透視変換の計算。焦点距離1.0におけるxy平面の上の6つの頂点のxy・Wを求める. xx[0] = vt0.x / vt0.z; yy[0] = vt0.y / vt0.z; xx[1] = vt1.x / vt1.z; yy[1] = vt1.y / vt1.z; xx[2] = vt2.x / vt2.z; yy[2] = vt2.y / vt2.z; xx[3] = vt3.x / vt3.z; yy[3] = vt3.y / vt3.z; xx[4] = vt4.x / vt4.z; yy[4] = vt4.y / vt4.z; xx[5] = vt5.x / vt5.z; yy[5] = vt5.y / vt5.z; float xmax, xmin, ymax, ymin; xmax = ymax = -1E10f; // 小さな値. xmin = ymin = 1E10f; // でかい値. // xy平面における最大点と最小点を求める. for(int i=0 ; i<6 ; i++) { if(xx[i]>xmax) xmax=xx[i]; if(xx[i]<xmin) xmin=xx[i]; if(yy[i]>ymax) ymax=yy[i]; if(yy[i]<ymin) ymin=yy[i]; } // 画角を決めるため、中心から一番離れたxとyの値を求める. float dx, dy, dd; if (Mathf.Abs(xmin) > Mathf.Abs(xmax)) dx = Mathf.Abs(xmin); else dx = Mathf.Abs(xmax); if (Mathf.Abs(ymin) > Mathf.Abs(ymax)) dy = Mathf.Abs(ymin); else dy = Mathf.Abs(ymax); // 顔が横幅が大きいor縦長か、で、どちらの値から画角を計算するかを、決定する. if (dy*aspectRatio > dx) dd = dy; else dd = dx/aspectRatio; // 画面上で顔の大きさを少し小さくする。closeupAdjustZoomは画面い・マいに対する比率。すなわちズームを少し引き気味にする. dd *= closeupAdjustZoom; float ff; // 焦点距離1.0における原点とy方向の距離から垂直画角を計算する. ff = (180.0f / f) * Mathf.Atan2(1.0f,dd) * 2.0f; // ちょ・ニ下を狙・トバストショットにする。closeupAdjustYは顔の大きさに対するカメラ中止位置のyずれの比率. float uuu = (180.0f/ f) * Mathf.Atan2(dd*closeupAdjustY, 1.0f); cammove.closeup.uuu = uuu; // Track=onに使うためにここで保存しておく.

6 The bad example... About 240 lines ..... (´Д`).
cammove.closeup.rx = tt + uuu; cammove.closeup.ry = pp; cammove.closeup.rz = 0.0f; cammove.closeup.x = sx; cammove.closeup.y = sy; cammove.closeup.z = sz; cammove.closeup.vangle = ff; // Track=onのときのために保存. cammove.closeup.prerx = cammove.closeup.rx; cammove.closeup.prery = cammove.closeup.ry; cammove.closeup.prerz = cammove.closeup.rz; cammove.closeup.x += adjx; cammove.closeup.y += adjy; cammove.closeup.z += adjz; cammove.closeup.rx += adjrx; cammove.closeup.ry += adjry; cammove.closeup.rz += adjrz; cammove.closeup.vangle += adjvangle; destf = cammove.closeup.vangle = f * Mathf.Atan2( 1.0f, (Mathf.Tan( f * cammove.closeup.vangle) * adjzoom) );// f = / PI * 2.0です。後の数字はその逆. cammove.closeup.rx += (cammove.closeup.vangle * adjtilt); destfh = f * Mathf.Atan2(aspectRatio * Mathf.Tan( f * cammove.closeup.vangle), 1.0f); // 垂直画角を水平画角に変換. cammove.closeup.ry -= (destfh * adjpan); cammove.closeup.ry += 180.0f; //calccameraに記述されていた内容をこちらに移植 if(skipscript == false) { cammove.closeup.trigger = true; cammove.closeup.status = true; cammove.move.type = type; cammove.move.speed = speed; cammove.closeup.transition = transition; } else { camdata.x = cammove.closeup.x; camdata.y = cammove.closeup.y; camdata.z = cammove.closeup.z; camdata.rx = cammove.closeup.rx; camdata.ry = cammove.closeup.ry; camdata.rz = cammove.closeup.rz; camdata.vangle = cammove.closeup.vangle; cammove.closeup.status = false; About 240 lines (´Д`).

7 Make it small! They should be smaller than small...
How short should it be? It could be more than 1000 lines! In the past, it corresponds to the screen size (24 lines) It could be 2 to 5 lines. Number of function would increase, though.

8 Make it small! Break down into smaller pieces
void ABCFunction( int input ) { // do A // do B // do C } calculateA( input ); calcultaeB ( input ); calculateC ( input ); void calculateA( int input ) { void calculateB( int input ) { void calculateC( int input ) { Break down into smaller pieces

9 Blocks and indenting It should not large enough to hold nested structures. The indent level should be less than 1 or 2. if(camera.isPerspective) { // do something if(status) { if(flag == OMITTED) { } 3 1 2 should be avoided. no more than 3...

10 Do one thing Functions should do one thing They should do it well
There's an old saying... Functions should do one thing They should do it well They should do it only. Don't make a function do different type of jobs. If you cannot extract a new function from the function that's the final.

11 A function doing multiple jobs
void WriteOutHtmlContentsToTextFromGivenUrl ( string url ) { WWW www = new WWW (url); while (! ; string html = Match m1 = Regex.Match(html, "<title>(.*?)</title>"); Match m2 = Regex.Match(html, "<img\\s*src\\s*=\\s*\"(.*?)\"\\s*.*?>"); string title = m1.Groups[1].Value; string imageUrl = m2.Groups[1].Value; string buff = "title: " + title + "\n"; buff += "image: " + imageUrl + "\n"; string fileName = "output.txt"; System.IO.File.WriteAllText(fileName, buff); }

12 One level of abstraction per function
Don't mix different abstraction level of lower and higher. If so, separate it to let one function take one abstraction level. void addCharacter(string modelName) { Character actor = getCharacter(modelName); string buff = "actor = " + actor.name + "\n"; appendDB(buff); } void addCharacter(string modelName) { Character actor = getCharacter(modelName); addActorToDB(actor); void addActorToDB(Character actor) { string buff = "actor = " + actor.name + "\n"; appendDB(buff);

13 Reading code from top to bottom
Let the code be read like a top-down narrative. Code Abstraction level TO - paragraphs public aaa (xxxx) { } public bbb(xxxx) { public ccc (xxxx) { public ddd (xxxx) { public eee (xxxx) { public fff (xxxx) { public ggg (xxxx) { public hhh (xxxx) { High To do aaa, we do bbb, then we do ccc. To do bbb, we do ddd. To do ccc, we do eee. To do ddd,...... Low

14 Switch statements "Switch" statements always do N things.
So, it may violate some basic rules regarding function: e.g. - It may induce multiple switch at multiple functions. - It may break Single Responsibility Principle One solution: Bury the switch statement in a low-level class and use polymorphism.

15 Single Responsibility Principle (SRP)
A class should have one responsibility. A class should have only one reason to change. A good abstraction has a good name.

16 Use descriptive names Take time to choose a good name for a function.
Good name is for a good function that does one thing. e.g. chk() < checkChar() < checkCharacterType() Don't hesitate to make a long name. Make a descriptive name to work mostly like a comment. Don't hesitate to change it in the middle of the way. Be consistent

17 Function arguments Number of argument should be small.
0 (niladic) > 1 (monadic) > 2 (dyadic) > 3 (triadic) should be avoided - Much arguments may reduce readability of the function. - It increases the difficulty when testing the function with much arguments.

18 Output arguments Output arguments (out, ref) may be troublesome.
int ABCFunction ( float a, float b, out float ans1, out float ans2 ); - It may reduce readability. - It may make a test troublesome. - If it's only one, use return value. - If you need two or more, try think to use member variables.

19 Avoid flag arguments Passing a boolean is a terrible practice.
It proclaims that this function does more than one thing. e.g. void render(bool is3D) You should split the function. e.g. void render3D() void render2D() void render(int flag) <--- worse...

20 Have no side effects Your function promises to do one thing, but it also does other hidden things. It should be avoided. e.g. public bool isCamera(string name) { Camera camera = getCameraByName(name); if(camera != null) { Camera.initialize(); return true; } return false; It may cause a temporal coupling (terrible).

21 Don't repeat yourself Be aware of duplication in a code.
public void appendCameraToLOG(string name) { Camera camera = getCameraByName(name); if(camera != null) { if(camera.type == "fps") { buffer = "#CAMERA INFO#\n" buffer += "camera name: " + camera.name + "\n"; buffer += " type: FPS\n"; } else if(camera.type == "fixed") { buffer += " type: FIXED\n"; else { buffer += " type: UNKNOWN\n"; writedown(buffer);

22 Don't repeat yourself Be aware of duplication in a code.
public void appendCameraToLOG(string name) { Camera camera = getCameraByName(name); if(camera != null) { buffer = "#CAMERA INFO#\n" buffer += "camera name: " + camera.name + "\n"; buffer += " type:"; if(camera.type == "fps") buffer += " FPS\n"; else if(camera.type == "fixed") buffer += " FIXED\n"; else buffer += " UNKNOWN\n"; writedown(buffer); }

23 Final words Making software is like writing a paper or an article.
System is a story to be told, rather than a program to be written. Make a draft first Massage it, restructure it, refine it It ended up with functions that follows the rules. No need to be perfect code from the first time.


Download ppt "2016 API for Game Development"

Similar presentations


Ads by Google