// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // sanctuary.hsp // Last Modified:2006/09/07-01:01. // // 無垢な瞳でのどかに暮らす彼らが、動き回ったりくっついたり破裂したりする様を静か // に見守る癒し系プログラム。 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // 定数定義 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // ブール #const TRUE 1 #const FALSE 0 // 行頭のコメント外すと、ちょっと特殊なSantuaryが楽しめる。 // 何気に本編よりも綺麗だったり ;#define SPECIAL_MODE #ifdef SPECIAL_MODE # const NUM_CREATURES 100 # const CREATURE_SIZE 7 #else # const NUM_CREATURES 24 # const CREATURE_SIZE 24 #endif #const CREATURE_SIZE_HALF CREATURE_SIZE / 2 // ウィンドウ系 #const WINDOW_WIDTH 640 #const WINDOW_HEIGHT 480 #const WINDOW_WIDTH_HALF WINDOW_WIDTH / 2 #const WINDOW_HEIGHT_HALF WINDOW_HEIGHT / 2 // 回転密度 #const RAD_DENSITY 32 // ライト #const LIGHT_SIZE 192 // バッファ系 #enum CREATURE_BUFFER_ID=2 #enum LIGHT_BUFFER_ID #ifdef SPECIAL_MODE #packopt name "sanctuary_sp" #else #packopt name "sanctuary" #endif // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // ここからメインプログラム // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - 初期化 - - - - // // 種植える randomize // 容量をケチるために少数型定数は変数を使用(#constは使わない) PI = 3.14159265358979 PI2 = 6.28318530717959 // - - - - ライト - - - - // buffer LIGHT_BUFFER_ID, LIGHT_SIZE, LIGHT_SIZE // 背景黒く塗って boxf // 真ん中に白い●を書く color 0x22, 0x22, 0x55 circle // - - - - クリーチャー - - - - // ; 何やってるか知りたいなら、buffer を screen に変えると分かりやすい buffer CREATURE_BUFFER_ID, CREATURE_SIZE * RAD_DENSITY, CREATURE_SIZE * 6 // 背景黒く塗って boxf // クリーチャーを書く repeat 6 creatureColor = cnt repeat RAD_DENSITY rad = PI2 * cnt / RAD_DENSITY x = cnt * CREATURE_SIZE y = creatureColor * CREATURE_SIZE // 本体 hsvcolor 32 * creatureColor, 0x22, 0xee repeat 2 if( cnt ) { color 0x01 } circle x, y, x + CREATURE_SIZE, y + CREATURE_SIZE, 1 - cnt loop #ifndef SPECIAL_MODE // 目 foo = 7, 8 eyeRadius = 5, 1 huge = -0.6, 0.6 repeat 2 dup _eyeRadius, eyeRadius.cnt dup _foo, foo.cnt repeat 2 px = cos( rad + huge.cnt ) * _foo + CREATURE_SIZE_HALF - _eyeRadius + x py = sin( rad + huge.cnt ) * _foo + CREATURE_SIZE_HALF - _eyeRadius + y circle px, py, px + _eyeRadius * 2, py + _eyeRadius * 2, 0 loop loop #endif loop loop // クリーチャーがらみ変数 repeat NUM_CREATURES creaturePosX.cnt = double( rnd( WINDOW_WIDTH ) ) creaturePosY.cnt = double( rnd( WINDOW_HEIGHT ) ) creatureSpeed.cnt = 2.0 creatureRad.cnt = 0.0 ;creatureHaveTarget.cnt = FALSE ;creatureShock.cnt = FALSE loop gsel _ginfo_wx1 = ginfo_wx1 _ginfo_wy1 = ginfo_wy1 #ifdef SPECIAL_MODE lightOffed = TRUE #endif // - - - - メインループ - - - - // repeat #ifdef SPECIAL_MODE dim bursted #endif // 画面初期化とか redraw : await 15 : redraw 0 // クリック stick key, 256 if( lightOffed ) { // 暗くする // ただしboxfではなくgmode 6 + gsquare の減算コピーを使って // すこしだけ残像が残るようにする color 0xff, 0xff, 0xaa gmode 6, WINDOW_WIDTH, WINDOW_HEIGHT, 40 ax = WINDOW_WIDTH, WINDOW_WIDTH ay.1 = WINDOW_HEIGHT, WINDOW_HEIGHT gsquare -1, ax, ay if( creatureShock > 230 ) { // ショック直後 // 加算コピーで閃光を再現 pget 3200 gmode 5, WINDOW_WIDTH, WINDOW_HEIGHT, ( creatureShock - 230 ) * 10 gsquare -1, ax, ay } if( key & 256 ) { lightStrength += ( lightStrength < 48 ) gmode 5, LIGHT_SIZE, LIGHT_SIZE, lightStrength pos mousex - LIGHT_SIZE / 2, mousey - LIGHT_SIZE / 2 gcopy LIGHT_BUFFER_ID } else { dim lightStrength } } else { pget 3200 boxf } // 明かり消したりつけたり if( key & 512 ) { lightOffed ^= 1 dim lightStrength } // - - - - クリーチャー - - - - // allConnected++ repeat NUM_CREATURES // オブジェクトのサイズを減らすために複製 dup _creaturePosX, creaturePosX.cnt dup _creaturePosY, creaturePosY.cnt dup _creatureSpeed, creatureSpeed.cnt dup _creatureRad, creatureRad.cnt dup _creatureHaveTarget, creatureHaveTarget.cnt dup _creatureShock, creatureShock.cnt // ターゲット _creatureTargetID = ( cnt + 1 ) \ NUM_CREATURES /** * NOTE: まじっくなんばーず * 0. 赤 * 1. 黄 * 2. 緑 * 3. 水 * 4. 青 * 5. 紫 */ creatureColor = cnt \ 6 // クリーチャーがショック受けてるなら減らしていく if( _creatureShock > 0 ) { _creatureShock-- } // スピードが1.5ならば減らす if( _creatureSpeed > 1.5 ) { dim _creatureHaveTarget _creatureSpeed -= 0.5 } if( _creatureSpeed < 1.0 ) { _creatureSpeed += 0.5 } if( _creatureSpeed = 1.5 ) { if( _creatureShock > 0 ) { _creatureSpeed = 5.0 } } // 自分とー〜ターゲット間の距離を計算 distance = sqrt( ( creaturePosX._creatureTargetID - _creaturePosX ) * ( creaturePosX._creatureTargetID - _creaturePosX ) + ( creaturePosY._creatureTargetID - _creaturePosY ) * ( creaturePosY._creatureTargetID - _creaturePosY ) ) // ターゲットの尻の方を向く。 // 回転しながら集結していく理由はこの変に起因する targetRad = atan( creaturePosY._creatureTargetID + sin( creatureRad._creatureTargetID ) * CREATURE_SIZE - _creaturePosY, creaturePosX._creatureTargetID + cos( creatureRad._creatureTargetID ) * CREATURE_SIZE - _creaturePosX ) _creatureRad += PI * ( 4 - rnd( 9 ) ) / 60.0 // ちょっとだけ回転(震わす) // _creatureRad が -PI ~ PI の間になるようにする if( _creatureRad > PI ) { _creatureRad -= PI2 } if( _creatureRad < -PI ) { _creatureRad += PI2 } // ライトが強いとき if( lightStrength == 48 ) { // ライト浴びてる時 if( sqrt( ( _creaturePosX - mousex ) * ( _creaturePosX - mousex ) + ( _creaturePosY - mousey ) * ( _creaturePosY - mousey ) ) < LIGHT_SIZE / 2 ) { if( rnd( 512 ) ) : else { // 一定確率で _creatureSpeed = 16.0 // 逃げる } } } // ウィンドウが動いたとき if( _ginfo_wx1 != ginfo_wx1 || _ginfo_wy1 != ginfo_wy1 ) { _creatureSpeed = 32.0 _creatureRad += PI dim _creatureHaveTarget _creatureShock = 240 * ( ( creatureColor == 2 ) + 1 ) } if( _creatureHaveTarget ) { // ターゲット持ち // 体をターゲットの方に向ける _creatureRad = targetRad if( distance > 32.0 ) { // このifが無いとちょっとキモくなる _creatureRad += PI * ( 4 - rnd( 9 ) ) / 60.0 // ちょっと震わす } if( distance < CREATURE_SIZE ) { _creatureSpeed = 0.3 // 近すぎるならゆっくり動かす if( bursted && ( creatureColor == 5 ) && rnd( 2048 ) == 0 ) { // 群れから逃げる _creatureRad += PI _creatureSpeed = 12.0 dim _creatureHaveTarget } if( ( creatureColor == 3 ) && rnd( 16 ) ) { // 前にいる奴をこづく if( creatureHaveTarget._creatureTargetID ) : else { creatureSpeed._creatureTargetID = 6.0 } } } if( distance > 4.0 ) { dim allConnected } if( distance > 300 ) { dim _creatureHaveTarget // 見失った _creatureRad -= PI / 8.0 } } else { dim allConnected if( creatureColor == 4 ) { // ゆっくり動く if( _creatureSpeed == 1.5 ) { _creatureSpeed = 0.5 } } if( rnd( 512 >> ( creatureColor == 0 ) * 2 ) == 0 ) { // 気まぐれで変な方向を向く _creatureRad -= ( rnd( 4 ) ) * PI / 2.0 } if( distance < 200 * ( ( creatureColor == 5 ) + 1 ) && absf( targetRad - _creatureRad ) < PI / 2.0 ) { // ターゲット発見か? if( _creatureShock == 0 ) { // ショックをうけてなかったら _creatureHaveTarget = TRUE // ターゲット発見! } } } if( bursted && creatureColor == 1 && rnd( 1024 ) == 0 ) { // しゃっくり _creatureSpeed -= 10.0 // 後ろに } // 体が画面からはみ出さない方法を探す // 何気に衝突を回避する為に決定付けられる向きが、左右均等に現れるようにしてあったり repeat 64 huga = PI2 / 64.0 * cnt * ( 1 - ( cnt & 1 << 1 ) ) creaturesGoalX = _creaturePosX + cos( _creatureRad + huga ) * _creatureSpeed * 32 creaturesGoalY = _creaturePosY + sin( _creatureRad + huga ) * _creatureSpeed * 32 if( ( int( creaturesGoalX - WINDOW_WIDTH_HALF ) / ( WINDOW_WIDTH_HALF - CREATURE_SIZE ) ) | ( int( creaturesGoalY - WINDOW_HEIGHT_HALF ) / ( WINDOW_HEIGHT_HALF - CREATURE_SIZE ) ) ) : else { // ぶつからないっぽい _creatureRad += huga // 決まり break } loop // 動かす _creaturePosX += cos( _creatureRad ) * _creatureSpeed _creaturePosY += sin( _creatureRad ) * _creatureSpeed // 描く pos _creaturePosX - CREATURE_SIZE_HALF, _creaturePosY - CREATURE_SIZE_HALF if( lightOffed ) { // 明るくするための加算コピー gmode 5, CREATURE_SIZE, CREATURE_SIZE, 48 + _creatureSpeed * 8 } else { // 普通にコピー(背景色の黒は無視) gmode 2, CREATURE_SIZE, CREATURE_SIZE } gcopy CREATURE_BUFFER_ID, ( ( int( _creatureRad * RAD_DENSITY / PI2 ) + RAD_DENSITY ) \ RAD_DENSITY ) * CREATURE_SIZE, CREATURE_SIZE * creatureColor loop if( allConnected ) { // 全部ひっ付いた // 破裂 repeat NUM_CREATURES creatureShock.cnt = 240 creatureSpeed.cnt = 32.0 poke creatureHaveTarget.cnt loop bursted = TRUE } // 古いウィンドウ座標を保存 _ginfo_wx1 = ginfo_wx1 _ginfo_wy1 = ginfo_wy1 loop