
今回のテーマはイベントと乱数。その前に既に出てきたことを復習しておきましょう。
比較演算子・・・条件式や評価式で使用する符号ですね。
a<b・・・aがbより小さい(未満)
a<=b・・・aがb以下
a>b・・・aがbより大きい(超過)
a>=b・・・aがb以上
a==b・・・aがbと等しい(等価)
a!=b・・・aがbと等しくない(不等)
a===b・・・aがデータ型も含めてbと等しい
a!=bはひな形スクリプトでもよく使われますので、覚えてくださいね。
変数名と関数名・・・半角英数字を使用。他に_アンダースコア記号も使用可能。但し、数字から始める名前は使用できず、JavaScriptで規定されているキーワードやオブジェクト名・プロパティ・メソッドなどの予約語をそのまま名前に使用することもできない。
とりあえず、このくらいにしておきましょう。
今回のテーマイベント行きましょう。
HTMLドキュメントを表示しているソフトウェア上では、何かが変化した時にイベントが発生しています。ページが読み込み完了した時、ページが切り替わった時、マウスが移動したとき、クリックした時、キーボードのキーが押された時、など様々なイベントが頻繁に発生しているといえます。パソコンがソフトウェア上で常日頃から変化を監視しているというわけですね。イベントは何か変化が起これば発生するわけですが、だからといってそのイベントに対して、行動を起こすようなことはありません。イベントはその発生を検出する検知器を設置しない限り何も起こりません。その検知器の役目をするのが、イベントハンドラと呼ばれるものです。
尚イベントはeventというオブジェクトが変化するものです。
[イベント発生メカニズム概要]
@イベントに関するユーザーアクションや状態変化が生じる。
Aeventオブジェクトが更新され、イベントの状態が反映される。
Bイベントが発生し、通知される。
Cソースエレメントのイベントハンドラが呼び出される。
Dイベントハンドラによって記述されたアクションが実行される。
イベントハンドラ自体はスクリプトが用意しているものではありません。HTMLのタグで使用するイベントハンドラは大文字小文字混在が許されます。但し、スクリプトが用意しているイベントハンドラもあります。この二つのイベントハンドラは異質のものではなく、スクリプト上で使用するイベントハンドラと、HTMLで使用するものがあり、用意されているイベントハンドラは相似しています。
例えばページ読み込み完了を検知するイベントハンドラはonloadです。これをタグ内で使用するときには、<body
onload="処理">のように記述します。
スクリプト内では、document.body.onload=処理のように記述します。
一応注意書きとしてスクリプト内からイベントハンドラで処理を行う方法は制限が多く、あまり推奨しません。
前置きはこのくらいにして早速イベントハンドラを使用して、画面上をクリックしたらINしてくるようにしましょう。クリックするまでは関数を実行しないようにするんです。
クリックイベントを検出するイベントハンドラはonclickです。タグ内ではONCLICKでもonClickでも構いません。エレメントをクリックすると何かを実行するには、onclick="スクリプト"のように書きます。スクリプト部分はJavaScriptでもVBScriptでも構いません。関数を呼び出す命令以外の命令も書けますし、;で区切ることで複数のステートメントを記述しても構いません。
画面上をクリック・・・画面上はHTML文書のbodyそのものです。従ってbodyエレメントにonclick="処理"を入れます。処理の部分ですが、lidou()関数とdidou()関数をクリックしたら実行したいので、onclick="lidou();didou()"とします。二つの命令を実行させるので、;で区切りますね。
[ソース]
<html>
<head>
<title></title>
</head>
<body
onclick="lidou();didou()" style="margin:0px;
overflow:hidden">
<img id="img1" src="akiakane.gif"
style="position:absolute; left:0px; top:100px; width:100px">
<script>
var
ix=5//一度に動くピクセル数
var iy=5//一度に動くピクセル数(縦)
var rtime=10//繰り返し実行時間(ミリ秒)
function
lidou(){//右移動する関数
if(img1.style.pixelLeft+ix>=document.body.clientWidth-img1.clientWidth){
if(img1.style.pixelLeft<document.body.clientWidth-img1.clientWidth){
img1.style.pixelLeft=document.body.clientWidth-img1.clientWidth
}else{
ridou()
return
}
}else{
img1.style.pixelLeft+=ix
}
//status=img1.style.pixelLeft
setTimeout("lidou()",rtime)
}
function
ridou(){//左移動する関数
if(img1.style.pixelLeft>0){
if(img1.style.pixelLeft-ix<0){
img1.style.pixelLeft=0
}else{
img1.style.pixelLeft-=ix
}
setTimeout("ridou()",rtime)
}else{
lidou()
return
}
}
function
didou(){//下移動する関数
if(img1.style.pixelTop+iy>=document.body.clientHeight-img1.clientHeight){
if(img1.style.pixelTop<document.body.clientHeight-img1.clientHeight){
img1.style.pixelTop=document.body.clientHeight-img1.clientHeight
}else{
uidou()
return
}
}else{
img1.style.pixelTop+=iy
}
setTimeout("didou()",rtime)
}
function
uidou(){//上移動する関数
if(img1.style.pixelTop>0){
if(img1.style.pixelTop-iy<0){
img1.style.pixelTop=0
}else{
img1.style.pixelTop-=iy
}
setTimeout("uidou()",rtime)
}else{
didou()
return
}
}
var
saikoro=Math.floor(Math.random()*4)+1
status=saikoro
switch(saikoro){
case
1:
img1.style.pixelLeft=-img1.clientWidth
img1.style.pixelTop=Math.floor(Math.random()*(document.body.clientHeight+img1.clientHeight+1))-img1.clientHeight
break
case
2:
img1.style.pixelTop=-img1.clientHeight
img1.style.pixelLeft=Math.floor(Math.random()*(document.body.clientWidth+img1.clientWidth+1))-img1.clientWidth
break
case
3:
img1.style.pixelLeft=document.body.clientWidth
img1.style.pixelTop=Math.floor(Math.random()*(document.body.clientHeight+img1.clientHeight+1))-img1.clientHeight
break
case
4:
img1.style.pixelTop=document.body.clientHeight
img1.style.pixelLeft=Math.floor(Math.random()*(document.body.clientWidth+img1.clientWidth+1))-img1.clientWidth
}
</script>
</body>
</html>
さあこれで問題ないと思いますか?クリックすると動き始めますね。・・・・でも動き出してから更にクリックを何度か繰り返してみてください。おかしな動きをしますよね。
クリックするとlidou()関数とdidou()関数を実行するように指令しています。動き出してもクリックすることで更に関数が実行されてしまいます。結果同じ関数がいくつも動いていることになります。
このような場合のプログラム上の処理ではよく使われる手法があります。それはフラグを使うものなんですが、フラグって何?って思いますよね。flagつまりは旗のことなんですが、プログラムではある状態になるか、ないかを示すものとして使用されます。その状態にない場合をフラグが立っていない、その状態にある場合をフラグが立っているという言い方をします。とはいえスクリプトでフラグなるものが用意されているわけではありません。フラグが立っている、立っていないという状態を表すように何か状態を表すものを用意すればいいのですね。あくまでもフラグを使用するというのは概念としてつかんで下さいね。
今までの右移動と左移動関数で言えば、例えば右移動中(lidou()関数が実行されている状態である)にはフラグを立てる、左移動中(ridou()関数が実行されている状態である)場合にはフラグを降ろすといった状態をなにかもので示そうというわけです。
そのものとは??・・・変数なんですね。変数を用意し、その内容を旗が立っている状態と旗が降りている状態と似た状態で示せばいいのです。
そこで変数flagを用意し、旗が立っている状態と旗が立っていない状態を決めましょう。立っている・降りているといった二つにひとつの状態をしますのですから、内容は二つに一つとなる値が入れば良いですね。旗が立っている状態を1という数値で表し、降りている状態を0という数値で表す、これでOKです。1と0でなければならない理由はありません。旗が立っているのが1で降りているのが-1でも構いませんし、立っているのが1でI以外なら降りているでも構いません。数値でなくても良いですね。変数がtrue(真である)という状態なら旗が立っている、false(偽である)状態なら降りているとしてもいいのです。もっと具体的には、変数の内容が"立っている"という文字列ならば立っている、"寝てます”という文字列ならば降りているでも構わないのです。
というようにユーザーが規則を設けてその規則に沿うようにプログラムすればいいのですが、扱いやすさを考えると数値で示す方が簡単だと誰しもわかりますよね。だってflag=1とかflag=0とかそれだけで旗の状態をセットできます。旗の状態を調べるなら、if(flag==1)やif(flag==0)で簡単に調べることができますからね。
さてフラグの概念はお分かりだと思います。コンピュータはコンデンサやトランジスタを組み込んだ集積回路で動いていますが、コンピュータの世界は実はこのフラグが立っているか立っていないかという二つに一つの状態を並列処理することで動作しています。電気が蓄えられている(onの状態)蓄えられていない(offの状態)という2進数の世界がコンピュータ内部で起こっているのですね。
このフラグとなる変数flagを用いてどうするの?
先ほどのソースではクリックすると何度も関数が実行されてしまいますね。そこで最初はクリックするまで関数が実行されていないわけですから、この状態をflagが0にしておきましょう。するとクリックすると関数実行されますが、その時にflagを1にしてしまいます。その状態を既に関数が実行されているということを示すものとしましょう。
クリックした時にflagが0ならばlidou()関数とdidou()関数を実行、クリックした時にflagが1ならば関数を実行させない---つまり二重実行させないようにすることが今回の課題です。
まずフラグとなる関数を確保、その初期値を0にしておきましょう。
var
flag=0
次はクリックすると関数を実行、尚且つflagを1にしてしまいます。このためには新たな関数を作成し、その関数の処理として行います。関数実行するかどうかはflagの内容が0か1かですね。
function
clstart(){
if(flag==0){
lidou()
didou()
}
flag=1
}
この関数clstart()の動きはまずflagが0かどうかで条件分岐させます。0ならばlidou()関数とdidou()関数が実行されます。flagが0ではない場合は、ifブロックの処理は実行されませんね。if文を抜け、flag=1によりflagは1という値に変わります。次回このclstart()関数が実行された時にはflagの値は1になっており、ifブロックの処理は実行されませんね。
では、このclstart()関数をクリックした時に実行させるようにしてみましょう。これもひとつの方法ですよ。
[ソース]
<html>
<head>
<title></title>
</head>
<body
onclick="clstart()" style="margin:0px;
overflow:hidden">
<img id="img1" src="akiakane.gif"
style="position:absolute; left:0px; top:100px; width:100px">
<script>
var
ix=5//一度に動くピクセル数
var iy=5//一度に動くピクセル数(縦)
var rtime=10//繰り返し実行時間(ミリ秒)
function
lidou(){//右移動する関数
if(img1.style.pixelLeft+ix>=document.body.clientWidth-img1.clientWidth){
if(img1.style.pixelLeft<document.body.clientWidth-img1.clientWidth){
img1.style.pixelLeft=document.body.clientWidth-img1.clientWidth
}else{
ridou()
return
}
}else{
img1.style.pixelLeft+=ix
}
//status=img1.style.pixelLeft
setTimeout("lidou()",rtime)
}
function
ridou(){//左移動する関数
if(img1.style.pixelLeft>0){
if(img1.style.pixelLeft-ix<0){
img1.style.pixelLeft=0
}else{
img1.style.pixelLeft-=ix
}
setTimeout("ridou()",rtime)
}else{
lidou()
return
}
}
function
didou(){//下移動する関数
if(img1.style.pixelTop+iy>=document.body.clientHeight-img1.clientHeight){
if(img1.style.pixelTop<document.body.clientHeight-img1.clientHeight){
img1.style.pixelTop=document.body.clientHeight-img1.clientHeight
}else{
uidou()
return
}
}else{
img1.style.pixelTop+=iy
}
setTimeout("didou()",rtime)
}
function
uidou(){//上移動する関数
if(img1.style.pixelTop>0){
if(img1.style.pixelTop-iy<0){
img1.style.pixelTop=0
}else{
img1.style.pixelTop-=iy
}
setTimeout("uidou()",rtime)
}else{
didou()
return
}
}
var
saikoro=Math.floor(Math.random()*4)+1
status=saikoro
switch(saikoro){
case
1:
img1.style.pixelLeft=-img1.clientWidth
img1.style.pixelTop=Math.floor(Math.random()*(document.body.clientHeight+img1.clientHeight+1))-img1.clientHeight
break
case
2:
img1.style.pixelTop=-img1.clientHeight
img1.style.pixelLeft=Math.floor(Math.random()*(document.body.clientWidth+img1.clientWidth+1))-img1.clientWidth
break
case
3:
img1.style.pixelLeft=document.body.clientWidth
img1.style.pixelTop=Math.floor(Math.random()*(document.body.clientHeight+img1.clientHeight+1))-img1.clientHeight
break
case
4:
img1.style.pixelTop=document.body.clientHeight
img1.style.pixelLeft=Math.floor(Math.random()*(document.body.clientWidth+img1.clientWidth+1))-img1.clientWidth
}
var
flag=0
function clstart(){
if(flag==0){
lidou()
didou()
}
flag=1
}
</script>
</body>
</html>
参考までに。
スクリプトは答えがひとつではありませんから、クリックで初回に限りlidou()とdidou()を実行させる手法もいろいろ考えられます。少し難しくなりますが、別の方法を示しておきますね。まだ出てきていない使い方をしている部分がありますので、解説はしません。こんな方法でもいいのか程度に見ておいてください。
[{ソース]
<html>
<head>
<title></title>
</head>
<body
onclick="lidou(flag);didou(flag);flag=1"
style="margin:0px; overflow:hidden">
<img id="img1"
src="akiakane.gif" style="position:absolute; left:0px; top:100px;
width:100px">
<script>
var ix=5//一度に動くピクセル数
var
iy=5//一度に動くピクセル数(縦)
var rtime=10//繰り返し実行時間(ミリ秒)
var
flag=0
function lidou(fl){//右移動する関数
status="flagの内容は"+flag+"です"
if(fl!=0)return
if(img1.style.pixelLeft+ix>=document.body.clientWidth-img1.clientWidth){
if(img1.style.pixelLeft<document.body.clientWidth-img1.clientWidth){
img1.style.pixelLeft=document.body.clientWidth-img1.clientWidth
}else{
ridou(fl)
return
}
}else{
img1.style.pixelLeft+=ix
}
setTimeout("lidou("+fl+")",rtime)
}
function
ridou(fl){//左移動する関数
if(fl!=0)return
if(img1.style.pixelLeft>0){
if(img1.style.pixelLeft-ix<0){
img1.style.pixelLeft=0
}else{
img1.style.pixelLeft-=ix
}
setTimeout("ridou("+fl+")",rtime)
}else{
lidou(fl)
return
}
}
function
didou(fl){//下移動する関数
if(fl!=0)return
if(img1.style.pixelTop+iy>=document.body.clientHeight-img1.clientHeight){
if(img1.style.pixelTop<document.body.clientHeight-img1.clientHeight){
img1.style.pixelTop=document.body.clientHeight-img1.clientHeight
}else{
uidou(fl)
return
}
}else{
img1.style.pixelTop+=iy
}
setTimeout("didou("+fl+")",rtime)
}
function
uidou(fl){//上移動する関数
if(fl!=0)return
if(img1.style.pixelTop>0){
if(img1.style.pixelTop-iy<0){
img1.style.pixelTop=0
}else{
img1.style.pixelTop-=iy
}
setTimeout("uidou("+fl+")",rtime)
}else{
didou(fl)
return
}
}
var
saikoro=Math.floor(Math.random()*4)+1
switch(saikoro){
case 1:
img1.style.pixelLeft=-img1.clientWidth
img1.style.pixelTop=Math.floor(Math.random()*(document.body.clientHeight+img1.clientHeight+1))-img1.clientHeight
break
case
2:
img1.style.pixelTop=-img1.clientHeight
img1.style.pixelLeft=Math.floor(Math.random()*(document.body.clientWidth+img1.clientWidth+1))-img1.clientWidth
break
case
3:
img1.style.pixelLeft=document.body.clientWidth
img1.style.pixelTop=Math.floor(Math.random()*(document.body.clientHeight+img1.clientHeight+1))-img1.clientHeight
break
case
4:
img1.style.pixelTop=document.body.clientHeight
img1.style.pixelLeft=Math.floor(Math.random()*(document.body.clientWidth+img1.clientWidth+1))-img1.clientWidth
}
status="flagの内容は"+flag+"です"
</script>
</body>
</html>
あらら今回はちょっと長くなりました。乱数を使用したはね返りする時に移動ピクセル数を変えて動きに変化をつけるは次回にまわします。
あっそれから今回のソースには問題点があります。それも次回解説しますね。