質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.41%
アルゴリズム

アルゴリズムとは、定められた目的を達成するために、プログラムの理論的な動作を定義するものです。

Unity

Unityは、Unity Technologiesが開発・販売している、IDEを内蔵するゲームエンジンです。主にC#を用いたプログラミングでコンテンツの開発が可能です。

Q&A

解決済

2回答

356閲覧

[Unity] 関数は呼ばれているが値が代入されていない

Ryusei.w

総合スコア44

アルゴリズム

アルゴリズムとは、定められた目的を達成するために、プログラムの理論的な動作を定義するものです。

Unity

Unityは、Unity Technologiesが開発・販売している、IDEを内蔵するゲームエンジンです。主にC#を用いたプログラミングでコンテンツの開発が可能です。

0グッド

0クリップ

投稿2024/05/08 03:20

実現したいこと

Glicko2 Rating Systemを実装しようとプログラムを組む過程で、値の2乗が様々なところで必要になったため、
Pow2という、各値の2乗を格納するための構造体を作って
private Pow2 power = new Pow2();
と宣言しました。

以降power.v2のように値を取り出せるようにし、
最後の方に記述してあるupDatePow2()関数を呼び出すことで計算に必要なdeltaやfaiといったfloat型の変数を二乗した値を格納する機能をもたせました。

発生している問題・分からないこと

コードが長いので中略していますが、upDatePow2を他の関数内(自作、Start()などなど)でも呼び出したのですが値が代入されていませんでした。

インスペクターで監視していましたがずっと0のままでした。

エラーメッセージ

error

1----------------

該当のソースコード

C#

1using System.Collections; 2using System.Collections.Generic; 3using Unity.VisualScripting; 4using UnityEngine; 5 6public class Glicko2Rating : MonoBehaviour 7{ 8 [SerializeField] private float TAU = 0.5f; //レーティング変動率 9 [SerializeField] private int INITIAL_RATE = 1500; 10 [SerializeField] private int MAX_RD = 350; 11 [SerializeField] private int MIN_RD = 50; 12 private const float CONST = 173.7178f; 13 14 [System.Serializable] 15 public struct Rating 16 { 17 public float rate; //現在のレート 18 public float RD; //レーティング偏差 19 } 20 21 /// <summary> 22 /// 2乗の値を格納 23 /// </summary> 24 [System.Serializable] 25 public struct Pow2 26 { 27 public float d2; //delta 28 public float f2; //fai 29 public float t2; //TAU 30 public float v2; //Vol 31 public float v22; //vol2 32 } 33 34 [SerializeField] private Pow2 power = new Pow2(); 35 36 public float Vol, vol2; //volatility 37 public Rating pG = new Rating(); //player grade 38 public Rating[] eG; //enemy grade 39 public int[] vicDef; //win = 1 / lose = 0 40 41 //計算用 42 [SerializeField] private float mue, fai, delta, v, a; 43 private float ipu = 0.000001f; 44 45///~~~中略~~~/// 46 47 private void upDatePow2(Pow2 p) 48 { 49 p.d2 = Mathf.Pow(delta, 2); 50 p.f2 = Mathf.Pow(fai, 2); 51 p.t2 = Mathf.Pow(TAU, 2); 52 p.v2 = Mathf.Pow(Vol, 2); 53 p.v22 = Mathf.Pow(vol2, 2); 54 55 //Debug.Log("updated pow2"); 56 } 57}

C#

1using System.Collections; 2using System.Collections.Generic; 3using Unity.VisualScripting; 4using UnityEngine; 5 6public class Glicko2Rating : MonoBehaviour 7{ 8 [SerializeField] private float TAU = 0.5f; //レーティング変動率 9 [SerializeField] private int INITIAL_RATE = 1500; 10 [SerializeField] private int MAX_RD = 350; 11 [SerializeField] private int MIN_RD = 50; 12 private const float CONST = 173.7178f; 13 14 [System.Serializable] 15 public struct Rating 16 { 17 public float rate; //現在のレート 18 public float RD; //レーティング偏差 19 } 20 21 /// <summary> 22 /// 2乗の値を格納 23 /// </summary> 24 [System.Serializable] 25 public struct Pow2 26 { 27 public float d2; //delta 28 public float f2; //fai 29 public float t2; //TAU 30 public float v2; //Vol 31 public float v22; //vol2 32 } 33 34 [SerializeField] private Pow2 power = new Pow2(); 35 36 public float Vol, vol2; //volatility 37 public Rating pG = new Rating(); //player grade 38 public Rating[] eG; //enemy grade 39 public int[] vicDef; //win = 1 / lose = 0 40 41 //計算用 42 [SerializeField] private float mue, fai, delta, v, a; 43 private float ipu = 0.000001f; 44 45 private void Start() 46 { 47 upDatePow2(power); 48 49 //スケール変換 50 mue = ConvertRateScale(pG.rate, true); 51 fai = ConvertRDScale(pG.RD, true); 52 53 Debug.Log("μ = " + mue); 54 Debug.Log("φ = " + fai); 55 56 //敵のスケール変換 57 for (int i = 0; i < eG.Length; i++) 58 { 59 eG[i].rate = ConvertRateScale(eG[i].rate, true); 60 eG[i].RD = ConvertRDScale(eG[i].RD, true); 61 } 62 63 ///Test用 64 CalculateV(); 65 CalculateDelta(); 66 upDateSigma(); 67 upDateRating(); 68 } 69 70 71 private float ConvertRateScale(float r, bool b) 72 { 73 //trueで変換 falseで復元 74 float i; 75 if (b) i = (r - INITIAL_RATE) / CONST; 76 else i = CONST * r + INITIAL_RATE; 77 78 return i; 79 } 80 81 private float ConvertRDScale(float rd, bool b) 82 { 83 //trueで変換 falseで復元 84 float i; 85 if (b) i = rd / CONST; 86 else i = CONST * rd; 87 88 return i; 89 } 90 91 private float Gfai(float f) 92 { 93 float i = Mathf.Sqrt(1 + 3 * (f * f) / 9.8696044f); 94 return (1/i); 95 } 96 97 private float E(float m, float mj, float fj) 98 { 99 float i = 1 + Mathf.Exp(-1 * Gfai(fj) * (m - mj)); 100 return (1/i); 101 } 102 103 private float F(float x) 104 { 105 upDatePow2(power); 106 float e = Mathf.Exp(x); 107 108 float o = e * (power.d2 - power.f2 - v - e); 109 float p = 2 * Mathf.Pow((power.f2 + v + e), 2); 110 float q = (x - a) / power.t2; 111 112 return (o / p) - q; 113 } 114 115 private void CalculateV() 116 { 117 v = 0; 118 119 for (int i = 0; i < eG.Length; i++) 120 { 121 float g = Mathf.Pow(Gfai(eG[i].RD), 2); 122 float e = E(mue, eG[i].rate, eG[i].RD); 123 124 v += g * e * (1 - e); 125 } 126 127 v = 1 / v; 128 Debug.Log("v = " + v); 129 } 130 131 private void CalculateDelta() 132 { 133 delta = 0; 134 135 for (int i = 0; i < eG.Length; i++) 136 { 137 delta += Gfai(eG[i].RD) * (vicDef[i] - E(mue, eG[i].rate, eG[i].RD)); 138 } 139 140 delta *= v; 141 Debug.Log("Δ = " + delta); 142 } 143 144 private void upDateSigma() 145 { 146 float A = a; //log(Vol^2) 147 upDatePow2(power); 148 149 float B, C, fa, fb, fc; 150 151 if(power.d2 > (power.f2 + v)) 152 { 153 B = Mathf.Log(power.d2 - power.f2 - v); 154 } 155 else 156 { 157 int k = 1; 158 while(F(a - k*TAU) < 0) 159 { 160 k = k + 1; 161 } 162 163 B = a - k*TAU; 164 } 165 166 fa = F(A); 167 fb = F(B); 168 169 while(Mathf.Abs(B - A) > ipu) 170 { 171 C = A + (A - B) * fa / (fb - fa); 172 fc = F(C); 173 174 if(fc*fb < 0) 175 { 176 A = B; 177 fa = fb; 178 } 179 else fa /= 2; 180 181 B = C; 182 fb = fc; 183 } 184 185 vol2 = Mathf.Exp(A / 2); 186 } 187 188 private void upDateRating() 189 { 190 upDatePow2(power); 191 192 Debug.Log("v22 = " + power.v22 + ", f2 = " + power.f2); 193 194 float faia = Mathf.Sqrt(power.f2 + power.v22); 195 float faid = 1 / Mathf.Sqrt((1 / Mathf.Pow(faia, 2)) + (1 / v)); 196 Debug.Log("φ' = " + faid); 197 Debug.Log("φ* = " + faia); 198 199 float mue2 = 0; 200 for(int i = 0; i < eG.Length; i++) 201 { 202 float g = Gfai(eG[i].RD); 203 float e = E(mue, eG[i].rate, eG[i].RD); 204 205 mue2 += g * (vicDef[i] - e); 206 207 //Debug.Log("μ' = " + mue2); 208 } 209 mue2 *= Mathf.Pow(faid, 2); 210 mue2 += mue; 211 212 Debug.Log("μ' = " + mue2); 213 214 pG.rate = ConvertRateScale(mue2, false); 215 pG.RD = ConvertRDScale(faid, false); 216 } 217 218 private void upDatePow2(Pow2 p) 219 { 220 p.d2 = Mathf.Pow(delta, 2); 221 p.f2 = Mathf.Pow(fai, 2); 222 p.t2 = Mathf.Pow(TAU, 2); 223 p.v2 = Mathf.Pow(Vol, 2); 224 p.v22 = Mathf.Pow(vol2, 2); 225 226 //Debug.Log("updated pow2"); 227 } 228}

試したこと・調べたこと

  • teratailやGoogle等で検索した
  • ソースコードを自分なりに変更した
  • 知人に聞いた
  • その他
上記の詳細・結果

http://www.glicko.net/glicko/glicko2.pdf

この論文に記載のある計算例と、数式をそのままプログラムにしています。

プログラムが長いので省略版と、完全版を乗せておきます。

補足

特になし

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

YAmaGNZ

2024/05/08 03:45 編集

的外れのコメントでした。
guest

回答2

0

ベストアンサー

Pow2を構造体として定義しているため、関数の引数とした場合に値渡しとなり

C#

1 private void test() 2 { 3 Pow2 a; 4 upDatePow2(a); 5 } 6 private void upDatePow2(Pow2 p) 7 { 8 p.d2 = Mathf.Pow(delta, 2); 9 p.f2 = Mathf.Pow(fai, 2); 10 p.t2 = Mathf.Pow(TAU, 2); 11 p.v2 = Mathf.Pow(Vol, 2); 12 p.v22 = Mathf.Pow(vol2, 2); 13 }

としたときのtest関数で定義したaとupDatePow2関数で受け取ったpは別物となりpの値を更新してもaの値は更新されません。

C#

1 private void test() 2 { 3 Pow2 a; 4 upDatePow2(ref a); 5 } 6 private void upDatePow2(ref Pow2 p) 7 { 8 p.d2 = Mathf.Pow(delta, 2); 9 p.f2 = Mathf.Pow(fai, 2); 10 p.t2 = Mathf.Pow(TAU, 2); 11 p.v2 = Mathf.Pow(Vol, 2); 12 p.v22 = Mathf.Pow(vol2, 2); 13 }

といった感じでrefを付けて参照渡しにすればいいと思いますがPow2構造体に計算メソッドを用意したほうがいいような気もします。

ただ計算時に2乗の値が欲しいだけであれば

C#

1 private float deltaPow2 { get { return Mathf.Pow(delta, 2);} }

といった感じで2乗した値を返すプロパティを用意してもいいような気もします。

投稿2024/05/08 03:56

編集2024/05/08 04:17
YAmaGNZ

総合スコア10336

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Ryusei.w

2024/05/08 04:32

具体的にありがとうございました!! 原因も解決方法も見通しが立ちました。
guest

0

Pow2は構造体(struct)になっています。
C#の場合、構造体は値型として(つまりintなどと同じように)扱われます。
そのため、upDatePow2(Pow2 p)の中でpをいくら変更しようが、その変更は呼び出し元の変数に反映されません。
これは、int型の引数を思い浮かべれば分かると思います。

修正方法としては以下が考えられます。

  • Pow2をclassに変更する(classは参照型なので、変更が反映されるようになる)
  • upDatePow2で変更したPow2p)を返すように変更し、それを元の変数に代入する
  • upDatePow2の引数pにoutキーワードを付ける

投稿2024/05/08 03:53

fiveHundred

総合スコア9993

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Ryusei.w

2024/05/08 04:31

なるほど、原因がわかりました。ありがとうございます!!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.41%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問