Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

【Unity道場スペシャル 2018京都】プロなら当然!プログラミング技能解説

5,269 views

Published on

2018/11/24に開催されたUnity道場 京都スペシャル3の講演スライドです。
講師: 安原 祐二(ユニティ・テクノロジーズ・ジャパン合同会社)

Unityのイベント資料はこちらから:
https://www.slideshare.net/UnityTechnologiesJapan/clipboards

Published in: Technology
  • Be the first to comment

【Unity道場スペシャル 2018京都】プロなら当然!プログラミング技能解説

  1. 1. プロなら当然! プログラミング技能解説 ユニティ・テクノロジーズ・ジャパン 安原 祐二
  2. 2. 長い歴史 C# C++ C オブジェクト指向 構造化 Java Rust Perl 関数型 Haskell 迷って当然
  3. 3. 1. プログラム言語 2. 参照と実体 3. プッシュとプル 4. 再帰
  4. 4. Part 1 プログラム言語
  5. 5. 美しい王国の姫 ハッキリ しなさいよ 美しいのは王国?姫? 自然言語
  6. 6. 曖昧さがない int a = 1 + 2 * 3; 2*3が先に計算される int a = (1 + 2) * 3; 1+2が先に計算される 自然言語 プログラム言語 美しい王国の姫 ハッキリ しなさいよ 美しいのは王国?姫?
  7. 7. 自然言語 •話す •聞く •書く •読む •聞く •話す •読む •書く
  8. 8. •聞く •話す •読む •書く •話す •聞く •書く •読む 自然言語 プログラム言語 •話す •聞く •書く •読む •聞く •話す •読む •書く
  9. 9. コンピューターはこれが読めるの?? 読んで理解する仕組みがある!
  10. 10. 2.構文解析 1.字句解析
  11. 11. 1.字句解析 public class A { int c = 0; • スペースは単語の区切り • 改行も単語の区切り • ; は式の区切り • {} は始まりと終わり public class A { int c = 0; 単語や記号の区切りを検出
  12. 12. public class Test : MonoBehaviour { void Start(){} void Update(){} } public class Test : MonoBehaviour { void Start() { } void Update() { } } 一行にまとめても同じ 字句解析を 理解すれば
  13. 13. この字下げ(indent)は必要なの? if (a == 10) { a = 0; } 必要ない! 字句解析に必要なのか 人間が見やすいためなのか 区別しよう
  14. 14. 2.構文解析 public class A int c = 0 public class A { int c = 0; 意味の構成を検出
  15. 15. void Start() { int a = 10; } 構文解析を 理解すれば void Start() { int a = ((((10)))); } ()をたくさん書いても問題なし
  16. 16. #define/*__Int3rn^ti[]n/l_()I3fusc^t3|]_C_C<>I7E_C[]nt3st__*/L/*__MMXVIII__*/for #include/*!"'()*+,-./12357:;<=>?CEFGHIJKLMNSTUVWXYZ[]^_`cfhijklmnrstuvwxyz{|}*/<stdio.h> char*r,F[1<<21]="~T/}3(|+G{>/zUhy;Jx+5wG<v>>u55t.?sIZrC]n.;m+:l+Hk]WjNJi/Sh+2f1>c2H`)(_2(^L -]=([1/Z<2Y7/X12W:.VFFU1,T77S+;N?;M/>L..K1+JCCI<<H:(G*5F--E11C=5?.(>+(=3)Z-;*(:*.Y/5(-=)2*-U, /+-?5'(,+++***''EE>T,215IEUF:N`2`:?GK;+^`+?>)5?>U>_)5GxG).2K.2};}_235(]:5,S7E1(vTSS,-SSTvU(<-HG -2E2/2L2/EE->E:?EE,2XMMMM1Hy`)5rHK;+.T+?[n2/_2{LKN2/_|cK2+.2`;}:?{KL57?|cK:2{NrHKtMMMK2nrH;rH[n" "CkM_E21-E,-1->E(_:mSE/LhLE/mm:2Ul;2M>,2KW-+.-u).5Lm?fM`2`2nZXjj?[n<YcK?2}yC}H[^7N7LX^7N7UN</:- ZWXI<^I2K?>T+?KH~-?f<;G_x2;;2XT7LXIuuVF2X(G(GVV-:-:KjJ]HKLyN7UjJ3.WXjNI2KN<l|cKt2~[IsHfI2w{[<VV" "GIfZG>x#&#&&$#$;ZXIc###$&$$#>7[LMv{&&&&#&##L,l2TY.&$#$#&&$,(iiii,#&&&#$#$?TY2.$#$1(x###;2EE[t, SSEz.SW-k,T&&jC?E-.$## &#&57+$$# &&&W1-&$$7W -J$#$kEN&#& $##C^+$##W,h###n/+L2YE" "2nJk/H;YNs#$[,:TU(#$ ,: &&~H>&# Y; &&G_x ,mT&$YE-#& 5G $#VVF$#&zNs$$&Ej]HELy CN/U^Jk71<(#&:G7E+^&# l|?1 $$Y.2$$ 7lzs WzZw>&$E -<V-wE(2$$ G>x; 2zsW/$$#HKt&$$v>+t1(>" "7>S7S,;TT,&$;S7S>7&#>E_::U $$'",op ,*G= F,*I=957+F ;int*t,k,O, i, j,T[+060<<+020];int M( int m,int nop){;;;return+ m%(0+nop );;} int*tOo,w, h,z,W;void(C) (int n){n=putchar(n);}int f,c,H=11,Y=64<<2,Z,pq,X ;void(E/*d */)( int/*RP*/n ){L(Z=k+00; Z; Z/=+2+000)G[000]=*G*!!f |M(n,2)<<f,pq=2,f=+06 <f?++pq,++pq ,G++ ,z:f+001,n /=2;;}void (V)( int/*opqrstabd*/n){C(n %Y);;C(n/Y+00);;}void J(){L(pq--,pq =j =O=-1+0;++ j<240;I[6+ (h +6+j/12/2*2+M(j/2,2))* W+M(j/2/2,+06)*2+w*014 +00+M(00+ 000+j,002 +00)]=000 +00+k)k=M(G[j/2/2+(*r-+ 32)**"<nopqabdeg"],/*4649&96#*/3);/*&oaogoqo*/;}/*xD%P$Q#Rq*/int/*dbqpdbqpxyzzyboo3570OQ*/main() {L(X=Y-1;i<21*3;i++,I++)L(r=G,G+=2;*G++;)*G>=13*3?*G-*r?*I++=*G:(*I++=r[1],*I++=r[2]):1;L(j=12,r =I;(*I=i=getchar())>-1;I++)i-7-3?I-=i<32||127<=i,j+=12:(H+=17+3,W=W<j?j:W,j=12);L(;*r>-1;r++)*r- 7-3?J(),w++:(w=z,h+=17+3);C(71);C(73);V('*'*'1'*7);C(57);C(32*3+1);V(W);V(H);C(122*2);L(V(i=z);i <32*3;)C(i++/3*X/31);C(33);C(X);C(11);L(G="SJYXHFUJ735";*G;)C(*G++-5);C(3);V(1);L(V(j=z);j<21*3; j++){k=257;V(63777);V(k<<2);V(M(j,32)?11:511);V(z);C(22*2);V(i=f=z);V(z);V(W);V(H);V(1<<11);r= G=I+W*H;L(t=T;i<1<<21;i++)T[i]=i<Y?i:-1;E(Y);L(i=-1;++i<W*H;t=T+Z*Y+Y)c=I[i]?I[i]*31-31:(31< j?j-31:31-j),Z=c[t[c]<z?E(Z),k<(1<<12)-2?t[c]=++k,T:T:t];E(Z);E(257);L(G++;k=G-r>X?X:G-r ,C(k),k;)L(;k--;C(*r++/*---#$%&04689@ABDOPQRabdegopq---*/));}C(53+6);return(z);} https://www.ioccc.org/2018/endoh1/prog.c 参考:IOCCC(国際難読化Cコードコンテスト)
  17. 17. この()はなんなの?なくてもいいの? void Start() { 例題:
  18. 18. 必要。この()は「関数であること」を 構文解析器に伝える この()はなんなの?なくてもいいの? void Start() { 例題:
  19. 19. このvoidはなんなの? void Start() {
  20. 20. 数学の関数を思い出そう f(x) = x2 − 1 y = f(x) このvoidはなんなの? void Start() { そのまえに・・・
  21. 21. int f(int x) { return x*x - 1; } f 2 − 1xx( ) = 関数の定義 関数の評価 (呼び出し) f 10( )=y y = f(10); 数学 プログラム
  22. 22. int f(int x) { return x*x - 1; } 関数は必ず結果を返す f 2 − 1xx( ) = 関数の定義 関数の評価 (呼び出し) f 10( )=y y = f(10); 数学 プログラム
  23. 23. そもそも関数は 函数 つまり 入れたら取り出す函(はこ)のこと
  24. 24. int f(int x) { return x*x - 1; } 関数は引数と返り値がある f 2 − 1xx( ) = 関数の定義 関数の評価 (呼び出し) f 10( )=y y = f(10); 数学 プログラム返り値が 整数 引数が 整数
  25. 25. ??? f(int x) { 処理 return; } プログラムでは、値を返さないこともある 値を返さない!
  26. 26. ??? f(int x) { 処理 return; } プログラムでは、値を返さないこともある 構文解析しやすいように ??? はvoid と書くことにしよう 値を返さない! ・・・ということでした
  27. 27. まとめ&今後の指針 • プログラムを解釈する機構を意識しよう • 記述には自由があることを知ろう • 自分が書いたコードをもういちど読んでみよう • いろんな言語の入門書を読んでみよう
  28. 28. Part 2 参照と実体
  29. 29. 参照 実体 •預金通帳 •URL(リンク) •クレジットカード •現金 •web魚拓 •切符
  30. 30. 広大なメモリ空間
  31. 31. 広大なメモリ空間
  32. 32. 2018 11 24
  33. 33. アドレス 2018 11 24 2148685152 2148685160 2148685168 中身 アドレスがあれば 中身にアクセスできる
  34. 34. 2018 11 24 2148685152 2148685152 2148685160 2148685168 2148685176 中身にアドレスも入れられる ちなみに・・・ アドレス 中身
  35. 35. class Date { long year; long month; long day; } 2148685152 2148685160 2148685168 2148685176 2148685184 2148685192 2148685200 2148685208 2148685144 2148685136 2148685128 この時点では何も起きない
  36. 36. 2018 11 24 Date d = new Date(); 2148685152 2148685160 2148685168 2148685176 2148685184 2148685192 2148685200 2148685208 2148685144 2148685136 2148685128class Date { long year; long month; long day; } メモリが確保される
  37. 37. 2018 11 24 2148685152 2148685160 2148685168 2148685176 2148685184 2148685192 2148685200 2148685208 2148685144 2148685136 2148685128class Date { long year; long month; long day; } Date d = new Date(); dにはアドレスが入る d
  38. 38. 2018 11 24 2148685152 2148685160 2148685168 2148685176 2148685184 2148685192 2148685200 2148685208 2148685144 2148685136 2148685128class Date { long year; long month; long day; } Date d = new Date(); Date d2 = d; d2 代入するとアドレスが 複製される d
  39. 39. 2018 11 2148685152 2148685160 2148685168 2148685176 2148685184 2148685192 2148685200 2148685208 2148685144 2148685136 2148685128class Date { long year; long month; long day; } Date d = new Date(); Date d2 = d; d2.day = 25; とするとdにも影響する 25 なので d2d
  40. 40. struct Date { long year; long month; long day; } 2148685152 2148685160 2148685168 2148685176 2148685184 2148685192 2148685200 2148685208 2148685144 2148685136 2148685128 classを structに変える
  41. 41. 2018 11 24 2148685152 2148685160 2148685168 2148685176 2148685184 2148685192 2148685200 2148685208 2148685144 2148685136 2148685128struct Date { long year; long month; long day; } 中身がまるごと入る Date d = new Date(); d d
  42. 42. 2018 11 24 2018 11 2148685152 2148685160 2148685168 2148685176 2148685184 2148685192 2148685200 2148685208 2148685144 2148685136 2148685128struct Date { long year; long month; long day; } 24 Date d = new Date(); Date d2 = d; d d2 代入すると内容が 複製される
  43. 43. 2018 11 24 2018 11 2148685152 2148685160 2148685168 2148685176 2148685184 2148685192 2148685200 2148685208 2148685144 2148685136 2148685128struct Date { long year; long month; long day; } d2.day = 25; としてもdに影響しない 25 Date d = new Date(); Date d2 = d; d d2 なので
  44. 44. 参照 実体 •勝手に中身が変わる •軽い(IDだけ) •複数から中身を閲覧できる •中身は固定 •重い(まるごと扱う) •中身を知るのは自分のみ
  45. 45. int a = b + c; int d = a * 2; 一時変数を使う記述 int d = (b+c) * 2; 一時変数を使わない記述
  46. 46. Rigidbody rb = GetComponent<Rigidbody>(); rb.AddForce(f); 一時変数を使う記述 一時変数を使わない記述 GetComponent<Rigidbody>().AddForce(f);
  47. 47. transform.position.x = 10; エラーが出ます。なぜでしょう?
  48. 48. transform.position.x = 10; エラーが出ます。なぜでしょう? transform.position 実体を返す 複製
  49. 49. transform.position.x = 10; エラーが出ます。なぜでしょう? transform.position 実体を返す 複製.x = 10; 複製のxを更新している
  50. 50. transform.position.x = 10; エラーが出ます。なぜでしょう? transform.position 実体を返す には変化なし!transform.position元の 意味のない操作なのでエラーにしてくれる親切 複製は破棄 複製.x = 10; 複製のxを更新している
  51. 51. Vector3 pos = transform.position; pos.x = 10; transform.position = pos; 正しい書き方 transform.position は 実体返しだから 複製のposを代入する 複製にposという名前を与える
  52. 52. void func(int x) { x = 10; } 引数の値を変更したら? Debug.Logに渡されるのは 5? 10? int x = 5; func(x); Debug.Log(x);
  53. 53. void func(int x) { x = 10; } 引数の値を変更したら? Debug.Logに渡されるのは 5? 10? int x = 5; func(x); Debug.Log(x); この関数は 無意味 実体を 更新している
  54. 54. void func(int[] x) { x[0] = 10; } 引数の値を変更したら? Debug.Logに渡されるのは 5? 10? int[] x = {5}; func(x); Debug.Log(x[0]);
  55. 55. void func(int[] x) { x[0] = 10; } 引数の値を変更したら? Debug.Logに渡されるのは 5? 10? int[] x = {5}; func(x); Debug.Log(x[0]); 参照を 更新している この関数は 狙い通り
  56. 56. List<Quaternion> rots = new List<Quaternion>(); rots[0]. SetLookRotation(Vector3.up); エラーすら出てくれない例 rots[0]に変化なし!(実体返しなので) Quaternion[] rots = new Quaternion[10]; rots[0]. SetLookRotation(Vector3.up); 期待通りに動作
  57. 57. • 言語を学ぶ際は、まず参照と実体の書き分けを確認しよう • C#の「値型(Value Type)」「参照型(Reference Type)」で調べてみよう • https://msdn.microsoft.com/ja-jp/library/cc406735.aspx • ref キーワードについて調べてみよう まとめ&今後の指針
  58. 58. Part 3 プッシュとプル ※確立したプログラミング用語ではなく、説明のための言葉です
  59. 59. 早く出なさいよ プッシュ型 主導権は送信側
  60. 60. プル型 来てるかな 主導権は受信側
  61. 61. void OnCollisionEnter(Collision c) { … } プッシュ型の例 誰かがこの関数を呼んでいる 関連用語:コールバック
  62. 62. if (Input.GetMouseButton(0)) { … } プル型の例 自分で関数を呼ぶ 関連用語:ポーリング
  63. 63. プルとプッシュは 受け手の自由 重大な事実
  64. 64. ただいま電話に 出られません。 発信音のあとに… プッシュ型を プル型に変換 ! 送信側に変更なし 留守電は あとでチェックしよう 受信側で工夫
  65. 65. プル型を プッシュ型に変換 受信したら 電話をかける装置 送信側に変更なし 受信側で工夫
  66. 66. void OnCollisionEnter(Collision c) { hit = true; } プッシュ型を プル型に変換 void Update() { if (hit) { … } } 留守電は あとでチェックしよう
  67. 67. プル型を プッシュ型に変換 少々ややこしい
  68. 68. 関数もメモリに置かれる void f() { 処理 return; } 2148685152 2148685160 2148685168 2148685176 2148685184 2148685192 2148685200 2148685208 2148685144 2148685136 2148685128 void f() { 処理 return; }
  69. 69. 関数のアドレスを実行 2148685152 2148685160 2148685168 2148685176 2148685184 2148685192 2148685200 2148685208 2148685144 2148685136 2148685128 void f() { 処理 return; } f(); 2148685152 を実行
  70. 70. 誰かに関数を実行してもらいたい 2148685152 2148685160 2148685168 2148685176 2148685184 2148685192 2148685200 2148685208 2148685144 2148685136 2148685128 void f() { 処理 return; }
  71. 71. 誰かに関数を実行してもらいたい 2148685152 2148685152 2148685160 2148685168 2148685176 2148685184 2148685192 2148685200 2148685208 2148685144 2148685136 2148685128 void f() { 処理 return; } 変数に関数を入れられればいい
  72. 72. 誰かに関数を実行してもらいたい 2148685152 2148685152 2148685160 2148685168 2148685176 2148685184 2148685192 2148685200 2148685208 2148685144 2148685136 2148685128 void f() { 処理 return; } ここにある関数を実行するよ C#ではdelegateを使う 変数に関数を入れられればいい
  73. 73. void f() { … } 関数fを変数に入れたい
  74. 74. void f() { … } 関数fを変数に入れたい delegate void MyFunc(); 関数fと同じ返り値と引数で delegate宣言 この段階では何も起きない
  75. 75. delegate void MyFunc(); void Update() { MyFunc h = f; void f() { … } 関数fを変数に入れたい 関数fと同じ返り値と引数で delegate宣言 MyFuncで定義した 変数hにfを代入
  76. 76. delegate void MyFunc(); void Update() { MyFunc h = f; h(); } void f() { … } 関数fを変数に入れたい 関数fと同じ返り値と引数で delegate宣言 MyFuncで定義した 変数hにfを代入 変数hを実行
  77. 77. static void OnMouseButton0() { … } void Start() { set(OnMouseButton0); } delegate void MyFunc(); static MyFunc cb; static void set(MyFunc f) { cb = f; } void Update() { if (Input.GetMouseButton(0)) { cb(); } } プル型を プッシュ型に変換 装置 呼んで欲しい関数 呼んで欲しい関数をセット
  78. 78. switch (n) { case 0: func0(); break; case 1: func1(); break; case 2: func2(); break; case 3: func3(); break; case 4: func4(); break; case 5: func5(); break; case 6: func6(); break; case 7: func7(); break; } func[n](); delegateを使うと・・・
  79. 79. • 身の回りの通信がプッシュ型かプル型か意識しよう • delegateを使いこなそう • コールバック・ポーリングについて調べよう まとめ&今後の指針
  80. 80. Part 4 再帰
  81. 81. 関数の中でその関数を 呼んだらどうなる? void f() { … f(); }
  82. 82. 関数の中でその関数を 呼んだらどうなる? void f() { … f(); } 無限ループ!
  83. 83. 引数を減らしながら呼ぶ void f(int n) { f(n-1); } nは減っていく でも無限ループ!
  84. 84. 返り値を用意する int f(int n) { return f(n-1); } まだ無限ループ!
  85. 85. 返り値を用意する int f(int n) { return f(n-1); } f(n) = f( −1)n 記述は正しいが数学的には意味をなさない 漸化式 まだ無限ループ!
  86. 86. 漸化式には必ず条件がある プログラムも同様に条件を与える f(n) = f( −1)n f(n) = 0 ≤ 0n のとき > 0n のとき
  87. 87. プログラム int f(int n) { if (n <= 0) return 0; else return f(n-1); }f(n) = f( −1)n f(n) = 0 ≤ 0n のとき > 0n のとき 数式
  88. 88. 応用例 f(4); で4+3+2+1を得る int f(int n) { if (n <= 0) return 0; else return f(n-1)+n; }f(n) = −1)+n f(n) = 0 ≤ 0n のとき > 0n のとき f( n
  89. 89. 親子構造のデータ © UTJ/UCL
  90. 90. 動画
  91. 91. [MenuItem("GameObject/DumpName", false, 0)] static void DumpName() { var obj = Selection.activeGameObject; string str = createString(obj.transform); Debug.Log(str); } static string createString(Transform tfm) { string name = ""; name += tfm.name + "n"; foreach(Transform child in tfm) { name += createString(child); } return name; }
  92. 92. [MenuItem("GameObject/DumpName(Indent)", false, 0)] static void DumpNameIndent() { var obj = Selection.activeGameObject; string str = createString(obj.transform, 0); Debug.Log(str); } static string createString(Transform tfm, int indent) { string name = ""; for (int i = 0; i < indent; ++i) name += " "; name += tfm.name + "n"; foreach(Transform child in tfm) { name += createString(child, indent+4); } return name; }
  93. 93. • 親子構造のデータを扱う • パズルの解を出すとき • 対戦ボードゲームのAIを作るとき 再帰が役に立つシーン
  94. 94. var g = new GameObject(); g.AddComponent<MyScript>(); AddComponentすると class MyScript: MonoBehaviour { void Start() { } } Startが呼ばれる これを利用して再帰プログラムを書いてみよう Start で AddComponent すると・・・?
  95. 95. using System.Collections; using System.Collections.Generic; using UnityEngine; public class Fractal : MonoBehaviour { [SerializeField] Mesh mesh_; [SerializeField] Material material_; const int MAX_DEPTH = 7; Vector3 start_ = Vector3.zero; Vector3 end_ = Vector3.up; float width_ = 0.1f; int depth_ = 0; void initialize(Fractal parent, float given_length, float given_width, Quaternion given_rotation, int depth) { mesh_ = parent.mesh_; material_ = parent.material_; transform.position = parent.transform.position + Vector3.up; start_ = parent.end_; end_ = start_ + given_rotation * (Vector3.up * given_length); width_ = given_width; depth_ = depth; }
    IEnumerator Start() { gameObject.AddComponent<MeshFilter>().mesh = mesh_; gameObject.AddComponent<MeshRenderer>().material = material_; transform.position = (start_ + end_) * 0.5f; var diff = end_ - start_; var length = diff.magnitude; transform.rotation = Quaternion.LookRotation(diff) * Quaternion.Euler(90f, 0f, 0f); transform.localScale = new Vector3(width_, length * 1f, width_); if (depth_ >= MAX_DEPTH) yield break; float roty = Random.Range(0f, 360f); for (var i = 0; i < 5; ++i) { if (Random.Range(0, 2) != 0) continue; yield return new WaitForSeconds(0.1f); var child = new GameObject(); child.name = gameObject.name; var fractal = child.AddComponent<Fractal>(); fractal.initialize(this, length * 0.75f, width_ * 0.75f, transform.rotation * Quaternion.Euler(30f, roty, 0f), depth_+1); roty += 137.5f;
  96. 96. 動画
  97. 97. using System.Collections; using System.Collections.Generic; using UnityEngine; public class Fractal : MonoBehaviour { [SerializeField] Mesh mesh_; [SerializeField] Material material_; const int MAX_DEPTH = 7; Vector3 start_ = Vector3.zero; Vector3 end_ = Vector3.up; float width_ = 0.1f; int depth_ = 0; void initialize(Fractal parent, float given_length, float given_width, Quaternion given_rotation, int depth) { mesh_ = parent.mesh_; material_ = parent.material_; transform.position = parent.transform.position + Vector3.up; start_ = parent.end_; end_ = start_ + given_rotation * (Vector3.up * given_length); width_ = given_width; depth_ = depth; }
    IEnumerator Start() { gameObject.AddComponent<MeshFilter>().mesh = mesh_; gameObject.AddComponent<MeshRenderer>().material = material_; transform.position = (start_ + end_) * 0.5f; var diff = end_ - start_; var length = diff.magnitude; transform.rotation = Quaternion.LookRotation(diff) * Quaternion.Euler(90f, 0f, 0f); transform.localScale = new Vector3(width_, length * 1f, width_); if (depth_ >= MAX_DEPTH) yield break; float roty = Random.Range(0f, 360f); for (var i = 0; i < 5; ++i) { if (Random.Range(0, 2) != 0) continue; yield return new WaitForSeconds(0.1f); var child = new GameObject(); child.name = gameObject.name; var fractal = child.AddComponent<Fractal>(); fractal.initialize(this, length * 0.75f, width_ * 0.75f, transform.rotation * Quaternion.Euler(30f, roty, 0f), depth_+1); roty += 137.5f;再掲
  98. 98. • 樹木生成のコードを変更して遊んでみよう • 「再帰は使うべきでない」とする説の意味を調べよう • スタックの動作を理解しよう まとめ&今後の指針
  99. 99. 1. プログラム言語 2. 参照と実体 3. プッシュ/プル 4. 再帰 本日のお話 C# C++ C オブジェクト指向 構造化 Java Rust Perl 関数型 Haskell
  100. 100. 永遠に続きます。
  101. 101. おしまい

×