ExcelVBAゲームプログラミング?

初心者でもきっとできる!
Excelさえ持っていれば特別なソフトは不要!
すぐにでも始められる簡単ゲームプログラミング!
今すぐ始めよう!

サンプルやゲームのダウンロードができる別館も好評運営中です。
ご意見やご質問、ゲームの感想等は掲示板までお気軽に。是非、皆さんの声を聞かせてください。運営、開発の励みになります。



各種ダウンロードはコチラ ↓ 意見・感想・質問はコチラ ↓
影倉庫 Shadow warehouse サポート掲示板
ブログの全体像はコチラ ↓ リンクのページはコチラ ↓
サイトマップ 自分本位なリンク


スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。






Chapter.35 [ 移動処理その2:DoEvents ]

■おさらい

今回は、前回の続きです。
前回はキャラクターの移動処理について、その考え方を解説しましたね。テレビアニメの要領で、少しずつキャラクターを移動することが大切だと、解説しました。具体的には、繰り返し処理を使って、1回ループするごとに少しずつキャラクターを動かしていきます。

以前紹介した、『同期処理を取り入れたメインループ』を覚えているでしょうか。これから先、全てこのコードを主軸にすえてコードを記述していきます。これをしっかり理解していないとこれから先に進むのは難しいですので、わからない人は先にこれをしっかり理解しておいてくださいね。これについては以前の講座で詳しく解説しています(Chapter32Chapter33を参照)。

まずは先述の『同期処理を取り入れたメインループ』を見てみましょう。

Sub Main()
    Dim Flg As Boolean
    Dim Stm As Long
    Flg = False
    Do Until Flg
        Stm = GetTickCount
        'ゲームの処理
        Do
            Call Sleep(1)
        Loop Until GetTickCount - Stm > 1回のループ時間
    Loop
End Sub

このコードのポイントをおさらいしておきましょう。

このコードでは、最初に『Flg』というBoolean型の変数を宣言していますね。この変数はループの終了を定義する重要な変数です。メインループが始まる前に、まずこの変数にFalseを代入しています。そして、そのあと登場するDo文がメインループになるわけですが、そのメインループの終了条件が『FlgがTrueになったとき』となっています。
つまり、繰り返し処理を終了したいときには、変数FlgTrueを代入すればいいのですね。

それからもうひとつ。『1回のループ時間』となっている部分。ここに1回あたりのループ時間を定義します。時間の単位がミリ秒単位となっている点に注意しましょう。
ミリ秒とは1000分の1秒単位を表します。ですから1秒は1000ミリ秒です。5秒なら5000ミリ秒ですね。
1回のループ時間を1秒単位にしたいときには、この『1回のループ時間』に『1000』を指定します。0.5秒単位でループしたいなら『500』です。間違えないようにしましょうね。

それでは実際にキャラクターの移動処理を記述していくことにしましょう。
今回は1回ループするごとに、キャラクターを1ポイントずつ、下に向かって移動する場合を考えてみます。


■繰り返し処理で移動する

今回キャラクターの役割を果たすのは、前回ゲーム画面の左上に配置した『イメージコントロール』です。

180.gif

このイメージコントロールは、特に名前などを変更していないので、コードで記述するときは『Image1』という名前で指定します。これはキチンと覚えておいてくださいね。

そして、先ほども書いたように、今回はキャラクターを1ポイントずつ下に向かって移動させます。下に向かって移動するということは、縦方向の移動になります。縦方向の位置情報を管理しているのは『Topプロパティ』でしたね。

つまり、1回ループするたびに、Image1というイメージコントロールの、Topプロパティを少しずつ変化させればいいわけです。
1回のループで移動する距離を大きくすれば、一度に長い距離を動くので、見た目はすばやく移動しているように見えます。反対に、1回のループで移動する距離を小さくすれば、見た目はゆっくり移動しているように見えますね。
今回は、1回のループで、1ポイントずつ移動するようにします。このことををコードで表すと次のようになります。

Image1.Top = Image1.Top + 1

このように、Image1Topプロパティに、1を加えて新しく設定し直します。こうすることで、1回ループするたびに、毎回Topプロパティがプラス1ずつ増えていくというわけです。

ですが、このままでは、プログラムが永遠に止まりません。たとえ画面上からイメージコントロールが見えなくなってしまっても、このままだと計算上はずっと下の方向に動いていってしまいます。
そこで、どういうときに終了するのかを定義しておきます。

今回は、イメージコントロールの縦位置、つまりImage1Topプロパティが、250を超えるところまで移動してみることにしましょう。

先ほども書いたように、メインループが終了する条件は、変数FlgTrueを代入することです。ですから、Image1Topプロパティが250を超えたときに、変数FlgTrueを代入すればいいのです。これをコードで表すと次のようになります。

If Image1.Top > 250 Then
    Flg = True
End If

If文を使って、縦位置が250を超えているかどうかを毎回チェックします。もし、縦位置が250を超えていた場合には、Do文の終了条件を満たすように設定すればいいわけです。
これで、イメージコントロールの縦位置が、250ポイントより大きくなった時点で、メインループが終了し、結果的に処理が止まるようになります。

さて、とりあえずこれで移動に関する処理はOKです。
ただし、もうひとつ、とても大切なことが残っています。これをキチンとやっておかないと、原因不明の不具合に悩まされることになります。実際、私はよくこれでハマって何時間も悩んだりしました。


■DoEvents様登場

VBAのコードが実行されているときというのは、原則としてプログラムがパソコンの処理を占有しています。
わかりやすく言うと、画面の更新など、通常なら意識しなくても行われているようなパソコンの根本的な処理が、行われないということです。これはどういうことなのでしょうか。

例えば、普段パソコンを使っているとき、ウィンドウのタイトルバーをドラッグしながら動かすと、自由にウィンドウの場所を移動できますよね。フォルダをたくさん同時に開いてしまったときなどは、この機能が非常に便利です。
人間から見るとこの処理は、ただウィンドウが動いているだけです。ですがパソコンから見ると少し違います。
パソコンはこのウィンドウの移動という操作が行われると、いったん今表示されている画面を消してから、移動先に全く同じレイアウトの新しい画面を再表示しています。ユーザーがウィンドウを移動している間ずっと、消して描いて、消して描いて、を繰り返しているのです。

パソコンの根本的な処理とは、例えばこのような処理を言います。そして、VBAのコードが実行されているときというのは、これらの処理が行われなくなってしまうのです。これは困った問題です。

そこで、この問題を回避する方法として『DoEvents』という関数がVBAにはキチンと用意されています。
DoEvents関数は、呼び出された瞬間に、オペレーティングシステム(根本的な処理を行う部分)に処理を明け渡します。こうすることによって、ウィンドウの再描画などが正常に行われるようになります。

メインループの中でキチンとDoEvents関数を呼び出すようにしていないと、画面の更新などが正常に行われません。このため、せっかくキャラクターを移動するコードを実行させているのに、画面上の見た目が全く変わらなくなってしまいます。ずーっとキャラクターは最初の位置から動かないわけです。
内部的にはキチンと計算などが行われ、設定が変化しています。しかし見た目が変わらないとあっては意味がありません。ループするたびに、きちんとDoEvents関数を呼び出すようにしておかなくてはいけません。

コードの記述はどこも間違っていないのに、画面上でキャラクターが移動してくれないときなどは、このDoEvents関数の呼び出しを忘れてしまっていることが多いです。画面の更新が行われないわけですから、移動してくれないのは当たり前です。毎回少しずつ移動させるわけですから、DoEvents関数を毎回呼び出すように設定しておきましょう。

これは非常に大切なことです。ついつい忘れてしまいがちなことですから、しっかり覚えておいてくださいね。


■コードの全容

さて、ちょっと前置きが長くなりましたが、メインループに移動処理を加えた、完成版コードを載せます。このコードを、『標準モジュール』に記述しましょう。新しく標準モジュールを準備するときは、メニューの『挿入』から『標準モジュール』を選択すればOKです。これで空の標準モジュールができるはずですから、そこに下のコードを記述すればいいわけです。

Declare Sub Sleep Lib "kernel32.dll" (ByVal dwMillsecounds As Long)
Declare Function GetTickCount Lib "kernel32.dll" () As Long

Sub Main()
    Dim Flg As Boolean
    Dim Stm As Long
    Flg = False
    Do Until Flg
        Stm = GetTickCount
        With UserForm1.Image1 '①
            .Top = .Top + 1 '②
            If .Top > 250 Then '③
                MsgBox "移動完了"
                Flg = True '④
            End If
        End With
        DoEvents '⑤
        Do
            Call Sleep(1)
        Loop Until GetTickCount - Stm > 50 '⑥
    Loop
End Sub

ちょっと長いですので大変ですが、ゆっくりひとつひとつ見ていきましょう。

メインループの中で、Withステートメントを使っている部分がありますね。①の部分です。そこには『With UserForm1.Image1』と記述されています。
以前、Withステートメントについては解説しましたね(Chapter23を参照)。『End With』という記述があるまでは、ピリオドに続けてプロパティを記述するだけで同様の設定を行うことができます。これにより無駄を省き、簡略化することができるのでしたね。

そして②のところで、Image1Topプロパティを、1回ループするたびに1ポイントずつ増やしていきます。これにより、イメージコントロールの縦位置が、毎回少しずつ下に移動していきます。

③の部分では、イメージコントロールの現在の位置が、250を超えていないかどうかチェックしています。もしもイメージコントロールの縦位置が、250よりも大きなっていた場合には、④で示すように、メインループの終了条件である『変数FlgへのTrueの代入』を行います。これで、メインループが終了し、結果的にコードが止まるわけです。

忘れてはいけないのが⑤の部分。メインループの間は毎回キチンとDoEvents関数を呼び出すようにしておきましょう。これがないとキャラクターは移動しているように見えませんからね。

⑥では、1回のループをどれくらいの早さで行うかを設定しています。今回はここで50ミリ秒を設定しています。50ミリ秒で1回ループするということは、1秒が1000ミリ秒ですから、1秒間におよそ20回ループすることになります。

どうですか? コードの内容はキチンと理解できたでしょうか。


■仕上げ

さて、最後の仕上げです。
先ほどのコードで、移動処理は完璧です。あとは、ユーザーフォームに設置したコマンドボタンから、このコードが呼び出されるようにすればいいのですね。これはじゃんけんゲームで使ったのと同じ手法です。

コマンドボタンのクリックイベントに、次のように記述しましょう。

Private Sub CommandButton1_Click()
    Call Main
End Sub

これで、コマンドボタンをクリックしたときに、先ほどのコードが呼び出されるようになりました。フォームを実行して表示させコマンドボタンをクリックすれば、赤い機体が下の方向に移動していくはずです。一定の場所に達すると、メッセージが表示され、処理が終了します。

さて、うまくいったでしょうか。

前回と今回の2回で、非常に単純な移動の処理について解説してきました。下に向かって移動するだけという単純な処理でも、結構考えなくてはならないことがたくさんありましたね。
ちょっと面倒な気がしたかもしれませんが、どのような複雑な移動処理であっても、考え方は同じです。今回の内容をしっかり理解していれば、これから先の講座でも、すんなり理解することができるでしょう。

途中、DoEvents関数の呼び出しなど、とても大切な仕組みが出てきました。焦らず、ひとつひとつ確実に覚えていってください。


■格言

1回のループでどのくらい移動するか定義する
どのタイミングで終了するかキチンと定義する
DoEvents関数をキチンと呼び出す


覚えることがたくさんあって大変です。
関連記事






Comment

Name
E-mail
URL
Comment
Pass  *
Secret? (管理者にだけ表示)

メールフォーム

影斬に物申すという方はこちら

名前 :
メール:
件名 :
本文 :

可能な限り要望には応えますが、必ず返信や回答ができることを、保障するものではありません。
ご了承ください。

Chapters

コンテンツ一覧


■Chapter 一覧■
    全てのChapterの一覧です。
    直接アクセスしたい方はこちらをご利用下さい。

    Chapter.1 [ 知っておくべき心得 ]
    Chapter.2 [ Excelってなんだろう ]
    Chapter.3 [ Excelの基本画面 ]
    Chapter.4 [ VBAとは? ]
    Chapter.5 [ モジュールについて ]
    Chapter.6 [ 変数 ]
    Chapter.7 [ 変数の型と宣言 ]
    Chapter.8 [ プロシージャとスコープ ]
    Chapter.9 [ ゲームつくる様々な手法 ]
    Chapter.10 [ ユーザーフォーム ]
    Chapter.11 [ プロパティウィンドウ ]
    Chapter.12 [ 乱数 ]
    Chapter.13 [ 条件分岐 ]
    Chapter.14 [ ゲーム画面のデザイン ]
    Chapter.15 [ コード記述の基本作法 ]
    Chapter.16 [ じゃんけんゲーム:1 名前をつける ]
    Chapter.17 [ じゃんけんゲーム:2 フォームの起動 ]
    Chapter.18 [ じゃんけんゲーム:3 乱数の種 ]
    Chapter.19 [ じゃんけんゲーム:4 イベント ]
    Chapter.20 [ じゃんけんゲーム:5 引数 ]
    Chapter.21 [ じゃんけんゲーム:6 役判定 ]
    Chapter.22 [ じゃんけんゲーム:7 予測と制限 ]
    Chapter.23 [ Withステートメント ]
    Chapter.24 [ 画像を表示させる ]
    Chapter.25 [ 画像表示の発展形 ]
    Chapter.26 [ 繰り返し処理 For文 ]
    Chapter.27 [ 繰り返し処理 Do~Loop文 ]
    Chapter.28 [ Exitステートメント ]
    Chapter.29 [ フォーム上の位置情報 ]
    Chapter.30 [ API基礎知識 ]
    Chapter.31 [ API補足知識 ]
    Chapter.32 [ メインループを考える ]
    Chapter.33 [ 同期処理の概念 ]
    Chapter.34 [ 移動処理その1:画面設定と考え方 ]
    Chapter.35 [ 移動処理その2:DoEvents ]
    Chapter.36 [ 移動処理その3:キー入力判定API ]
    Chapter.37 [ 条件分岐のさらなる探求 Select Case ]
    Chapter.38 [ アニメーション ]
    Chapter.39 [ 配列変数 ]
    Chapter.40 [ ゲームの初期化 ]
    Chapter.41 [ シューティングゲーム1:ゲーム設計 ]
    Chapter.42 [ シューティングゲーム2:メインプロセス ]
    Chapter.43 [ シューティングゲーム3:構造体 ]
    Chapter.44 [ シューティングゲーム4:定数 ]
    Chapter.45 [ シューティングゲーム5:プレイヤーキャラクター ]
    Chapter.46 [ シューティングゲーム6:ショットを撃つ① ]
    Chapter.47 [ シューティングゲーム7:ショットを撃つ② ]
    Chapter.48 [ シューティングゲーム8:Mod演算子の活用 ]
    Chapter.49 [ シューティングゲーム9:敵キャラクター登場 ]
    Chapter.50 [ シューティングゲーム10:衝突判定 ]
    Chapter.51 [ シューティングゲーム11:衝突の実体 ]
    Chapter.52 [ シューティングゲーム12:敵の攻撃 ]
    Chapter.53 [ シューティングゲーム13:爆発エフェクト ]
    Chapter.54 [ シューティングゲーム14:残機数表示① ]
    Chapter.55 [ シューティングゲーム15:残機数表示② ]
    Chapter.56 [ シューティングゲーム16:スコアの表示 ]
    Chapter.57 [ シューティングゲーム17:タイトル画面 ]
    Chapter.58 [ シューティングゲーム18:ボスキャラクター ]
    Chapter.59 [ シューティングゲーム19:最後の仕上げへ ]
    Chapter.60 [ シューティングゲーム20:いよいよ完成STG ]
    Chapter.61 [ カードゲームで使えるめくり効果 ]
    Chapter.62 [ ラジアンと角度 ]
    Chapter.63 [ ラジアンの活用:円運動 ]
    Chapter.64 [ ラジアンの活用:任意の角度へ移動する ]
    Chapter.65 [ APIによるサウンド再生:基礎 ]
    Chapter.66 [ APIによるサウンド再生:MIDIと多重再生 ]
    Chapter.67 [ APIによるサウンド再生:MCIコマンドとループ再生 ]
    Chapter.68 [ Function プロシージャ ]
    Chapter.69 [ 値渡しと参照渡し ]
    Chapter.70 [ デバッグ1:イミディエイトウィンドウ ]
    Chapter.71 [ デバッグ2:ローカルウィンドウ ]
    Chapter.72 [ デバッグ3:コード実行の中断 ]
    Chapter.73 [ オブジェクトってなんだ ]
    Chapter.74 [ プロパティ・メソッド・イベント ]
    Chapter.75 [ オブジェクト変数 ]
    Chapter.76 [ オブジェクトとコレクション ]
    Chapter.77 [ 特殊な繰り返し:For Each ]
    Chapter.78 [ エラー処理 ]
    Chapter.79 [ On Error と GoTo文 ]
    Chapter.80 [ Resumeステートメント ]
    Chapter.81 [ バイトとビット ]
    Chapter.82 [ ウィンドウメッセージとイベント ]
    Chapter.83 [ 文字列の基礎 ]
    Chapter.84 [ 文字列操作① ]
    Chapter.85 [ 文字列操作② ]
    Chapter.86 [ タイピングゲーム1:仕様を決める ]
    Chapter.87 [ タイピングゲーム2:キー入力検知 ]
    Chapter.88 [ タイピングゲーム3:文字列照合 ]
    Chapter.89 [ タイピングゲーム4:判定関数 ]
    Chapter.90 [ タイピングゲーム5:ゲーム画面設計 ]
    Chapter.91 [ タイピングゲーム6:問題文のソート ]
    Chapter.92 [ タイピングゲーム7:動的配列 ]
    Chapter.93 [ タイピングゲーム8:キーダウンイベント ]
    Chapter.94 [ タイピングゲーム9:正打数の表示 ]
    Chapter.95 [ タイピングゲーム10:タイムの表示 ]
    Chapter.96 [ クリックゲーム1:イベントの種類 ]
    Chapter.97 [ クリックゲーム2:画面設計 ]
    Chapter.98 [ クリックゲーム3:クリック座標検知 ]
    Chapter.99 [ クリックゲーム4:キャラクター準備 ]
    Chapter.100 [ クリックゲーム5:キャラクターの配置 ]
    Chapter.101 [ クリックゲーム6:キャラクター移動とNot演算子 ]
    Chapter.102 [ クリックゲーム7:クリックのヒット判定 ]
    Chapter.103 [ クリックゲーム8:ヒットマークエフェクト ]
    Chapter.104 [ クリックゲーム9:サウンド処理の実装 ]
    Chapter.105 [ クリックゲーム10:マウスカーソルの変更 ]
    Chapter.106 [ ブロック崩しゲーム1:仕様と概要を決める ]
    Chapter.107 [ ブロック崩しゲーム2:基本概念の確認 ]
    Chapter.108 [ ブロック崩しゲーム3:ベクトルとは ]
    Chapter.109 [ ブロック崩しゲーム4:変数や定数の宣言 ]
    Chapter.110 [ ブロック崩しゲーム5:初期化処理の実装 ]
    Chapter.111 [ ブロック崩しゲーム6:ブロックの配置 ]
    Chapter.112 [ ブロック崩しゲーム7:根幹処理とバーの処理 ]
    Chapter.113 [ ブロック崩しゲーム8:線分と線分の交差を判定 ]
    Chapter.114 [ ブロック崩しゲーム9:線分同士の交点 ]
    Chapter.115 [ ブロック崩しゲーム10:ボールの処理 ]
    Chapter.116 [ ブロック崩しゲーム11:最終調整して完成へ ]
    Chapter.117 [ テキストファイル操作基礎 ]
    Chapter.118 [ テキストファイル操作:読み込み編 ]
    Chapter.119 [ テキストファイル操作:CSV読み込み編 ]
    Chapter.120 [ テキストファイル操作:様々な読込編 ]
    Chapter.121 [ テキストファイル操作:バイナリ編 ]
    Chapter.122 [ テキストファイル操作:暗号化編 ]
    Chapter.123 [ テキストファイル操作:復号化編 ]
    Chapter.124 [ クラスモジュールとは ]
    Chapter.125 [ クラスモジュール:メソッド編 ]
    Chapter.126 [ クラスモジュール:プロパティ編 ]
    Chapter.127 [ クラスモジュール:イベント拡張編 ]
    Chapter.128 [ クラスモジュール:イベント自作編 ]
    Chapter.129 [ APIによる描画処理1:ハンドル ]
    Chapter.130 [ APIによる描画処理2:デバイスコンテキスト ]
    Chapter.131 [ APIによる描画処理3:ペン オブジェクト ]
    Chapter.132 [ APIによる描画処理4:ブラシ オブジェクト ]
    Chapter.133 [ APIによる描画処理5:図形描画準備編 ]
    Chapter.134 [ APIによる描画処理6:図形描画実践編 ]
    Chapter.135 [ APIによる描画処理7:画像描画の仕組み編 ]
    Chapter.136 [ APIによる描画処理8:ビットブロック転送編 ]
    Chapter.137 [ APIによる描画処理9:ラスタオペレーション ]
    Chapter.138 [ APIによる描画処理10:マスク描画 概念編 ]
    Chapter.139 [ APIによる描画処理11:マスク描画 実践編 ]


    コードやVBAに関する質問などはサポート掲示板(別館)までお気軽にどうぞ。




fc2 seotool Excel VBA ゲーム プログラミング 講座

Counter

twitter


Shadow BBS - 影掲示板

VBA 関連書籍



上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。