ひな形スクリプト講座20

 

[ひな形スクリプト講座1][ひな形スクリプト講座2][ひな形スクリプト講座3][ひな形スクリプト講座4][ひな形スクリプト講座5][ひな形スクリプト講座6][ひな形スクリプト講座7][ひな形スクリプト講座8][ひな形スクリプト講座9][ひな形スクリプト講座10][ひな形スクリプト講座11][ひな形スクリプト講座12][ひな形スクリプト講座13][ひな形スクリプト講座14][ひな形スクリプト講座15][ひな形スクリプト講座16][ひな形スクリプト講座17][ひな形スクリプト講座18][ひな形スクリプト講座19][ひな形スクリプト講座20][ひな形スクリプト講座21][ひな形スクリプト講座22][ひな形スクリプト講座23][ひな形スクリプト講座24][ひな形スクリプト講座25][ひな形スクリプト講座26][ひな形スクリプト講座27][ひな形スクリプト講座28][ひな形スクリプト講座29][ひな形スクリプト講座30][参考資料索引]

雪降りの基本形は理解できましたでしょうか?前回の雪降りは上からひとつずつ落ちてくるものです。それはimgtop[i]=-thという初期TOPの位置と時間差で動き始めるsetTimeout("yukiMove("+i+")",yt*i*1000)によるものです。

topの位置をランダムにして、まとめて動かし始めるとまた違ったスタートが可能です。

ちょっとやってみましょう。

topの位置はランダムに・・・stageエレメントの縦幅でランダムにしてみますと、imgtop[i]=Math.random()*stage.clientHeightでできそうですね。

開始は時間差を設ける必要がなくなりますので、setTimeout("yukiMove("+i+")",yt*i*1000)をyukiMove(i)に変えるとよさそうです。

[ソース]

<HTML>
<head>
<meta http-equiv="content-type" content="text/html; charset=shift_jis">
<META http-equiv="Content-Style-Type" content="text/css">
<title></title>
</head>
<body style="overflow:auto; margin:0px; padding:0px">
<img id="img1" src="yuki.gif" style="display:none">
<div id="stage" style="position:absolute; left:10px; top: 10px; background-color:black; width:600px; height:500px; overflow:hidden">
<script>
var ys=20//雪の数
var imgtop=new Array()//雪のTOP計算用配列
var imgleft=new Array()//雪のLFT用配列
var dd=5//落ちる重さ
var th=30//上部配置位置
var bh=50//下部end位置
var sk=50//速度(ミリ秒)
//var yt=2//雪の間隔(秒)これは不要になりますね。
var imgObj=new Array()//雪オブジェクトを入れる配列
for(i=1;i<=20;i++){
document.write("<img src='"+img1.src+"' style='position:absolute; left:-1000px; top:0px'>")
}

imgObj=stage.all

function yukiMove(n){
imgtop[n]=(imgtop[n]+dd)%(th+stage.clientHeight+bh)
imgObj[n].style.pixelTop=imgtop[n]-th
setTimeout("yukiMove("+n+")",sk)
}

function yukistart(){
for(i=1;i<=ys;i++){
imgtop[i]=Math.random()*stage.clientHeight
imgleft[i]=Math.random()*(stage.clientWidth-25-25)+25
imgObj[i].style.pixelLeft=imgleft[i]
imgObj[i].style.pixelTop=imgtop[i]
yukiMove(i)
}
}


setTimeout("yukistart()",3000)
</script>
</div>
</body>
</html>

雪降り基本形一度に降り始める


元に戻りましょう。

雪降りに横揺れを追加します。実はimgleft配列変数をわざわざ設けたのは、横揺れさせるときにその計算値を入れる器の用意のためだったんです。

横揺れはスクリプトで左右に動かすスクリプトを組めばいいのですが、三角関数を使うとif〜文が不要になるなど便利です。またサインカーブの特性を利用するとなだらかな曲線的変化が可能になるんです。

円運動での動きをよく見てください。縦横を三角関数で計算させて移動するので円運動に見えますが、横方向だけを見つめると揺れが生じているように見えますよね。もう一度次のサンプルを見てください。

円運動のひな形のtopを変化させずにleftのみにしたものなんです。

横揺れサンプル

eval("rimg"+n).style.pixelLeft=Math.cos(deg[n]*Math.PI/180)*hn+cx-eval("rimg"+n).clientWidth/2
deg[n]=deg[n]+dd

ソースのこの部分ですね。ということはdegという角度変化用の器と半径としてのhn、それにcxという中心X座標が必要になりますね。雪降りで利用するので、雪エレメント分を確保しましょう。またddはこのひな形では落ちる重さとして使用していますから、dgと変えます。

var dg=10//揺れの周期角度
var deg=new Array()
var hn=new Array()
var cx=new Array()

雪エレメントそれぞれ別の値を入れる器を用意すると、それぞれの動きに変化を付けられるという利点があります。同じ変数を利用するとシンクロした動きになり、自然な感じが出ませんので、別々の値で計算させるようにします。そのために配列変数を用意して、それぞれのエレメント用に値を入れる器にします。

角度ですが、0から360まででランダムにしましょう。

deg[n]=Math.random()*360・・・これを初期値にするといいですね。

半径が異なれば振幅が変わります。揺れがまったくないのは0にすればいいのですが、この半径を揺れ幅最大値と揺れ幅最小値でランダムにしてやります。

var hmax=30//揺れの大きさ最大値
var hmin=0//揺れの大きさ最小値

するとhnはどうなりますか?覚えてますか、最小値以上最大値の以下の整数値を得る公式は?

Math.floor(Math.random()*(最大値-最小値+1))+最小値でしたね。

hn[n]=Math.floor(Math.random()*(hmax-hmin+1))+hmin

cxは揺れの中心です。つまり揺れを生じない場合はLEFTそのものですね。LEFTはランダムに設定していました(imgleft[i]=Math.random()*(stage.clientWidth-25-25)+25)。

cx[n]=Math.random()*(stage.clientWidth-25-25)+25

でよさそうですね。

横揺れになるためのLEFT計算ですが、eval("rimg"+n).style.pixelLeft=Math.cos(deg[n]*Math.PI/180)*hn+cx-eval("rimg"+n).clientWidth/2はrimgn画像の横幅から中心を調整していました。

この調整は今回はあまり必要とは思えませんのでシンプルにしますね。

imgleft[n]=Math.cos(deg[n]*Math.PI/180)*hn[n]+cx[n]

さ、まとめてみましょう。

[ソース]

<HTML>
<head>
<meta http-equiv="content-type" content="text/html; charset=shift_jis">
<META http-equiv="Content-Style-Type" content="text/css">
<title></title>
</head>
<body style="overflow:auto; margin:0px; padding:0px">
<img id="img1" src="yuki.gif" style="display:none">
<div id="stage" style="position:absolute; left:10px; top: 10px; background-color:black; width:600px; height:500px; overflow:hidden">
<script>
var ys=20//雪の数
var dd=5//落ちる重さ
var th=30//上部配置位置
var bh=50//下部end位置
var sk=50//速度(ミリ秒)
var yt=2//雪の間隔(秒)
var hmax=30//揺れの大きさ最大値
var hmin=0//揺れの大きさ最小値
var dg=10//揺れの周期角度
//設定ここまで
var imgtop=new Array()//雪のTOP計算用配列
var imgleft=new Array()//雪のLFT用配列
var deg=new Array()
var hn=new Array()
var cx=new Array()

var imgObj=new Array()//雪オブジェクトを入れる配列

for(i=1;i<=20;i++){
document.write("<img src='"+img1.src+"' style='position:absolute; left:-1000px; top:0px'>")
}

imgObj=stage.all

function yukiMove(n){
imgtop[n]=(imgtop[n]+dd)%(th+stage.clientHeight+bh)
deg[n]=deg[n]+dg
imgleft[n]=Math.cos(deg[n]*Math.PI/180)*hn[n]+cx[n]
imgObj[n].style.pixelTop=imgtop[n]-th
imgObj[n].style.pixelLeft=imgleft[n]
setTimeout("yukiMove("+n+")",sk)
}

function yukistart(){
for(i=1;i<=ys;i++){

deg[i]=Math.random()*360
hn[i]=Math.floor(Math.random()*(hmax-hmin+1))+hmin
cx[i]=Math.random()*(stage.clientWidth-25-25)+25

imgtop[i]=-th
imgleft[i]=Math.cos(deg[i]*Math.PI/180)*hn[i]+cx[i]
imgObj[i].style.pixelTop=imgtop[i]
imgObj[i].style.pixelLeft=imgleft[i]
setTimeout("yukiMove("+i+")",yt*(i-1)*1000)
}
}

setTimeout("yukistart()",3000)

</script>
</div>
</body>
</html>

雪降り横揺れ有

 


更に改造してみましょう。

雪の落ちる速さは全て同じになっています。これはvar dd=5//落ちる重さimgtop[n]=(imgtop[n]+dd)%(th+stage.clientHeight+bh)によるものですね。
そこでまず雪のサイズを変えることにし、そのサイズに応じてddを比例させて変えましょう。また横揺れもランダムにしていますが、雪のサイズに比例するようにします。揺れの最小値は使用せず、揺れの大きさを設定できるようにして、その値に対し、比例させます。

画像のサイズはzoomプロパティを使用します。zoomは通常のサイズを1として、倍率を与えます。

yzという配列変数を用意し、それぞれの倍率をランダムに発生させます。

var ybmax=1.0//倍率最大値
var ybmin=0.3//倍率最小値
var yz=new Array()

とした時yz[n]はどのようなランダム発生式を書けばいいでしょうか?今回は最大値と最小値の間の数値をランダムに出したいのです、整数ではなく、少数のままがいいのです。0.5倍とか0.72倍とか問題ないからです。

yz[n]=Math.random()*(ybmax-ybmin)+ybmin

ybmin以上ybmax未満のランダム値になりますね。よく確認しておいてくださいね。

var hmax=30//揺れの大きさ最大値
var hmin=0//揺れの大きさ最小値

これはいらなくなります。代わりにゆれの基準幅としてhkとしておきます。

var hk=30//揺れ半径

zoom値はyz[n]で、それぞれの半径はhn[n]=hk*yz[n]とします。

zoomプロパティは日本語MSDNにはなく、英語MSDNにあります。

object.style.zoom・・・エレメントオブジェクトの倍率スケールを設定または読み取る。読み書き可能。
とりうる値:0以上の数値・・・倍率。%単位での数値。normal。

ということでimgObj[n].style.zoom=yz[n]となります。

落ちる重さddは標準値にして、個々のエレメントの落ちる重さは配列を使用しましょう。

var yd=new Array()

yd[n]=dd*yz[n]となります、わかりますね。

topを計算する部分が少し変わります。修正を忘れないようにしてください。

imgtop[n]=(imgtop[n]+yd[n])%(th+stage.clientHeight+bh)

 

ではまとめます。

[ソース]

<HTML>
<head>
<meta http-equiv="content-type" content="text/html; charset=shift_jis">
<META http-equiv="Content-Style-Type" content="text/css">
<title></title>
</head>
<body style="overflow:auto; margin:0px; padding:0px">
<img id="img1" src="yuki.gif" style="display:none">
<div id="stage" style="position:absolute; left:10px; top: 10px; background-color:black; width:600px; height:500px; overflow:hidden">
<script>
var ys=20//雪の数
var dd=5//落ちる重さ標準値
var th=30//上部配置位置
var bh=50//下部end位置
var sk=50//速度(ミリ秒)
var yt=2//雪の間隔(秒)
var hk=30//揺れ半径
var dg=10//揺れの周期角度
var ybmax=1.0//倍率最大値
var ybmin=0.3//倍率最小値

//設定ここまで
var yz=new Array()//雪の倍率用配列
var yd=new Array()//落ちる重さ用配列
var imgtop=new Array()//雪のTOP計算用配列
var imgleft=new Array()//雪のLFT用配列
var deg=new Array()
var hn=new Array()
var cx=new Array()
var imgObj=new Array()//雪オブジェクトを入れる配列

for(i=1;i<=20;i++){
document.write("<img src='"+img1.src+"' style='position:absolute; left:-1000px; top:0px'>")
}

imgObj=stage.all

function yukiMove(n){
imgtop[n]=(imgtop[n]+yd[n])%(th+stage.clientHeight+bh)
deg[n]=deg[n]+dg
imgleft[n]=Math.cos(deg[n]*Math.PI/180)*hn[n]+cx[n]
imgObj[n].style.pixelTop=imgtop[n]-th
imgObj[n].style.pixelLeft=imgleft[n]
setTimeout("yukiMove("+n+")",sk)
}

function yukistart(){
for(i=1;i<=ys;i++){

yz[i]=Math.random()*(ybmax-ybmin)+ybmin
hn[i]=hk*yz[i]

yd[i]=dd*yz[i]
deg[i]=Math.random()*360
cx[i]=Math.random()*(stage.clientWidth-25-25)+25
imgtop[i]=-th
imgleft[i]=Math.cos(deg[i]*Math.PI/180)*hn[i]+cx[i]
imgObj[i].style.zoom=yz[i]

imgObj[i].style.pixelTop=imgtop[i]
imgObj[i].style.pixelLeft=imgleft[i]
setTimeout("yukiMove("+i+")",yt*(i-1)*1000)
}
}

setTimeout("yukistart()",3000)

</script>
</div>
</body>
</html>

雪降り横揺れ有サイズ違い有

 

もう少し改善するべきところがありそうです。画像サイズが小さいものほど奥に、大きいものほど手前に表示されるようにしたいのです。小さいということは奥にあるということですからね。

奥行きという概念はCSSのz-indexで設定できますが、スクリプトではzIndexというプロパティで設定できます。

今倍率が1ならばz-indexが100になるようにします。yz[n]を100倍して少数点以下を切捨てするとうまくいきそうなんです。

例えばyz[n]が0.3ならz-indexは3になります。0.33と0.34では同じく3になりますね。1000倍して切捨てするともっと細かくなりますが、そこまでする必要はないでしょう。

zIndexプロパティ・・・object.style.zIndex

デフォルト値はautoで、HTMLソースで出現した順番に下から上に重ねられる。正の値のエレメントは、負の値のエレメントの上に重ねられる。また値が大きなものが小さいものの上に重ねられる。もし、同じ値が設定された場合には、ソース順に重ねられる。読み書き可能である。

imgObj[i].style.zIndex=Math.floor(yz[i]*100)をスタート関数に入れて初期値にします。

[ソース]

<HTML>
<head>
<meta http-equiv="content-type" content="text/html; charset=shift_jis">
<META http-equiv="Content-Style-Type" content="text/css">
<title></title>
</head>
<body style="overflow:auto; margin:0px; padding:0px">
<img id="img1" src="yuki.gif" style="display:none">
<div id="stage" style="position:absolute; left:10px; top: 10px; background-color:black; width:600px; height:500px; overflow:hidden">
<script>
var ys=20//雪の数
var dd=5//落ちる重さ標準値
var th=30//上部配置位置
var bh=50//下部end位置
var sk=50//速度(ミリ秒)
var yt=2//雪の間隔(秒)
var hk=30//揺れ半径
var dg=10//揺れの周期角度
var ybmax=1.0//倍率最大値
var ybmin=0.3//倍率最小値

//設定ここまで
var yz=new Array()//雪の倍率用配列
var yd=new Array()//落ちる重さ用配列
var imgtop=new Array()//雪のTOP計算用配列
var imgleft=new Array()//雪のLFT用配列
var deg=new Array()
var hn=new Array()
var cx=new Array()
var imgObj=new Array()//雪オブジェクトを入れる配列

for(i=1;i<=20;i++){
document.write("<img src='"+img1.src+"' style='position:absolute; left:-1000px; top:0px'>")
}

imgObj=stage.all

function yukiMove(n){
imgtop[n]=(imgtop[n]+yd[n])%(th+stage.clientHeight+bh)
deg[n]=deg[n]+dg
imgleft[n]=Math.cos(deg[n]*Math.PI/180)*hn[n]+cx[n]
imgObj[n].style.pixelTop=imgtop[n]-th
imgObj[n].style.pixelLeft=imgleft[n]
setTimeout("yukiMove("+n+")",sk)
}

function yukistart(){
for(i=1;i<=ys;i++){

yz[i]=Math.random()*(ybmax-ybmin)+ybmin
hn[i]=hk*yz[i]

yd[i]=dd*yz[i]
deg[i]=Math.random()*360
cx[i]=Math.random()*(stage.clientWidth-25-25)+25
imgtop[i]=-th
imgleft[i]=Math.cos(deg[i]*Math.PI/180)*hn[i]+cx[i]
imgObj[i].style.zIndex=Math.floor(yz[i]*100)
imgObj[i].style.zoom=yz[i]

imgObj[i].style.pixelTop=imgtop[i]
imgObj[i].style.pixelLeft=imgleft[i]
setTimeout("yukiMove("+i+")",yt*(i-1)*1000)
}
}

setTimeout("yukistart()",3000)

</script>
</div>
</body>
</html>

雪降り横揺れ有サイズ違い有 z-index対策有

 

応用:このひな形のimgObj[n].style.pixelTop=imgtop[n]-thimgObj[n].style.pixelTop=stage.clientHeight+bh-imgtop[n]と変更し、imgObj[i].style.pixelTop=imgtop[i]imgObj[i].style.pixelTop=stage.clientHeight+bhと変更すると下から上に雪降りになります。

下から上に雪降り(たこたこ揚がれ!)

雪画像を一種類ではなく複数使用したい場合は、円運動の講座で行ったように剰余を使用してやってみてくださいね。

また揺れの周期角度を同じではなくランダムに設定するともっと変化に富んだ動きになることでしょう。

揺れの周期角度を最大値と最小値からランダムにセットするひな形を次に示しておきます。

下から上に雪降り(たこたこ揚がれ!)-揺れ方がランダム〜〜


[ひな形スクリプト講座1][ひな形スクリプト講座2][ひな形スクリプト講座3][ひな形スクリプト講座4][ひな形スクリプト講座5][ひな形スクリプト講座6][ひな形スクリプト講座7][ひな形スクリプト講座8][ひな形スクリプト講座9][ひな形スクリプト講座10][ひな形スクリプト講座11][ひな形スクリプト講座12][ひな形スクリプト講座13][ひな形スクリプト講座14][ひな形スクリプト講座15][ひな形スクリプト講座16][ひな形スクリプト講座17][ひな形スクリプト講座18][ひな形スクリプト講座19][ひな形スクリプト講座20][ひな形スクリプト講座21][ひな形スクリプト講座22][ひな形スクリプト講座23][ひな形スクリプト講座24][ひな形スクリプト講座25][ひな形スクリプト講座26][ひな形スクリプト講座27][ひな形スクリプト講座28][ひな形スクリプト講座29][ひな形スクリプト講座30][参考資料索引]