1

ダイスロールのディスプレイを作ろうとしています。私がやりたいのは、サイコロのランダムな顔のちらつき画像で、最後に数字が出た顔で終わります。この後、関数を続行してダイスロールの数を返したいと思います。これが私が持っているものです

public int RollDie()
{
    RollNum = dieRoll.Next(1, 7);
    DispCount = 0;
    Timer Time = new Timer();
    Time.Interval = TimerInterval;
    Time.Tick += DisplayRollHandler;
    Time.Start();
    System.Threading.Thread DispThread = new System.Threading.Thread(Time.Start);
    DispThread.Start();
    DispThread.Join();
    return RollNum;
}
private void DisplayRollHandler(object sender, EventArgs evt)
{
    if (DispCount < TargetDispCount)
    {
        Random Nums = new Random();
        Display.BackgroundImage = Faces[Nums.Next(0, 6)];
        DispCount++;
    }
    else
    {
        ((Timer)sender).Stop();
        Display.BackgroundImage = Faces[RollNum - 1];
    }
}

ここdieRollで、はランダムオブジェクトでありDisplay、はパネルです。画像のちらつきは機能し、ロールの数を一貫して返します。残念ながら、表示のちらつきが終了するのを待たずに続行します。これは、サイコロを振った後にポップアップする自動メッセージがある場合に問題になります。

私はかなり経験の浅いプログラマーなので、おそらく本当に基本的な概念が欠けています。これをメソッド呼び出しに抽象化できれば、メソッド呼び出しが終了するのを待つことができますが、Thread.Sleep呼び出しを使用してプログラムをフリーズしないと、その方法を理解できません。

助言がありますか?

4

2 に答える 2

3

このソリューションには、ダイスオブジェクト自体の中でランダマイザーをインスタンス化してはならないという根本的なエラーがあります。簡単なテストでその理由がわかります。フォームに別のサイコロオブジェクトを追加し、両方を同時に転がすだけです。何か面白いことに気づきましたか?彼らはいつも同じです!

これは、デフォルトでは、ランダマイザーが現在の時刻を使用してジェネレーターをシードしたためです。コードの同じ部分に2つ(またはそれ以上)のオブジェクトを作成すると、すべてのサイコロオブジェクトが同じシードを持つことになり、毎回ロールしたときに同じ結果になります。

より良い解決策は、すべてのサイコロを振る(ランダム化する)すべてのサイコロを処理する静的シングルトンクラスを作成することです。

簡単な例を次に示します(もう少し一般的なDiceクラスを使用)。

public static class DiceRoller
{
    private static Random _roller;

    public static void RollDice(Dice dice)
    {
        if (dice.Faces.Count < 1)
            throw new InvalidOperationException("A dice must contain at least 1 side to be rolled.");

        if (_roller == null)
            _roller = new Random();

        int index = _roller.Next(dice.Faces.Count);
        dice.SetFacingIndex(index);
    }
}
于 2013-01-10T14:23:19.463 に答える
2

Dice必要な値を提供する小さなクラスを作成しました。

public class Dice
{
    private Random _Random;
    private BackgroundWorker _Worker;

    /// <summary>
    /// Initializes a new instance of the <see cref="Dice"/> class.
    /// </summary>
    public Dice()
    {
        _Random = new Random();

        InitializeDefaultValues();
        InitializeBackgroundWorker();
    }

    /// <summary>
    /// Occurs when the dice finished rolling.
    /// </summary>
    public event EventHandler Rolled;

    /// <summary>
    /// Occurs while the dice is rolling and the value has changed.
    /// </summary>
    public event EventHandler RollingChanged;

    /// <summary>
    /// Gets or sets the including maximum value that the dice can return.
    /// </summary>
    /// <value>
    /// The maximum value.
    /// </value>
    [DefaultValue(6)]
    public int Maximum { get; set; }

    /// <summary>
    /// Gets or sets the including minimum value that the dice can return.
    /// </summary>
    /// <value>
    /// The minimum.
    /// </value>
    [DefaultValue(1)]
    public int Minimum { get; set; }

    /// <summary>
    /// Gets the result that this dice currently has.
    /// </summary>
    public int Result { get; private set; }

    /// <summary>
    /// Gets or sets the duration of the rolling.
    /// </summary>
    /// <value>
    /// The duration of the rolling.
    /// </value>
    [DefaultValue(typeof(TimeSpan), "00:00:03")]
    public TimeSpan RollingDuration { get; set; }

    /// <summary>
    /// Starts rolling the dice.
    /// </summary>
    public void Roll()
    {
        if (!_Worker.IsBusy)
        {
            CheckParameters();
            _Worker.RunWorkerAsync();
        }
    }

    private void CheckParameters()
    {
        if (Minimum >= Maximum)
        {
            throw new InvalidOperationException("Minimum value must be less than the Maximum value.");
        }

        if (RollingDuration <= TimeSpan.Zero)
        {
            throw new InvalidOperationException("The RollingDuration must be greater zero.");
        }
    }

    private void InitializeBackgroundWorker()
    {
        _Worker = new BackgroundWorker();
        _Worker.WorkerReportsProgress = true;
        _Worker.DoWork += OnWorkerDoWork;
        _Worker.ProgressChanged += OnWorkerProgressChanged;
        _Worker.RunWorkerCompleted += OnWorkerRunWorkerCompleted;
    }

    private void InitializeDefaultValues()
    {
        Minimum = 1;
        Maximum = 6;
        Result = Minimum;
        RollingDuration = TimeSpan.FromSeconds(3);
    }

    private void OnWorkerDoWork(object sender, DoWorkEventArgs e)
    {
        var finishTime = DateTime.UtcNow + RollingDuration;

        while (finishTime > DateTime.UtcNow)
        {
            Result = _Random.Next(Minimum, Maximum + 1);
            _Worker.ReportProgress(0);
            // ToDo: Improve sleep times for more realistic rolling.
            Thread.Sleep(50);
        }
    }

    private void OnWorkerProgressChanged(object sender, ProgressChangedEventArgs e)
    {
        RaiseEvent(RollingChanged);
    }

    private void OnWorkerRunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        RaiseEvent(Rolled);
    }

    private void RaiseEvent(EventHandler handler)
    {
        var temp = handler;

        if (temp != null)
        {
            temp(this, EventArgs.Empty);
        }
    }
}

最初の簡単な例では、フォーム(buttonRoll)とラベル(labelDiceResult)にボタンを追加し、次のコードを追加しました(フォームコンストラクターにinitializeメソッドを追加することを忘れないでください)。

private void InitializeDice()
{
    _Dice = new Dice();
    _Dice.RollingChanged += OnDiceRollingChanged;
    _Dice.Rolled += OnDiceRolled;
}

void OnDiceRolled(object sender, EventArgs e)
{
    buttonRoll.Enabled = true;
}

void OnDiceRollingChanged(object sender, EventArgs e)
{
    // ToDo: Select desired picture from image list depending on _Dice.Result
    labelDiceResult.Text = _Dice.Result.ToString();
}

private void OnButtonRollClick(object sender, EventArgs e)
{
    buttonRoll.Enabled = false;
    _Dice.Roll();
}

Thread.Sleep(50)最後のステップとして、副鼻腔の立ち上がり部分とサイコロを時間の経過とともに遅くするための望ましい期間に応じて計算されたリストを使用して、時間の経過とともに異なる値を使用するように呼び出しを微調整します。しかし、私はこの部分を読者(または次の質問)に公開しました。

于 2012-12-04T09:33:29.360 に答える