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

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

新規登録して質問してみよう
ただいま回答率
85.35%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Unity

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

Q&A

解決済

4回答

1058閲覧

毎秒何回クリックしているか正確に出したい

mushipan0929

総合スコア56

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Unity

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

0グッド

1クリップ

投稿2020/07/15 06:42

編集2020/07/15 07:18

解決したい事

現在CookieClickerをUnityで再現しようとしているのですが
正確に毎秒クッキーを何回クリックしたか出力するコードの書き方が分からず詰まっております。
ネットで調べたりもしましたが、そもそも調べ方が悪いのかそれとも情報がないのか有用な情報は見つかりませんでした。
なんとかそれっぽい物は作れましたが、長時間クリックしていると正しく表示されなくなってしまいます。

どなたかご教授願います。
また測定方法として毎フレーム情報が更新されるようにしたいです。(フレームレートは30FPS)

書いたコード

テキスト表示部分

C#

1using System.Collections; 2using System.Collections.Generic; 3using UnityEngine; 4using UnityEngine.UI; 5 6public class UiManager : MonoBehaviour 7{ 8 public Text totalCookie; 9 public Text cookiePerSecondText; 10 11 // 毎フレーム毎の総クッキー数 12 private float[] frameTotalCookie = new float[30]; 13 // 現フレームのクッキー生産効率 14 private float frameCPS; 15 16 void Update() 17 { 18 frameTotalCookie[Time.frameCount % 30] = GameManager.gameManager.totalCookie; 19 // 現フレームの総クッキーから29フレーム前の総クッキーを引くことでクッキー生産効率を算出 20 // ただしこのやり方だと一生frameTotalCookie[0]が引かれることはない為、要修正 21 // TODO;CPS算出時にframeTotalCookie[0]が引かれる側の数値として選ばれない問題の修正 22 frameCPS = frameTotalCookie[Time.frameCount % 30] - frameTotalCookie[Time.frameCount % 29 + 1]; 23 24 totalCookie.text = GameManager.gameManager.totalCookie.ToString("000000000.0") + " Cookies"; 25 cookiePerSecondText.text = frameCPS.ToString("F1") + " CPS"; 26 } 27} 28

クリック部分(クッキーをクリックするとPushCookieが呼ばれます)

C#

1using System.Collections; 2using System.Collections.Generic; 3using UnityEngine; 4 5public class CookieManager : MonoBehaviour 6{ 7 public void PushCookie() 8 { 9 GameManager.gameManager.totalCookie++; 10 } 11} 12

###追記
配列数参照の部分を変数にして[30]読み込もうとしたときに[0]にすれば解決出来ますが
出来ればそれ以外のやり方でお願いします。
追記し忘れていました、申し訳ないです。

###追記2
出力したい回数は1秒間でのクリック回数(30FPS固定なので過去30フレームの総クリック回数です。)

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

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

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

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

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

guest

回答4

0

ベストアンサー

リングバッファの考え方に近いかと思います。

ようは、現在のフレームカウントの次のフレームカウントの時の添え字を求めれば、最古のデータが格納されていることになります。

そうなると提示された下記ソースですと、

C#

1frameCPS = frameTotalCookie[Time.frameCount % 30] - frameTotalCookie[Time.frameCount % 29 + 1];

求めるべき最古のデータが格納されている添え字がどんどんずれていきます。
(例 Time.frameCount = 29の時 最新データを格納した添え字(Time.frameCount % 30)は29となり、最古のデータが格納されているべき添え字は0のはずがTime.frameCount % 29 + 1だと1になります)

最古のデータは次のフレームで格納される場所なので(Time.frameCount + 1) % 30と計算すればいいはずです。

投稿2020/07/15 08:39

編集2020/07/15 08:40
YAmaGNZ

総合スコア10489

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

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

mushipan0929

2020/07/15 09:22 編集

回答ありがとうございます。 これほど簡単に解決するとは驚きました... やっぱり論理的な考えは大切ですね。 とても分かりやすいためベストアンサーとさせて頂きます。 他の方々も教えていただきありがとうございました!
YAmaGNZ

2020/07/16 00:51

改めて考えてみたのですが、クリックカウンタをリセットしていないので、カウンタを格納した配列の最大値と最小値を取ればいいだけじゃないかと思いました。 frameCPS = frameTotalCookie.Max() - frameTotalCookie.Min(); 速度的には添え字を計算したほうが速いのでしょうが、30個くらいの配列であれば誤差程度かなと思います。
guest

0

【追記2020/7/16】以下の処理は「毎秒ごとのクリック数」をカウントする処理であり、質問者様の意図する「毎フレーム情報が更新される」という使用とは異なっています。申し訳ございません

コルーチンとInvokeRepetingの組み合わせで計測可能です

ざっとやっていることを説明すると、Unity Editor上ではFPSを固定するにはproject settingのQualityからOtherのVSync Countを「Don't Sync」と設定し、その後にApplication.targetFrameRateで指定のFPSに変更する必要があります。Project settingを変更すると後々変更したことを忘れて手間取る場合があるので、QualitySettings.vSyncCount = 0;と記述することでScene再生時のみ設定を変更出来ます。

IEnumerator loop(int frame)のframeが繰り返すフレームの長さなので今回で言えば30、30FPSの中でwhileでループさせ、カウントを取り、30FPS経った時にクリック数を表示、リセット。
これをInvokeRepetingで0f開始、1fつまり1秒ごとにIEnumerator loop(int frame)を繰り返すことで毎秒のクリック数を集計可能です。

c#

1using System.Collections; 2using System.Collections.Generic; 3using UnityEngine; 4 5public class ClickCountForSecond : MonoBehaviour 6{ 7 int ClicksPerSecond; 8 int TotalClicksCount; 9 10 void Start () 11 { 12 QualitySettings.vSyncCount = 0; // vsyncをOFFにする 13 Application.targetFrameRate = 30; // FPSを変更 14 InvokeRepeating( "LoopCount",0f,1f);//1秒ごとにコルーチンを呼び出す 15 } 16 17 void LoopCount() 18 { 19 StartCoroutine(loop(30));//30回 Whileを繰り返し、それを一回のコルーチンループとする 20 } 21 22 private IEnumerator loop(int frame) 23 { 24 while (frame > 0) 25    { 26 yield return null; 27 if(Input.GetMouseButtonDown(0)) 28 ClicksPerSecond++; 29 30 frame--; 31 } 32 TotalClicksCount += ClicksPerSecond; 33 Debug.Log(ClicksPerSecond + "Click/s TotalClicks : " + TotalClicksCount); 34 ClicksPerSecond = 0; 35 } 36}

投稿2020/07/15 07:53

編集2020/07/16 03:35
Y0241-N

総合スコア1066

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

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

mushipan0929

2020/07/15 09:21

回答頂きありがとうございます。 GetMouseButton→GetMouseButtonDownで正常に動きました。 説明付きで分かりやすかったです。 それにしても色々と今後応用が利く関数ですね...
Y0241-N

2020/07/16 00:17

GetMouseButtonになっている部分を見落としていました...、なんという初歩的なミス...。 お恥ずかしい限りです、正常に作動したようでなによりです。 コルーチンとInvokeは単体でも応用が利くので、今後使用する機会や目にする機会も多いと思います。 回答の方は正しく機能する内容に修正しておきます。
YAmaGNZ

2020/07/16 00:46

この方法だと、要件の「毎フレーム情報が更新されるようにしたい」を満たしていないのではないでしょうか?
Y0241-N

2020/07/16 00:56

すみません、計測目的でのみの機能で考えていました。 トータル数も集計するように変更しておきます。
YAmaGNZ

2020/07/16 01:10

すみません。私が「毎フレーム情報が更新されるようにしたい」という要件とソースから読み取ったのは 現フレームから過去30フレームの間にクリックされた数をCPSとして表示するということでした。 ですので、ご提示の方法ですと、コルーチンを起動してから30フレーム間カウントアップし、CPSがリセットされるため、30フレーム毎にCPSが1~となってしまうので提示要件に合わないのではないかとコメントしました。
Y0241-N

2020/07/16 01:21

なるほど、確かに私は勝手に見やすさを考慮して1秒ごとにCPSをリセットしていました。 要件にあった形にするならCPS = 0;を消してwhile内にDebug.Log(ClickPerSecond);を記入すれば毎フレーム情報が更新されるようになると思うのですが、そもそもコルーチンとInvokeRepetingを使って毎フレーム情報更新できているとするのは危ういということでしょうか?
YAmaGNZ

2020/07/16 01:45

現状のロジックでClicksPerSecond = 0;を消すと、ClicksPerSecondが延々とインクリメントされCPSという意味とは違ってしまうのではないかと思います。 また、「毎フレーム情報更新できているとするのは危うい」ということではなく、毎フレーム更新はされるが表示したい物が異なるという感じですかね。 例えば1フレームに1回クリックしたとすると Y0241-Nさんが提示されたロジックですとCPSは 1→2→3→4→5→6→7→8→9→・・・28→29→30→1→2→3と遷移するかと思います。 もし、ClicksPerSecond = 0;を消すと 1→2→3→4→5→6→7→8→9→・・・28→29→30→31→32→33と遷移するかと思います。 求められている仕様は 1→2→3→4→5→6→7→8→9→・・・28→29→30→30→30→30ではないのかということです。
Y0241-N

2020/07/16 02:01

なるほど!そういうことでしたか、完全に解釈が違っていました。 毎フレーム情報を更新するのは単にフレームごとに加算すればよいと考えていました。 詳しく説明していただきありがとうございます。であれば、CPSをMatf.Clampで制限すればよさそうですね。 ちなみになんですが、28→29→30→30→30→30という風にするのはもしFPSがなんらかの影響で30FPSを越えてしまった場合の対処という認識でよろしいでしょうか?
YAmaGNZ

2020/07/16 02:21

いえ、過去30フレーム間の値なので、例えば32フレーム目の時点ですと、2フレーム目~32フレーム目の間にクリックされた数をCPSとするということなのではないかと思います。 その為、質問者さんのソースはそのフレーム時点でのカウンター値を保持しておき、30フレーム前の値との差を求めているロジックになっていると考えました。 ですのでMatf.Clampにて値の範囲を限定するというのは違うと思います。 >ちなみになんですが、28→29→30→30→30→30という風にするのはもしFPSがなんらかの影響で30FPSを越えてしまった場合の対処という認識でよろしいでしょうか? 1フレーム1クリックとしたときの例なので30フレーム30クリックとなっているだけです。 もし5フレームの間に1回クリックしたのであればCPSは 0→0→0→0→1→1→1→1→1→2→2→2→2→2→3→3→3→3→3→4→4→4→4→4→5→5→5→5→5→5→5→5 となるのではないかと思います。 コルーチンを使って、過去30フレームのクリック数を計算できるロジックであればそれでいいとは思います。
Y0241-N

2020/07/16 03:30

ようやく理解できました、私が作成した内容はまったく違うものですね... 意図を全くくみ取れていませんでした、仕組みはちょっと思いつけそうにないので回答の方を「1秒間ごとにクリックされた回数をカウントする処理」という風に説明を入れておきます。
guest

0

データを更新する前に引いておかないとダメなんじゃないかな?(ベタ書きしてるので適当に最適化して下さい)
30個くらいなら毎回sum取ってもいいような気がしますが。

c#

1frameCPS -= frameTotalCookie[Time.frameCount % 30]; 2frameTotalCookie[Time.frameCount % 30] = GameManager.gameManager.totalCookie; 3frameCPS += frameTotalCookie[Time.frameCount % 30];

C#もUnityも知らないので的外れならすみません。

投稿2020/07/15 07:51

fuzzball

総合スコア16733

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

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

mushipan0929

2020/07/15 09:21

回答頂きありがとうございます。 Time.frameCountは現在のフレーム数を返すため、frame -= ~は30フレーム遅れたデータが代入されてしまいズレてしまいます。
fuzzball

2020/07/15 09:31

そのつもりで回答しました。 合計値から一番古いデータを引き、その後で今回のデータを上書き&足しています。
mushipan0929

2020/07/15 09:45

そうだったんですね、失礼いたしました。 質問の書き方が悪く申し訳ないです。
fuzzball

2020/07/16 03:54 編集

たびたびアクティブになるので眺めていたら、自分の勘違いに気づきました。 frameCPS: トータルクリック数 frameTotalCookie[]: 各フレームのクリック数 だと思って回答してました。これじゃ全然違いますね‥。 (自分ならそういう作りにする‥という思い込みです)
mushipan0929

2020/07/17 06:31

あまり英語が得意ではないのでいつも翻訳頼みで書いているのですが、自分でも偶に良くわからなくなってしまいます...
guest

0

https://unity-senpai.hatenablog.com/entry/2019/05/17/011419
調べてみました
少しでも参考になればと思います

投稿2020/07/15 06:47

snowdropAPP

総合スコア41

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

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

mushipan0929

2020/07/15 07:06

回答頂きありがとうございます。 リンク先のページを確認しましたが、ボタンを使わずクリックを検知するやり方しか 書かれていなかったので質問の解決にはなりませんでした。 ですがまだまだ知らない情報なので今後の参考にしていきたいと思います。
mushipan0929

2020/07/15 07:16

ボタンを押した累計回数ではなく、1秒間で(30FPS固定なので過去30フレーム内で)何回押しているか知りたいです。 タイトルや説明欄に記載していますが分かりにくかったでしょうか...申し訳ないです。
snowdropAPP

2020/07/15 07:24

あーそういうことなんですね。。。 すいませんタイトルをあまり見てませんでした
mushipan0929

2020/07/15 07:33

ちゃんと見てください(T_T) でも紹介してくれた機能結構多機能そうなのでありがとうございますー
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問