- ベストアンサー
ロールオーバーしたボタンは押したくない
結構分かってきたつもりなので 自分なりに色々駆使したのですが どーも長ったらしいプログラムになるので 簡潔な方法を知りたく質問しました。 (過去ログでどういうキーワードにしたら良いか分からなかったです) 画面上、ある特定の場所にマウスが来ると 予め仕組まれたMCが動く。 ただこれだけなのですが・・・・・ 一つだけ条件があります。 そのボタン上でロールオーバーするのは良いのですが ボタンとして機能してしまうのを防ぎたいのです。 なぜなら、ロールオーバーした時に クリックするとまたMCが最初から動くのが困る。 今は、MCの方に制御を掛けているのですが ボタン機能として何か良い手立てはないでしょうか。 よろしくお願いします。 追伸: 今回は、ちゃんと腰を据えて データー量もきちんと考慮して 無駄なプログラムを省いてのゲーム作りに挑戦したいので。
- みんなの回答 (6)
- 専門家の回答
質問者が選んだベストアンサー
同じく、横から失礼いたします。 ボタンシンボルを使用およびスクリプトを全くなしというわけにはいきませんけれど、ムービークリップの特殊なフレームラベルを使うとご希望の処理に近いことができると思います。 ただし、独自のヒット領域を採用したい場合は、ヒット領域をムービークリップで作る必要があります。 Flash Player 6(作成ツールは Flash MX )からは、ムービークリップをボタンとして使えるようになりました。 単にスクリプトでボタンイベントが使えるようになっただけでなく、ムービークリップそのものにも仕掛けが追加されています。 ムービークリップのフレームに _up ・ _over ・ _down というフレームラベルを付けると、ムービークリップにボタンシンボルと同等の機能を実装できます。 一般にムービークリップでマウス操作に応じて外観を変えるには on アクション や onPress = function などを利用して gotoAndStop か gotoAndPlay でフレームを切り替えますが、これらのフレームラベルを付けておくと、スクリプトでフレームを移動することなく自動で切り替わるようになります。 この機能についての詳細はヘルプをご参考になさってください。 ・ Flash ドキュメンテーション ActionScript 2.0 の学習:イベントの処理 - ボタン状態を持つムービークリップの作成 http://livedocs.macromedia.com/flash/8_jp/main/00001382.html *************************************** ボタンシンボルでは、たとえ”ダウン”のフレームを空白にしていたとしても、クリックした後は必ず”オーバー”のフレームが表示されます。 これは、ボタンをクリックしてその上でマウスボタンを離した時( release イベント発生時)はカーソルがボタンの上に重なっているためと思われます。 この仕様はムービークリップの自動フレーム切り替え機能を使った場合も同様で、クリックした時に _down 、ムービークリップ上でマウスのボタンを離すと _over のラベルが付いたフレームが表示されます。 しかし、_down のラベルの付いたフレームがない場合は release イベントが発生した時に _over のフレームは再生されません。 (理由は再生ヘッドの仕様と関係があると思われますが、詳細は割愛させていただきます) ここがボタンシンボルと違うところで、 > ロールオーバーしたときに確かに > 予定していたMCは動きだすのですが > クリックしちゃうとまたMCが作動しちゃうんです。 > クリックさえできなければー!と、思っています。 この望みを叶えてくれる仕様だと思います。 ただ、クリック不可能になるのではありません。 _down のフレームがない場合はクリックしてもフレームの自動切り替えが行われないだけで、press や release イベントは通常通り発生します。 これらのイベントを利用するスクリプトが設定されていないのならば、何の処理も行われないし外見も変化しないということです。 ------------------------------------------------------------------ 実際に作ってみますと、次のようになります。 まず、アニメのムービークリップとヒット領域にするムービークリップを用意します。 アニメのムービークリップがループ再生されては困る場合は、最後のフレームに stop(); を入れてください。 この2つを、別のムービークリップの入れ子にします。 ボタンシンボルの中にオーバーの外観とヒット領域をひとまとめにして定義するのと、似たような発想です。 このシンボルは2フレームの構成にします。 ヒット領域はフレーム1から2まで、アニメのムービークリップはフレーム2にだけ配置します。 ヒット領域を非表示にする場合は、「プロパティ」パネルでアルファを0%に設定してください。 もちろん、スクリプトで _alpha プロパティを 0 にして透明にするか _visible プロパティを false にして非表示にしても構いません。 ヒット領域のムービークリップにインスタンス名を付けてください。 ここでは仮に” hit_area ”とします。 次に、フレームラベルとスクリプトを設定します。 このフレームラベルが、今回の肝です。 フレーム1はボタンシンボルでいうところのアップにあたりますので”_up”、フレーム2はオーバーですから”_over”と付けます。 レイヤーを分け、フレームラベル専用のレイヤーを作っておくと分かりやすくなります。 スクリプトはフレーム1に書きます。 (↓各行頭に全角のスペースが入っています。コピーする際はご注意ください) //自動フレーム切り替え機能を有効にするための、ダミーのイベントハンドラ this.onRollOver = null; //ヒット領域の定義 this.hitArea = hit_area; //タイムラインを止めておく stop(); 以上でシンボルは完成です。 インスタンスを配置し、「ムービープレビュー」で確認してみてください。 hit_area にカーソルを合わせると _over のラベルを付けたフレーム(フレーム2)に自動的に切り替わり、アニメのムービークリップが再生されます。 当然ながら、フレームアクションを設定していればそのスクリプトも実行されます。 普段は _up のラベルの付いたフレーム(フレーム1)が表示され、hit_area からカーソルが外れた時もフレーム1に自動で戻ります。 このフレームにはアニメのムービークリップがありませんから、アニメのムービークリップはステージから消えて見えなくなります。 hit_area にカーソルを合わせてクリックしても、再度アニメのムービークリップが再生されることはありません。 また、hit_area がアニメのムービークリップの上に重なっていなければ、アニメのムービークリップの部分にはカーソルが反応しません。 ちなみに、今回はボタンシンボルに倣って _up → _over の順にフレームを作りましたが、逆に _over → _up の順で作ることもできます。 この順番で作るとムービークリップのフレーム1にアニメのムービークリップが存在するため、「ライブラリ」のプレビューウィンドウやステージに配置した時も分かりやすく便利です。 この場合はフレーム1の stop(); をフレーム2に移動してください。 *************************************** ムービークリップのこの機能は ・特定のフレームラベルを付ける ・ on(press) や onRollOver など、ボタンイベントを使う処理を定義する の、2点の条件が揃った時に有効になります。 今回は単にフレームを自動で切り替えてくれる機能を使いたいだけですので、this.onRollOver = null; という何もしないイベントハンドラを定義しています。 上記のスクリプトではただのダミーですけれど、例えばロールオーバーで特定のセリフが出力されるなど、ここにゲームの処理等を定義しても構いません。 MovieClip クラスの hitArea プロパティは、ボタンとして使う際のヒット領域を定義するものです。 未定義の場合はムービークリップ自身がヒット領域になります。 この例ではとりあえず自分の子を指定しましたが、他の階層にあるムービークリップを定義することもできます。 異なる階層にあるものを使う場合は、ターゲットパスにご注意ください。 ヒット領域にカーソルが重なった時にカーソルが手のひらの形に変わらないようにするには、フレーム1のスクリプトに //手のひらカーソルを無効にする this.useHandCursor = false; というスクリプトを追加してください。 ヒット領域は子である hit_area ですが、手のひらカーソルを使うかどうかは、あくまでも親ムービークリップの問題です。 これを無効にするには、ヒット領域として使うもののプロパティではなく親自身の useHandCursor を変更します。 ------------------------------------------------------------------ 特殊なフレームラベルと入れ子のムービークリップを利用すると、スクリプトが3~4行と短くて済み、「○○で△△が起こった時に□□のムービークリップでああしてこうして」といった複雑さをなくせる利点はあります。 しかし、スクリプトだけで実現するものではないため、スクリプトからでは何をしているのかが分かりにくくなるところが欠点です。 もっとも、これはボタンシンボルの”オーバー”や”ヒット”フレームを使っても同じことですが。 それから、独自のヒット領域にする場合はヒット領域もムービークリップにせざるをえないので、どうしてもシンボルが1つ増えてしまいます。 好みや制作者の美学にもよるのかと思いますけれど、スクリプトを見て分かりやすく作るのなら、ヒット領域側でイベントを検出してアニメのムービークリップに対する制御を行う方が無難なのかもしれません。 rollOver イベントの代わりに、ムービークリップとマウスカーソルの座標で hitTest をとる判別方法があります。 他にも、ヒット領域が単純な形(四角形や円など)ならば、インスタンスを置かずに、カーソルの座標がその領域内にあるかを if 文で数学的に判断する方法も考えられます。 ただし、hitTest や座標による判定では、カーソルが重なっている間は常に条件が成立してしまいます。 ”カーソルがそこに重なった時に1度だけ”と限定するにはフラグが必要です。 *************************************** ゲームの制作は長丁場になる場合があります。 後から見て、「これはどうやっていたんだったかな?」とならないように設計してください。 ゴチャゴチャして訳が分からなくなっているプログラム(通称”スパゲティ・プログラム”)はいただけませんが、省略に省略を重ねた華麗すぎるプログラムも分かりにくいものです。 スッキリ・スマートな設計にした場合は、こまめにコメントを入れるなどして後で見る時の手がかりを残しておくといいでしょう。
その他の回答 (5)
- DPE
- ベストアンサー率85% (666/776)
#5です。 つまり、ヒット領域にカーソルが重なった時にアニメのムービークリップを再生、更にこの中の特定の部分をクリックした時だけ何かをする(アニメのムービークリップは消えないようにする)・・・ということでしょうか? 特殊なフレームラベルを使ったムービークリップで、_up と _over はあっても _down のラベルの付いたフレームがない場合は、クリックすると press や release イベントは発生するけれど _over のフレームが表示されたままになります。 ヒット領域とクリックして反応する部分が重なっている場合は、この特徴を上手く利用すると何とかなります。 まず、クリックして反応する領域をムービークリップとして作ります。 このムービークリップを、#5で作成したシンボルの、ヒット領域のムービークリップ(#5の例では hit_area )と重ねて配置してください。 上でも下でも、レイヤーを分けなくても分けなくても構いませんが、まあ、レイヤーを分けて上に重ねる方が分かりやすいでしょう。 この領域のムービークリップにインスタンス名を付けてください。 ここでは仮に” click_hit ”とします。 #5のスクリプトに、次のようなスクリプトを追加します。 (↓各行頭に全角のスペースが入っています。コピーする際はご注意ください) this.onRelease = function() { //クリック領域上にカーソルがある時だけ、クリックしたと見なす if( this.click_hit.hitTest( _root._xmouse , _root._ymouse , true ) ) { /*ここに、クリックした時の処理を書く*/ } }; ムービーをプレビューし、動作を確認してみてください。 hit_area にカーソルを合わせるとアニメのムービークリップが再生され、カーソルが外れるとアニメは消えます。 クリックした時の処理に仮に trace アクションでも書いておくと、click_hit の部分をクリックすると「出力」パネルが開いてメッセージが表示されます。 しかし、hit_area の click_hit と重なっていない部分をクリックした時は trace アクションが実行されません。 また、click_hit にカーソルが重なっている時でも、アニメのムービークリップはそのまま再生され続けます。 ポイントは click_hit とカーソルの位置で衝突判定をとっている hitTest です。 クリックした時は、”対象とカーソルが必ず重なっている”という特徴があります。 つまり、hitTest でムービークリップとカーソルの座標で衝突判定をとり、衝突している( hitTest の結果が true )であればムービークリップとカーソルが重なっていると判断できます。 親シンボルのヒット領域は hit_area なので、何もせず onRelease で処理をしようとすると click_hit 以外の部分にも反応してしまいます。 ” release イベントが発生した時に click_hit の上にカーソルがあった場合だけ”と制限を加えると、ヒット領域内の特定の部分にだけ反応するようになります。 hitTest を使ってクリックを検出する方法はいろいろな場面で使えます。 今回は release イベントで使いましたが、mouseDown や mouseMove イベントと組み合わせて擬似的な press ・ rollOver / Out イベント処理を作ることもできます。 機会がありましたら研究してみてください。 なお、onRelease イベントハンドラを定義しましたので、これだけでムービークリップのボタン機能が有効になります。 ダミーとして入れておいた this.onRollOver = null; は削除しても構いません。 ----------------------------------------------------------------- カーソルがヒット領域を高速で横切って出てしまった時に一瞬だけアニメが見える現象は、ボタン機能を使う限りはまず対処できないでしょう。 ヒット領域側で rollOver や rollOut イベントを検出するならば、フラグを利用して何とかできると思います。 市販のゲームでも、たまたま一瞬だけ何かが見えて、これは何かあるのではと思って調べてみたら謎が解けて先に進めた・・・という局面がよくあります。 あまりゴテゴテとフラグを付けて無理やり対応するよりは、隠れキャラを探す楽しさのような演出として残しておくというのも、1つの手ではないでしょうか。
お礼
だんだん、付いていけなくなってきている 自分に気づき焦っています・・・・(;´д`)ゞ でも、頑張って意味を理解して利用してみます。 衝突判定を用いる手法は考えもしなかったので トライは是非してみたいと思います。 >市販のゲーム~ そうなんですよね。 あまり固執したがんじがらめのゲームより ゆとりと遊びが入ったゲームのほうが楽しいですよね。 技術面・アディア共に有難う御座います。 必ず成功させてみます。 助かりました有難うございます!
- perse
- ベストアンサー率74% (113/152)
横から失礼します。 #3さんのやり方だとロールオーバー時に動く子ムービークリップ自体も 「マウスが乗っかるであろう面積」に含まれてしまうと思います。 つまり子ムービー再生中にその子ムービーにマウスが乗っかってさえいれば 本来の「マウスが乗っかるであろう面積」からマウスが外れても ロールアウトにならないのでは?ってことです。 (子ムービーがマウスが乗っかる面積より大きい場合) それでは困るというのであれば、 「マウスが乗っかるボタン」と「ロールオーバーで再生されるムービー」は (入れ子にしないで)別々に作る方がよいかと思います。 「マウスが乗っかるボタン」はヒット領域だけ作成し配置、 ボタンのを置いた後ろ(下のレイヤー)にロールオーバー時に動くMCを配置します。 MCのインスタンス名はmy_mcとしておきます。 ボタンに on (rollOver) { this.my_mc._visible = true; this.my_mc.play(); } on (rollOut, dragOut) { this.my_mc.gotoAndStop(1); this.my_mc._visible = false; } my_mcに onClipEvent (load) { this._visible = false; }
補足
ご指導ありがとうございます。 意味的には良く理解できました。 やっぱ、表示・非表示を持ちいらないとダメですか。 ボタンインスタンスだけでは苦しいという事で解釈しますね。 (内心、需要はあるハズなので簡単方法あると思ったんですが) (けど、これは簡単な方法に該当するんでしょうね) ですが、余談になりますが 本当FLASHって面白いですね。 作り込みに悩む事が解決できそうでできないという ホント頭の体操になっていいです。 これからも、愚問ばかりしてしまいますが 皆さん宜しくお願いします。
#1&2です。 #2もフライングしてますね。 すみません。 大訂正です。 今度はちゃんと作成&検証してみました。 > ボタンタイムラインにて > 「アップ」なにも無し(空白キーフレーム) > 「オーバー」MCを設置 > 「ダウン」なにも無し(空白キーフレーム) > 「ヒット」マウスが乗っかるであろう面積のオブジェクト それでしたら,やっぱり, ムービークリップでボタンを作成しましょう。 ムービークリップを作成し, そのムービークリップのタイムラインを2レイヤー2フレームにします。 ↓(子)ムービークリップ レイヤー 筆・・|○|●| レイヤー 筆・・|●/ []|←透明な塗り(マウスが乗っかるであろう面積) そして,この(親)ムービークリップに, ------------------------------------ onClipEvent (load) { this.stop(); } on (rollOver) { this.gotoAndStop(2); } on (press) { this._alpha = 0; } on (release) { this._alpha = 100; } on (rollOut, dragOut) { this._alpha = 100; this.gotoAndStop(1); } ------------------------------------- と書くと, on (press) でアルファ0の非表示になり, on (release) でアルファ100の表示になり, 見た目は, > 「ダウン」なにも無し(空白キーフレーム) になります。 ノンスクリプトではやはり難しいかと… あまり良いアイデアではないかもしれませんが, 一応一案です。
補足
なるほど、やはりこの手法しか無いですか。 さすがに、スプリクト上でアルファを調整してまでの 知識がなかったので、類似した手法で (ビジュアル操作で出来る範囲) 造ってみたんですが・・・・・ こんな現象がでたのですが sasakunさんの方法だと防止できるのでしょうか? (実行すればいいのですが、配置したオブジェクトが複雑化してきているので できれば触らないで理解したいので><) ボタンインスタンスでは ロールオーバーしたときの判定は1度だけで、 次はマウスが判定範囲から外れるまでロールオーバーされたと認識しないんですよね? なので、設置したMCは(ストップ制御で)1度だけ再生する。と、設定したりできるんですが、 試しに作った 「透明MCにマウス乗っかったらMC動け!」と 教えてやると、マウスが判定範囲に居座るとずーっとMCを繰り返してしまうのです。 繰り返さないようにフラグ持たせてとかしないと ダメなんでしょうか。 複雑化したオブジェクトの前にそこまで階層の深い処理を 私がずっと根気良く間違わずにできると思えません;; 簡素化された方法でご指導お願いします。>< 追伸: 今回も簡単な話をややこしくしてしまいました。 すみません。
#1です。 いや,私の勘違いです。 あまりの懐かしさにフライングしてしまいました。 よく考えると,ボタンをダウンしてまたアップすると, ロールオーバー状態と等しくなりますね。 それでは, ボタンを透明な塗りなどのムービークリップで作成して, on (rollOver) { ムービーリップよ動け(); } を書けば良いのではないでしょうか。 ただし, ボタンシンボルのインスタンスではなく, ムービークリップの場合,1つの階層を持つため階層が変わりますから, on (rollOver) { _parent.ムービーリップよ動け(); } のように, ボタンより1つ上の階層を指すようにするか, on (rollOver) { _root.ムービーリップよ動け(); } のように絶対パスでムービークリップを指定すると, うまく動きます。 またもや何か勘違いしていましたら補足してください。
大変なつかしく,また,お久しぶりです。 お元気ですか? 私はお元気です。 さて… >> 画面上、ある特定の場所にマウスが来ると >> 予め仕組まれたMCが動く。 >> そのボタン上でロールオーバーするのは良いのですが >> ボタンとして機能してしまうのを防ぎたい… よく意味がわかりませんが, 文章中に登場している 「ボタン」 という言葉は この,一箇所だけです。 他に ボタン は登場しませんから, ある特定の場所にマウスが来る = ボタンにロールオーバーする と考えて良いのでしょうか? すると,ボタンに, --------------------- on (rollOver) { ムービーリップよ動け(); } -------------------- というようなスクリプトを書けば良いだけのことで, >> クリックするとまたMCが最初から動く という現象は起きないと思うのですが… -------------------- on (release, rollOver) { ムービーリップよ動け(); } -------------------- のように書いたら, ロールオーバーしたときと,クリックしたとき,両方に, 「ムービーリップよ動け();」 が作動してしまいますが, on (rollOver) だけだと,ロールオーバーしたときだけだと思いますけど…??? 何か何処かで,私が勘違いしているような気もします。 よろしければ補足してください。 私がわからなくてもひょっとしたらどなたかわかる方がいらっしゃるかもしれません。 ------------------ 追伸は,ちょっと笑えました…。失礼。
補足
さっそくのお返事有難うございます。 そして、お久しぶりです。 私も相変わらず元気で過ごしています。^^ 解釈は全て合っております、私のやりたい事は それで事が足るようです。 ・・・・が、 今回したいのは MCを予め配置しているのでなく (すれば良いのですが、面倒&容量を考慮して) ボタンインスタンス上で、操作をしたく思っています。 現状は、このようになっています。 ボタンタイムラインにて 「アップ」なにも無し(空白キーフレーム) 「オーバー」MCを設置 「ダウン」なにも無し(空白キーフレーム) 「ヒット」マウスが乗っかるであろう面積のオブジェクト こんな感じです。 この設定だと「ヒット」の不可視と「オーバー」時の MC造るだけで簡単にMCの制御できるから (自動開始だけですが) どうしてもこちらを採用したいのですが。 スプリクト管理も含め単純化も狙いたいので。 ただ、これだと ロールオーバーしたときに確かに 予定していたMCは動きだすのですが クリックしちゃうとまたMCが作動しちゃうんです。 クリックさえできなければー!と、思っています。 やはり、スプリクト管理しないとダメですかぁ? (´・ω・`)ショボーン 追伸2: またご指導頂けて光栄です。 宜しくお願いします。
お礼
親切丁寧な文章、ありがとうございました。 とても、私の力量では一読しただけでは全て理解できそうにありません。 プリントして、じっくり熟読してみます。 それにしても事細かいご指導ありがとうございます。 毎度、挫折しかけては皆さんの説明を見て 投げ出してはいけないと励まされています。 スパゲティ・プログラムかから脱皮し、 せめて うどん・プログラムぐらいなるように頑張ります。 ありがとうございました。
補足
できました。 ちゃんと動きもしました。 ですが・・・・・・ (もう手が無いと思い、ゲーム自体の操作方法を 変更するつもりなので、今後の知識として 聞いておきたいと思い連絡しました) じつは、マウスが乗っかった時に 用意したMCが動き、管理もできるようになったのですが、 その上に見えないボタンを配置しています。 ※ ゲーム進行上、クリックする所を誘導するMC、 そしてその中心となる場所をクリックすると イベント発生といった感じです。 今度は、その見えないボタンにマウスが乗っかると 再生しているMCが途中で中止しちゃうんです。 それと、早い速度でマウスを移動している時、 折角判定されてMCが動こうとしているのに 範囲枠からマウスが飛び出しちゃうとMCの再生が 中止されます。 これって、考えればそりゃそうでしょ。と 言われてしまいそうな現象なのですが いやぁ、ゲーム造りってホント面白い。 予期せぬ(?)事が次から次へと・・・・少し凹んできました^^; やっぱ、再生中かどうか調べるとかする 必要があるんですよねー? 手抜きはしたくないけど、ちょっとややこしく なり過ぎそうなので、操作方法変更しようかと・・・・ つД`)・゜・。・゜゜・*:.。..。.:*・゜