3

私は do while ループを使用しており、ループごとにユーザーに次に何をしたいかを尋ねる必要があります。プログラムは、ポケモンを戦わせる以外は、自分でモンスターと戦う、ポケモン スタイルのバトル RPG です。

私が探しているのは、ポケモン/ファイナル ファンタジーの戦闘スタイルです。

これは戦闘を処理する私のサブです:

  Private Sub Battle(ByVal Name As String, ByVal life As Integer, ByVal damage As Integer)

    lbl_MonsterName.Text = Name
    mobCurrHealth = mobMaxHealth
    lbl_MonsterHP.Text = mobCurrHealth & " / " & mobMaxHealth
    bar_monsterHP.Value = mobCurrHealth
    bar_monsterHP.Maximum = mobMaxHealth


    txtbx_Action.AppendText(Environment.NewLine & "You find a " & Name)
    lbl_MonsterName.Visible = True
    lbl_MonsterHP.Visible = True
    bar_monsterHP.Visible = True

    wait(2000)

    txtbx_Action.AppendText(Environment.NewLine & "What would you like to do?")
    btn_Attack.Visible = True
    btn_Run.Visible = True

'Here I want the program to wait for button input, but i still have to find a way to do that        


End Sub

「何をしたいですか」という行の後に、2 つの (3) ボタンが表示されます。

  • 攻撃
  • 走る
  • (在庫)

ただし、ご覧のとおり (何が問題なのかは理解していますが、修正方法がわかりません)、ボタンが表示された後、サブバトルが終了します。

これらのボタンのいずれかが押されるまで潜水艦を待機させ、それに応じて動作させたい.

これどうやってするの?


編集:

これは私が使用するコードで、サブ「バトル」が呼び出されます。

   Private Sub btn_Adventure_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btn_Adventure.Click

    btn_Adventure.Visible = False

    txtbx_Action.Visible = True

    Dim rng As New Random
    Dim MobGen As Integer = rng.Next(1, 4)

    Select Case MobGen

        Case 1
            mobName = "Rat"
            mobMaxHealth = 5
            mobDamage = 2
        Case 2
            mobName = "Bat"
            mobMaxHealth = 7
            mobDamage = 3
        Case 3
            mobName = "Snake"
            mobMaxHealth = 9
            mobDamage = 4
        Case 4
            mobName = "Wolf"
            mobMaxHealth = 11
            mobDamage = 5

    End Select

    txtbx_Action.AppendText(Environment.NewLine & "You run around the forest trying to find something to kill")
    wait(1500)
    Battle(mobName, mobMaxHealth, mobDamage)


    btn_Adventure.Visible = True

End Sub

また、現在のプログラムの扱い方が非常に間違っていると思われる場合は、改善方法を教えてください。これは、vb.net 言語をもう少しよく学ぼうとする趣味のプロジェクトなので、アドバイスや建設的な批判は大歓迎です。

4

6 に答える 6

3

Buttons イベントは、探しているように見えるボタンをクリックすると発生します。私は実際に自分の成長のためにポケモンを書き直し始めており、button_click イベントを使用しています。

Button_Click サブルーチンは、ボタンがクリックされたときに実行されるサブルーチンです。プログラムがホバリングし、入力を待っているときにボタンがクリックされると、プログラムはクリックされたボタンに関連付けられたサブにジャンプします。

「button_click」サブを生成するには、フォームを表示しているときにボタンをダブルクリックして、「Button_Click」サブを自動的に生成します。他にも方法はありますが、個人的には使いにくく、間違いやすいと思います。

ここで何が起こるかというと、「バトル」サブが終了し、バトルがセットアップされます。プログラムはホバリングし、何かが起こるのを待っています。ボタンの 1 つをクリックすると、プログラムはクリックされたボタンのサブにジャンプします。ボタンが押されるまでプログラムがループを保持する必要はなく、既存のバトルサブにコードを追加する必要はありません (終了させるだけでかまいません)。

始めるのに役立つ小さな例を次に示します。button_click サブルーチンを埋めるコードは、独自の目的に合わせて微調整するものですが、設定はこれと非常によく似ているはずです。Visual Basic 2010 Express と書かれています。

Private Sub btn_Attack_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btn_Attack.Click
    If mobCurrHealth > 0 And youCurrHealth > 0 Then
        'Both the monster and you are alive
        'Execute attack code
    End If
End Sub

Private Sub btn_Run_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btn_Run.Click
    If mobCurrHealth > 0 And youCurrHealth > 0 Then
        'Both the monster and you are alive
        'Execute run code
    End If
End Sub

重要な行は、おそらく自動的に生成されるサブ宣言行です。ボタンをダブルクリックしてサブを自動的に生成しない場合は、サブをアクティブにするボタンに「ハンドル」が設定され、その後に「.Click」が続くことを確認してください。ボタンが押されたら何をしたいかはあなた次第です。上記の例では、あなたとモンスターの両方がまだ生きていることを確認しますが、それは何でもかまいません。

ゲーム開発頑張ってください!

于 2013-05-24T15:10:22.693 に答える
3

更新: 使用await

私は、この種の状況を処理するための潜在的により良い方法を提案する TechEd セミナーに参加していますasync。こちらのデモを参照してください:チャネル 9: ヒント 3: タスクを返す API でイベントをラップし、それらを待機します

基本的に、イベントを でラップしてawaitから、UI スレッドにイベントの完了を (ハングさせずに) 待機させることができます。これは、複雑な状態を追跡する必要なくストーリーボードを作成するための優れた方法です。すべてのシナリオで機能するわけではありませんが、従来の状態ベースのソリューションよりもはるかに単純な代替手段である可能性があります。


状態ベースのアプローチ

これについてあなたが考えている方法は非常に直感的ですが、まったく正しくありません。一般にプログラミングは、一連の異なる状態の間を遷移するものと考えることができます。これは基本的に、さまざまなコントロールを表示および非表示にするときに行っていることです。つまり、ある状態から次の状態に暗黙的に移行します。

その暗黙の状態変更を明示的にすることが最も役立つと思います。ゲームが「休止」できるさまざまな状態を定義し、ユーザーの入力に応じて、ある状態から次の状態に移行できます。

したがって、たとえば、CurrentState という名前のクラス レベルのプロパティと、表現したいさまざまな状態を含む列挙型を定義できます。コントロールのオンとオフの切り替えは、ゲームの状態が変化したときに発生するイベントの結果として発生する可能性があります。

CurrentState プロパティを使用すると、ゲームの状態を検出し、同じ入力に対して異なる応答をすることができます (問題がある場合)。明らかに、私はあなたのコード全体にアクセスすることはできませんが、うまくいけば、以下のコードが刺激的であることがわかります. 創造的な判断を下す必要があることを認識してください。以下のコードを必ずしもコピーして貼り付けて、ゲームをそれに適合させる必要はありません。

ゲーム状態の列挙。これをアセンブリ レベル (クラス外) で定義します。

Public Enum GameState
    Adventure
    Battle
    BattleCompleted
End Enum

ゲーム クラス (CurrentState プロパティ、StateChanged イベント、State の使用方法の 1 つを示すスタブ メソッドを含む):

Public Class Game

    ' This defines your custom event which will be
    ' raised when the CurrentState property changes
    Public Event GameStateChanged As EventHandler(Of GameStateChangedEventArgs)

    Private _currentState As GameState = GameState.Adventure
    Private Property CurrentState() As GameState
        Get
            Return _currentState
        End Get
        Set(ByVal value As GameState)
            ' Don't raise GameStateChanged if setting the GameState to the same value
            If value = _currentState Then Exit Property

            ' If your application code changes the CurrentState
            ' property, raise the GameStateChanged event
            Dim l_oldState = _currentState
            _currentState = value
            RaiseEvent GameStateChanged(Me, New GameStateChangedEventArgs(l_oldState, _currentState))
        End Set
    End Property

    ' This is the event handler for your GameStateChanged event.
    ' When the game state changes, you can respond by updating the UI.
    Public Sub Game_GameStateChanged(ByVal sender As Object, ByVal e As GameStateChangedEventArgs) Handles Me.GameStateChanged
        If e.ToState = GameState.Adventure Then
            ' Turn on adventure mode buttons, etc
        ElseIf e.FromState = GameState.Adventure Then
            ' Turn off adventure mode buttons, etc
        End If
        If e.ToState = GameState.Battle Then
            ' Turn on battle monster controls, etc
        ElseIf e.FromState = GameState.Battle Then
            ' Turn off monster controls, etc
        End If
        If e.ToState = GameState.BattleCompleted Then
            ' Turn on post-battle controls, etc
        ElseIf e.FromState = GameState.BattleCompleted Then
            ' Turn off post-battle controls, etc
        End If
    End Sub

    ' Now, all you need to do is set the state of your game...
    Private Sub Adventure()
        Me.CurrentState = GameState.Adventure

        Battle()
    End Sub

    Private Sub Battle()
        Me.CurrentState = GameState.Battle

        ' Do the battle

        PostBattle()
    End Sub

    Private Sub PostBattle()
        Me.CurrentState = GameState.BattleCompleted
    End Sub

End Class

StateChanged EventArgs クラス。これは完全にオプションですが、状態遷移を処理する際の柔軟性が少し向上します。

Public Class GameStateChangedEventArgs
    Inherits EventArgs

    Private _fromState As GameState
    Public ReadOnly Property FromState() As GameState
        Get
            Return _fromState
        End Get
    End Property

    Private _toState As GameState
    Public ReadOnly Property ToState() As GameState
        Get
            Return _toState
        End Get
    End Property

    Public Sub New(ByVal fromState As GameState, ByVal toState As GameState)
        _fromState = fromState
        _toState = toState
    End Sub

End Class

これがプログラムを設計する唯一の方法ではありませんが、イベントベースの設定で作業する場合に役立つアーキテクチャの 1 つです。

于 2013-05-24T14:23:47.910 に答える
2

Windows GUI プログラムが実際にどのように機能するかについての基本的な理解が不足しているようです。次のようなコード行を含める場合:

button.Visible = true;

その場でボタンを実際に表示するわけではありません。Windows フォーム フレームワークは、ボタンを表示する必要があることを示すフラグを設定し、ボタンの再描画を要求するメッセージをボタンのメッセージ キューに送信します。コードが UI スレッドから実行されている場合 (ここではそのようです)、そのようなメッセージを受信して​​処理する前に、制御をオペレーティング システムに戻す必要があります。

あなたのアプローチの主な欠点は、単一の関数内ですべてを実行しようとしていることです。現実的には、おそらくプログラム全体を別の方法で構造化する必要があります。Cyborgx37の答えには正しい基本的な考え方がありましたが、あなたはそれをよく理解していなかったかもしれません。

基本的な考え方は、プログラムには、ゲーム ロジック全体の特定のチャンクを個別に処理するさまざまな関数と、ゲームの現在の状態を常に定義する変数とデータ構造のコレクションが必要であるということです。そして、これらの関数は、GUI イベント処理が機能する方法を適切に考慮する必要があります。

概要を見ていきましょう。これは正確ではありませんが、一般的には、やりたいことにかなり近いはずです。

ゲームを開始すると、ゲームの開始に適した方法で、変数とデータ構造 (以降、「ゲーム状態」と呼びます) を初期化します。これには、ディスクやデータベースからの情報のロード、またはコードによる動的な作成が含まれる場合があります。これには、グラフィックス データ、サウンド データなどが含まれます。

次に、ゲームのディスプレイを作成します。ディスプレイの作成とディスプレイの再描画は 2 つの異なるものであることに注意してください。

「ディスプレイの作成」とは、(必要に応じて) ウィンドウを開く、必要なボタンなどの UI コントロールを追加するなどのことを意味します。

それに比べて、「ディスプレイの再描画」は、実際にピクセルをプッシュするプロセスです。プログラムがグラフィック ライブラリ呼び出しを使用して画面上の何かを更新する場合、コードは、プログラムが "PAINT" メッセージを受信したときに呼び出される関数を実装する必要があります。

厳密に Windows GUI アプリケーションとしてゲームを実行している場合は、「画面の再描画」関数を明示的に作成する必要がないことに注意してください。一般に、すべてが UI コントロールによって描画される場合、UI コントロールは必要ありません。

この時点で、おそらく画面再描画イベントを強制したいと思うでしょう。Windows GUI アプリケーションでは、これは通常、「無効化」メッセージをウィンドウに送信することによって行われます。これが処理されると、必要に応じてすべてが再描画されます。標準の UI コントロールのようなものは、通常、プログラムから特別な操作をしなくても、自分自身を再描画します。

ここで、「ゲームを開始」をクリックするだけであっても、続行するために何らかのユーザー入力が必要になる可能性があります。ボタンを選択している場合、各ボタンは、その特定の選択に固有のコードを含むイベント ハンドラー関数にリンクする必要があります。そのコードは、必要に応じてゲームの変数とデータ構造を更新する必要があります。

Cyborgx37は、単一の変数がゲームの状態を指定する例を示しました。実際には、その変数は氷山の一角であり、他のあらゆる種類の変数やデータ構造が関与します。基本的なゲームの状態は、「開始を待機中」や「ユーザーが ATTACK を押した」など、あらゆる種類のものを示すことができます。追加の変数は、攻撃されているモンスター、プレイヤーとモンスターがいるゾーン、プレイヤーの現在の健康状態などを示す場合があります。

「ゲームの状態」を説明するために集められるすべての基本情報は、おそらくクラスとしてまとめて整理する必要があります。これには、個別に維持する必要がある UI セットアップなどの詳細を含めないでください。

ユーザー入力が画面上で何かを変更する必要があることを意味する場合、イベント ハンドラーはゲームの状態を更新し、関連する UI コントロールを削除/追加/変更する必要があります。特定のゲーム状態に必要な画面コントロールを設定できる関数が必要になるでしょう。これらのボタンが常に適切なイベント ハンドラー関数で構成されていることを確認してください。

ユーザー入力が、画面に動的に描画されたものを更新する必要があることを意味する場合、ウィンドウ (または特定のコントロール) に「無効化」メッセージを送信する必要があります。

あなたのコード サンプルには、いくつかの場所でwait()への呼び出しがありました。スレッド全体を失速させているため、これは通常、一時停止を行う間違った方法です。しかし、それは基本的な根底にある考え方が間違っているという意味ではありません。2 つのことが起こっている間に、ある程度の時間を置きたいと思うのはまったく問題ありません。そこでタイマーの出番です。

タイマーを使用すると、時間の経過に対応するために必要に応じてゲームの状態を更新できます。これは多くの理由で必要になる可能性がありますが、ゲームの場合、最も一般的なのはアニメーションです。たとえば、1 秒間に 5 回アニメーション化する必要がある画像があるとします。5hz で刻むように設定されたタイマーを作成し、イベント ハンドラー関数でアニメーション フレーム インデックスをインクリメントし、「無効化」メッセージをウィンドウまたはコントロールに画像とともに送信します。

複数のタイマーを異なる周波数に設定できますが、可能な場合は組み合わせて使用​​することをお勧めします。画面上にアニメーション化する必要があるさまざまなものがある場合は、ハンドラー関数が各項目を個別にチェックする単一のタイマーを使用します。

関係することはもっとたくさんありますが、これらは正しい軌道に乗るために必要だと私が考える基本です。

于 2013-05-25T01:00:33.727 に答える
2

アプローチを少し変更する必要があります。各ボタンが特定の作業を行うことを考える必要があり、誰かを待つべきではありません。

あなたの btn_Adventure.Click で、戦闘を開始する必要があります。

Private Sub btn_Adventure_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btn_Adventure.Click

    GetModToAttack()
    InitialiseUI() ' Show the btnAttack, btnRun, show the "What would you like to do text", ...

End Sub

UI はそれ自体でユーザー入力を待機し、ユーザーがボタンをクリックすると、アクションを処理します。

Private Sub btn_Attack_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btn_Attack.Click

    ' Handle attack action
    ' Handle UI

End Sub
于 2013-05-24T17:10:09.517 に答える
0

メイクVarAVarBクラスレベル:

Private VarA, VarB As Integer ' Or whatever type

次に、ループの開始ロジックの関数を追加します。

Private Sub NextIteration() ' Give this a better name, or even make it part of Update
    If VarA <= 0 OrElse VarB <= 0 Then
        ' Loop’s over; hide the buttons or something
    Else
        Update()
    End If
End Sub

次に、すべてのアクション ボタンを個別に処理し、アクションを実行して、各ハンドラーNextIteration()の最後で呼び出します。Click呼び出しNextIteration()て開始します。

于 2013-05-22T13:07:58.860 に答える