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

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

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



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


スポンサーサイト

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






Chapter.69 [ 値渡しと参照渡し ]

■VBAは何渡し?

皆さんは、値渡しと参照渡し、と言われて、それが何のことだかわかるでしょうか。

色んなところで目にはするけど、一体なんのことだかいまいちよくわからない、という人も多いのではないでしょうか。

プログラミング言語によっては、『値渡し』とか『参照渡し』という言葉自体が無いものもあります。しかし、両者の違いを理解しているかどうかは、大抵どのような言語を用いる場合にも、非常に大きな意味を持ちます。
そして、この値渡しと参照渡しを本質的に理解することは『メモリ』についての理解を深めることにつながります。
C言語などの場合には、メモリに関する知識がないとどうにもならないといった雰囲気がありますが、VBAではその辺が曖昧でも、意外とプログラムが組めてしまいます。

値渡しと参照渡しを理解したからといって、必ずしもメモリに関することが全て理解できたとは言えないのですが、それでも、知っているかいないかの違いは大きいです。がんばって覚えてしまいましょう。


それでは早速、値渡しと参照渡しの違いについて考えてみましょう。

まず、次のようなプログラムがあったとします。

Sub sProc(N As Integer)

    N = N + 100

End Sub

なんとも簡易なプログラムですね。その構造は非常に単純です。

このsProcというプロシージャは、整数型の引数をひとつ受け取り、そこに100を足し算するだけのプロシージャです。なんとも単純ですね。

それでは別のプロシージャから、このsProcを呼び出してみることにします。

Sub main()

    Dim Number As Integer
    
    Number = 0
    
    Call sProc(Number)
    
    MsgBox Number
    
End Sub

このmainというプロシージャの最後で呼び出されているメッセージボックスで、どのような値が表示されるか、想像ができますか?

即答できた人は中々優秀です。
このケースでは、『 100 』というメッセージが出るはずですね。

先ほどのコードでは、Callを使ってsProcを呼び出しています。当然、引数は括弧でくくった状態で、sProcに渡しています。


さて、それでは、もしも次のようにコードを書き換えたら、一体どのようなメッセージが表示されるでしょうか。

Sub main()

    Dim Number As Integer
    
    Number = 0
    
    sProc(Number) 'Call をつけずに呼び出す
    
    MsgBox Number
    
End Sub

これも即答できたという人は、基礎がそこそこしっかりできている証拠です。

この場合には、メッセージは『 0 』が表示されます。
同じプロシージャを呼び出しているだけなのに、Callを使ったかどうかで、結果は全く違ったものになります。一体なぜこのようなことが起きるのでしょうか。

実は、これこそが値渡しと参照渡しの違いなのです。


■なぜ結果が変わったのか

VBAでは、プロシージャ間で引数を用いて変数の受け渡しをする際に、原則として参照渡しでデータをやり取りします。前者の例がこれにあたります。

参照渡しを考える場合には、変数をやり取りする際に住所をやり取りしていると考えるとわかりやすいと思います。
今回の例で言えば、引数に渡す変数として使われているのはNumberという変数ですね。これが参照渡しでsProcに渡されています。

このとき、sProc側が受け取っているのは、実は変数の存在する住所(場所)なのです。
住所を受け取ったsProcは、変数がどこに住んでいるのかを知ることができます。ですから、その場所に100を足し算する、という処理を行うことができるのですね。


これに対して、後者では、値渡しで引数が渡されています。
値渡しでは、その名が示す通り、値だけがデータとして渡されます。この場合は、sProcが変数の住所を知ることができません。sProcが受け取るのは、そのときの変数Numberの値、つまり『 0 』という値だけなのです。

受け取った値に100を足し算しても、変数Numberには何の影響もありません。なぜなら、変数Numberがどこに住んでいるのかなんてsProcにはわからないからです。住んでいる場所がわからないのに、そこに変更を加えることはできないのです。

ですから、後者の例では、メッセージとして『 0 』が表示されたわけです。変数Numberには、このとき何の作用も起きていなかったというわけです。


ここで言う住所とは、すなわちメモリのどこにデータが存在するか、ということとイコールです。実際にパソコンの中では、広大なメモリの畑の中で、どこにどのようなデータを置いておくかということが厳密に管理されています。
参照渡しの場合には、そのデータが存在する場所という情報が渡されます。これに対して値渡しでは、その場所にどんなデータがあるかという情報だけがコピーされ、コピーされたデータが渡されています。

この違いは、一見するとわかりにくいかもしれませんが、じつはかなり重要なのです。


■ Call と括弧と引数の微妙な三角関係

VBAでは、プロシージャの呼び出しを行う際に、値渡しをするのか参照渡しをするのかは、プロシージャの呼び出し方などによって変わってきます。

そして、ここに影響するのが、『 Call 』、『 括弧 』、『 引数 』の3つの要素です。

まずはCallから見てみましょう。

Callを使う場合のルール

Callを使う場合、引数を括弧でくくらなくてはいけない
Callを使った場合、原則として参照渡しとなる

Callステートメントは、実は使わなくてもプロシージャを呼び出すことができます。(これについては後で詳しく説明します)
ただし、Callステートメントを使う場合には、絶対に引数を括弧でくくらなくてはいけません。

そして、プロシージャを呼び出す際に、絶対にCallステートメントを使わなくてはいけない、ということはありません。例えば、次のコードはどちらも全く同じように解釈できます。

① Call sProc(Number)

② sProc Number

Callステートメントを使わずにプロシージャを呼び出しているのが②ですね。プロシージャ名に続けて半角スペースを打ち、そのまま引数を指定します。この場合には、引数はVBAの原則どおり参照渡しでやり取りされます。


次に括弧についてです。

■括弧が引数に与える影響

Callなしで括弧を使うと値渡しになる
・戻り値が必要な場合は括弧を使わなくてはいけない

プロシージャを呼び出す際に、括弧を使うかどうかで引数を渡す形式が変わります。

Callを使わずにプロシージャを呼び出すとき、括弧で引数をくくった場合には値渡しになります。先ほどメッセージで『 0 』が表示されてしまったときが、まさしくこれですね。

そしてもうひとつ重要なのが、戻り値が必要な場合には、引数を括弧でくくらなくてはいけないというVBAの仕様です。
例えば、次のようなコードは間違いです。

間違っている例
    L = Int 1.234

この場合、恐らく変数 L には、Int 関数によって小数点を切り捨てた数値が入ってほしいはずです。しかし、先ほども書いたように、戻り値が必要な場合には関数の呼び出しに括弧をつけなくてはいけません。自動構文チェックが有効になっている場合にはエラーが発生して、コードが赤くなってしまうはずです。

390.gif

これを、エラーが起きないように正しく書き直すと次のようになります。

正しい記述の例
    L = Int(1.234)

こうすれば、キチンと変数 L に Int 関数が返す戻り値が入るようになります。当然、構文エラーも起きません。


そしてデータの渡し方に影響する最後の要素として、引数があります。

例えば、次のようなファンクションプロシージャがあるとします。

Function SumValue(valueA As Long, valueB As Long) As Long

    valueA = valueA + valueB
    
    SumValue = valueA
    
End Function

この SumValue というプロシージャは、引数をふたつ受け取り、その合計値を返してくれるだけという、全く使い道のないプロシージャです。

このプロシージャの中では、引数として受け取ったデータをそのまま計算に使っていますね。

valueA = valueA + valueB

ここです。

このようなコードでは、参照渡しでデータを受け取った場合には、元となっているデータのほうも書き換えてしまいます。つまり、第一引数 valueA に渡された変数のデータを一緒に書き換えてしまうということです。

L = SumValue(変数A , 変数B)

このように呼び出した場合には、変数 A が書き換えられてしまうわけです。

変数 A が、参照渡しされたことによって書き換えられてしまうと、その後の処理に影響が出てしまうかもしれません。後から変数 A を使ったときに、予期せぬ数値が入っていて計算がおかしくなるというのは容易に想像がつきます。

そこで、このような場合などでは、引数の受け取りを行うプロシージャ側で値渡しを明確にしておくことができます。そのためには、引数の宣言時に『 ByVal 』というキーワードを使います。

Function SumValue(ByVal valueA As Long, ByVal valueB As Long) As Long

    valueA = valueA + valueB
    
    SumValue = valueA
    
End Function

このように引数を宣言しておけば、自動的に値渡しでデータが引き渡されます。よって、先ほどのように変数 A が勝手に書き換えられてしまうことはなくなります。

このように、引数のデータを書き換えてしまう可能性がある場合には、受け取る側のほうで、引数を値渡しで受け取るように明示しておくべきでしょう。こうすることで、予期せぬエラーや、思わぬ不具合を事前に回避することができるのですね。


■まとめ

さて、結構長い文章でしたが、皆さんついてこれているでしょうか。

値渡しと参照渡しは、あまり理解していなくてもとりあえずコードを書いていくことができてしまうため、意外と認知度が低いと思います。

これは、VBAが非常に親切、というか、難しいことをそれほど知らなくてもプログラムが組めるように作られているためです。多くの言語では、このようなメモリの参照に関わることは非常に重要視され、その理解度によって習熟度を判断することも多いのです。
しかしVBAが非常に親切なつくりになっているがために、我々はそのことをあまり意識しなくても、それなりにコードを記述していくことができてしまいます。

メモリの話はとりあえず置いておくとしても、値渡しと参照渡しの違いについては理解しておいたほうがいいでしょう。APIを使う場合にも、この渡し方の違いが重要になるケースは多いです。
いまいちピンとこない人もいるかもしれませんが、動作に違いが出るのはどんな場合でも困った問題を引き起こしますから、ゆっくり確実に理解していってみてください。



■格言

VBAでは原則参照渡しとなる
参照渡しはメモリの住所を渡す
値渡しはデータのコピーを渡す
ByValを使って値渡しを明示できる


あまり気にしすぎる必要はないですが、不具合が起きたときなどにこれらの知識が重要になることがありますね。

関連記事






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ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。