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

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

ただいまの
回答率

88.93%

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

解決済

回答 4

投稿 編集

  • 評価
  • クリップ 1
  • VIEW 365

mushipan0929

score 8

解決したい事

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

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

書いたコード

テキスト表示部分

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class UiManager : MonoBehaviour
{
    public Text totalCookie;
    public Text cookiePerSecondText;

    // 毎フレーム毎の総クッキー数
    private float[] frameTotalCookie = new float[30];
    // 現フレームのクッキー生産効率
    private float frameCPS;

    void Update()
    {
        frameTotalCookie[Time.frameCount % 30] = GameManager.gameManager.totalCookie;
        // 現フレームの総クッキーから29フレーム前の総クッキーを引くことでクッキー生産効率を算出
        // ただしこのやり方だと一生frameTotalCookie[0]が引かれることはない為、要修正
        // TODO;CPS算出時にframeTotalCookie[0]が引かれる側の数値として選ばれない問題の修正
        frameCPS = frameTotalCookie[Time.frameCount % 30] - frameTotalCookie[Time.frameCount % 29 + 1];

        totalCookie.text = GameManager.gameManager.totalCookie.ToString("000000000.0") + " Cookies";
        cookiePerSecondText.text = frameCPS.ToString("F1") + " CPS";
    }
}


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

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class CookieManager : MonoBehaviour
{
    public void PushCookie()
    {
        GameManager.gameManager.totalCookie++;
    }
}

追記

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

追記2

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

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 4

checkベストアンサー

+3

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

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

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

frameCPS = 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 18:21 編集

    回答ありがとうございます。

    これほど簡単に解決するとは驚きました...
    やっぱり論理的な考えは大切ですね。
    とても分かりやすいためベストアンサーとさせて頂きます。

    他の方々も教えていただきありがとうございました!

    キャンセル

  • 2020/07/16 09:51

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

    キャンセル

+1

【追記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)を繰り返すことで毎秒のクリック数を集計可能です。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ClickCountForSecond : MonoBehaviour
{
    int ClicksPerSecond;
    int TotalClicksCount;

    void Start ()
    {
        QualitySettings.vSyncCount = 0; // vsyncをOFFにする
        Application.targetFrameRate = 30; // FPSを変更        
        InvokeRepeating( "LoopCount",0f,1f);//1秒ごとにコルーチンを呼び出す
    }

    void LoopCount()
    {
        StartCoroutine(loop(30));//30回 Whileを繰り返し、それを一回のコルーチンループとする
    }

    private IEnumerator loop(int frame)
    {
        while (frame > 0) 
    {
            yield return null;
            if(Input.GetMouseButtonDown(0))
                ClicksPerSecond++;

            frame--;
        }
        TotalClicksCount += ClicksPerSecond;
        Debug.Log(ClicksPerSecond + "Click/s   TotalClicks : " + TotalClicksCount);
        ClicksPerSecond = 0;
    }
}

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2020/07/16 11:01

    なるほど!そういうことでしたか、完全に解釈が違っていました。
    毎フレーム情報を更新するのは単にフレームごとに加算すればよいと考えていました。
    詳しく説明していただきありがとうございます。であれば、CPSをMatf.Clampで制限すればよさそうですね。

    ちなみになんですが、28→29→30→30→30→30という風にするのはもしFPSがなんらかの影響で30FPSを越えてしまった場合の対処という認識でよろしいでしょうか?

    キャンセル

  • 2020/07/16 11: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フレームのクリック数を計算できるロジックであればそれでいいとは思います。

    キャンセル

  • 2020/07/16 12:30

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

    キャンセル

0

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

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2020/07/15 16:16

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

    キャンセル

  • 2020/07/15 16:24

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

    キャンセル

  • 2020/07/15 16:33

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

    キャンセル

0

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

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

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

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2020/07/15 18:45

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

    キャンセル

  • 2020/07/16 12:52 編集

    たびたびアクティブになるので眺めていたら、自分の勘違いに気づきました。

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

    キャンセル

  • 2020/07/17 15:31

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

    キャンセル

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

  • ただいまの回答率 88.93%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る