Repository: takahirox/toho-like-js Branch: master Commit: 8ff780d9a8bb Files: 46 Total size: 504.2 KB Directory structure: gitextract_2g3v46sm/ ├── README.md ├── TODO.txt ├── data/ │ ├── bosses_params.js │ ├── bullets_params.js │ ├── danmaku_helper.js │ ├── enemies_params.js │ ├── stage_params.js │ └── talk_params.js ├── index.html ├── index2.html ├── replay/ │ ├── replay1.txt │ ├── replay2.txt │ └── replay_list.txt ├── source/ │ ├── Background.js │ ├── Bomb.js │ ├── Boss.js │ ├── Bullet.js │ ├── CharacterSelectState.js │ ├── Effect.js │ ├── Element.js │ ├── EndingState.js │ ├── Enemy.js │ ├── EnemyBullet.js │ ├── Fighter.js │ ├── FighterOption.js │ ├── Game.js │ ├── GameSocket.js │ ├── GameState.js │ ├── Item.js │ ├── LoadingState.js │ ├── MoveVector.js │ ├── OpeningState.js │ ├── PostReplayState.js │ ├── ReplaySelectState.js │ ├── SpellCard.js │ ├── StaffRollState.js │ └── StageState.js ├── utility/ │ ├── Draw.js │ ├── FreeList.js │ ├── Inherit.js │ ├── Peer.js │ ├── Random.js │ └── WebGL.js ├── webgl_test.html ├── webrtc_test.html └── webrtc_trial.html ================================================ FILE CONTENTS ================================================ ================================================ FILE: README.md ================================================ # toho-like-js This is a touhou style danmaku shooter game which runs on your chrome. ## Demo [Demo](http://takahirox.github.io/toho-like-js/index.html) [Demo(online Co-op play)](http://takahirox.github.io/toho-like-js/index2.html) ## Online co-op play tutorial http://d.hatena.ne.jp/takahirox/20140920/1411190305 ## Screenshot    ## Features - fast rendering and many bullets with WebGL - online co-op play with WebRTC - watch other players real-time status with WebSocket - register your replay and watch other players replays ## Benchmarks [WebGL benchmark](http://takahirox.github.io/toho-like-js/webgl_test.html) [WebRTC performance test](http://takahirox.github.io/toho-like-js/webrtc_test.html) [WebRTC Simple test](http://takahirox.github.io/toho-like-js/webrtc_trial.html) ## Dependencies - [glMatrix](https://github.com/toji/gl-matrix) No any WebGL 3D libraries, yeah! ## Link [Touhou Project official site](http://www16.big.or.jp/~zun/) ================================================ FILE: TODO.txt ================================================ stage2 - bgm - bg boss finish bonus boss time limit spell card finish bonus vanish bullet enemy variation Boss effect Game pad API separate count up from run step? enemy beam collision multi power items divide area sin, cos, tan cache network ================================================ FILE: data/bosses_params.js ================================================ var __stage1BossParams = [ ] ; __stage1BossParams.push( { 'count': 2100, 'character': 'rumia', 'width': 128, 'height': 128, 'collisionWidth': 50, 'collisionHeight': 50, 'appearedTalk': false, 'vanishedTalk': false, 'dead': 'escape', 'x': 240, 'y': 0, 'animation': 3, 'powerItem': 1, 'score': 1000, 'params': [ { 'spellCard': false, 'x': 400, 'y': 150, 'vital': 200, 's': [ { 'bullet': 2, 'type': 5, 'r': 20, 'shotCount': [ 10, 20, 30, 280, 290, 300 ], 'baseCount': 600 }, { 'bullet': 3, 'type': 2, 'shotCount': [ 120, 420 ], 'baseCount': 600 }, { 'bullet': 4, 'type': 7, 'r': 20, 'shotCount': [ 310, 320, 330 ], 'baseCount': 600 }, { 'bullet':20, 'type': 6, 'shotCount': [ 130, 430 ], 'baseCount': 600 }, ], 'v': [ { 'count': 0, 'v': { 'r': 0, 'theta':180, 'w': 0, 'ra': 0, 'wa': 0, 'raa': 0, 'rrange': { min: 0 } } }, { 'count': 50, 'v': { 'r': 4, 'theta':200, 'w': 0, 'ra':-0.05, 'wa': 0, 'raa': 0, 'rrange': { min: 0 } } }, { 'count': 200, 'v': { 'r': 4, 'theta':160, 'w': 0, 'ra':-0.05, 'wa': 0, 'raa': 0, 'rrange': { min: 0 } } }, { 'count': 350, 'v': { 'r': 4, 'theta':340, 'w': 0, 'ra':-0.05, 'wa': 0, 'raa': 0, 'rrange': { min: 0 } } }, { 'count': 500, 'v': { 'r': 4, 'theta': 20, 'w': 0, 'ra':-0.05, 'wa': 0, 'raa': 0, 'rrange': { min: 0 } } }, { 'count': 600, 'v': 2 } ], }, ] } ) ; __stage1BossParams.push( { 'count': 3200, // 'count': 0, 'character': 'rumia', 'width': 128, 'height': 128, 'collisionWidth': 50, 'collisionHeight': 50, 'appearedTalk': true, 'vanishedTalk': true, 'x': 240, 'y': 0, 'animation': 3, 'powerItem': 1, 'score': 5000, 'params': [ { 'x': 240, 'y': 150, 'vital': 200, 's': [ { 'bullet': 2, 'type': 3, 'shotCount': [ 250, 260, 270, 280, 290 ], 'baseCount': 400 }, { 'bullet': 3, 'type': 3, 'shotCount': [ 340, 360 ], 'baseCount': 400 }, { 'bullet': 4, 'type': 3, 'shotCount': [ 255, 265, 275, 285, 295 ], 'baseCount': 400 }, { 'bullet': 5, 'type': 4, 'shotCount': [ 35, 37, 39, 41, 43, 45, 47, 49, 51, 53 ], 'baseCount': 400 }, { 'bullet': 6, 'type': 4, 'shotCount': [ 37, 39, 41, 43, 45, 47, 49, 51, 53, 55 ], 'baseCount': 400 }, { 'bullet': 7, 'type': 4, 'shotCount': [ 39, 41, 43, 45, 47, 49, 51, 53, 55, 57 ], 'baseCount': 400 }, { 'bullet': 8, 'type': 1, 'shotCount': [ 135 ], 'baseCount': 400 }, ], 'v': [ { 'count': 0, 'v': { 'r': 0, 'theta': 90, 'w': 0, 'ra': 0, 'wa': 0, 'raa': 0 } }, { 'count': 30, 'v': { 'r': 3, 'theta':290, 'w': 0, 'ra':-0.05, 'wa': 0, 'raa': 0, 'rrange': { min: 0 } } }, { 'count': 130, 'v': { 'r': 3, 'theta': 70, 'w': 0, 'ra':-0.05, 'wa': 0, 'raa': 0, 'rrange': { min: 0 } } }, { 'count': 230, 'v': { 'r': 3, 'theta':250, 'w': 0, 'ra':-0.05, 'wa': 0, 'raa': 0, 'rrange': { min: 0 } } }, { 'count': 330, 'v': { 'r': 3, 'theta':110, 'w': 0, 'ra':-0.05, 'wa': 0, 'raa': 0, 'rrange': { min: 0 } } }, { 'count': 400, 'v': 2 } ] }, { 'spellCard': 'Rumia\'s Spell 1', 'x': 240, 'y': 100, 'vital': 300, 's': [ { 'bullet': 9, 'type': 2, 'r': 20, 'shotCount': [ 50, 100, 150, 200 ], 'baseCount': 250 }, { 'bullet':10, 'type': 4, 'r': 20, 'shotCount': [ 25, 75, 125, 170 ], 'baseCount': 250 }, { 'bullet':11, 'shotCount': [ 50 ], 'baseCount': 250 }, ], 'v': [ { 'count': 0, 'v': { 'r': 0, 'theta': 90, 'w': 0, 'ra': 0, 'wa': 0, 'raa': 0, 'rrange': { min: 0 } } }, { 'count': 250, 'v': { 'r': 3, 'theta': 80, 'w': 0, 'ra':-0.05, 'wa': 0, 'raa': 0, 'rrange': { min: 0 } } }, { 'count': 500, 'v': { 'r': 3, 'theta':240, 'w': 0, 'ra':-0.05, 'wa': 0, 'raa': 0, 'rrange': { min: 0 } } }, { 'count': 750, 'v': { 'r': 3, 'theta':110, 'w': 0, 'ra':-0.05, 'wa': 0, 'raa': 0, 'rrange': { min: 0 } } }, { 'count':1000, 'v': { 'r': 3, 'theta':310 , 'w': 0, 'ra':-0.05, 'wa': 0, 'raa': 0, 'rrange': { min: 0 } } }, { 'count':1250, 'v': 2 } ] }, { 'spellCard': 'Rumia\'s Spell 2', 'x': 240, 'y': 100, 'vital': 300, 's': [ { 'bullet':12, 'type': 5, 'r': 20, 'shotCount': [ 0 ], 'baseCount': 1 }, { 'bullet':12, 'type': 6, 'r': 20, 'shotCount': [ 0 ], 'baseCount': 1 }, ], 'v': [ { 'count': 0, 'v': { 'r': 0, 'theta': 90, 'w': 0, 'ra': 0, 'wa': 0, 'raa': 0, 'rrange': { min: 0 } } }, ] }, ] } ) ; var __stage2BossParams = [ ] ; __stage2BossParams.push( { 'count': 2100, 'character': 'daiyousei', 'width': 128, 'height': 128, 'collisionWidth': 50, 'collisionHeight': 50, 'appearedTalk': false, 'vanishedTalk': false, 'x': 240, 'y': 0, 'animation': 3, 'powerItem': 1, 'score': 1000, 'params': [ { 'spellCard': false, 'x': 240, 'y': 150, 'vital': 250, 's': [ { 'bullet': 14, 'type': 8, 'shotCount': [ 10, 20, 30, 40 ], 'baseCount': 300 }, { 'bullet': 15, 'type': 9, 'shotCount': [ 160, 170, 180, 190 ], 'baseCount': 300 }, ], 'v': [ { 'count': 0, 'v': { 'r': 0, 'theta': 90 } }, { 'count': 149, 'v': { 'target': { 'x': { 'min': 50, 'max': 240 }, 'y': { 'min':100, 'max': 200 }, 'count': 1 } } }, { 'count': 150, 'v': { 'r': 0, 'theta': 90 } }, { 'count': 299, 'v': { 'target': { 'x': { 'min': 240, 'max': 430 }, 'y': { 'min':100, 'max': 200 }, 'count': 1 } } }, { 'count': 300, 'v': { 'r': 0, 'theta': 90 } }, { 'count': 449, 'v': { 'target': { 'x': { 'min': 190, 'max': 290 }, 'y': { 'min': 50, 'max': 150 }, 'count': 1 } } }, { 'count': 450, 'v': 2 } ], 'e': { 'vanish': { 'count': 100, 'length': 50, 'baseCount': 150 } } }, ] } ) ; __stage2BossParams.push( { 'count': 3200, // 'count': 0, 'character': 'chilno', 'width': 128, 'height': 128, 'collisionWidth': 50, 'collisionHeight': 50, 'appearedTalk': true, 'vanishedTalk': true, 'x': 240, 'y': 0, 'animation': 3, 'powerItem': 1, 'score': 5000, 'params': [ { 'spellCard': 'The star of Chilno', 'x': 240, 'y': 150, 'vital': 300, 's': [ { 'bullet':16, 'type': 4, 'shotCount': [ 20 ], 'baseCount': 100 }, ], 'v': [ { 'count': 0, 'v': { 'r': 0, 'theta': 90, 'w': 0, 'ra': 0, 'wa': 0, 'raa': 0 } }, ] }, { 'spellCard': 'Something freeze', 'x': 240, 'y': 100, 'vital': 300, 's': [ { 'bullet': 18, 'type': 2, 'r': 20, 'shotCount': [ 0 ], 'baseCount': 500 }, { 'bullet': 19, 'type': 3, 'r': 20, 'shotCount': [ 350, 355, 360, 365, 370, 375, 380 ], 'baseCount': 500 }, ], 'v': [ { 'count': 0, 'v': { 'r': 0, 'theta': 90, 'w': 0, 'ra': 0, 'wa': 0 } }, { 'count': 10, 'v': { 'target': { 'x': { 'min': 100, 'max': 340 }, 'y': { 'min': 80, 'max': 120 }, 'count':100 } } }, { 'count': 110, 'v': { 'r': 0, 'theta': 90, 'w': 0, 'ra': 0, 'wa': 0 } }, { 'count': 335, 'v': { 'target': { 'x': { 'min': 200, 'max': 280 }, 'y': { 'min': 80, 'max': 120 }, 'count': 35 } } }, { 'count': 370, 'v': { 'r': 0, 'theta': 90, 'w': 0, 'ra': 0, 'wa': 0 } }, { 'count': 500, 'v': 2 } ], 'e': { 'shockwave': [ { 'count': 175, 'baseCount': 500, 'params': { 'w': 10, 'g': 5, 'b': 7, 'a': 0.5, 'endCount': 100 } }, { 'count': 375, 'baseCount': 500, 'params': { 'w': 10, 'g': 5, 'b': 7, 'a': 0.5, 'endCount': 100 } } ] } }, { 'spellCard': 'Falling icicle', 'x': 240, 'y': 100, 'vital': 300, 's': [ { 'bullet':17, 'type': 7, 'r': 20, 'shotCount': [ 0 ], 'baseCount': 1 }, ], 'v': [ { 'count': 0, 'v': { 'r': 0, 'theta': 90, 'w': 0, 'ra': 0, 'wa': 0, 'raa': 0, 'rrange': { min: 0 } } }, { 'count': 50, 'v': { 'target': { 'x': { 'min': 190, 'max': 290 }, 'y': { 'min': 80, 'max': 120 }, 'count': 100 } } }, { 'count': 150, 'v': 2 }, ] }, ] } ) ; var __bossesParams = [ ] ; __bossesParams.push( __stage1BossParams ) ; __bossesParams.push( __stage2BossParams ) ; ================================================ FILE: data/bullets_params.js ================================================ var __danmakuHelper = new DanmakuHelper( ) ; var __bulletTypes = [ { 'image': 0, 'indexX': 3, 'indexY': 4, 'width': 16, 'height': 32, 'collisionWidth': 16, 'collisionHeight': 32, 'rotate': true }, { 'image': 0, 'indexX': 3, 'indexY': 3, 'width': 16, 'height': 32, 'collisionWidth': 16, 'collisionHeight': 32, 'rotate': true }, { 'image': 0, 'indexX': 1, 'indexY': 15, 'width': 16, 'height': 16, 'collisionWidth': 16, 'collisionHeight': 16, 'rotate': true }, { 'image': 0, 'indexX': 5, 'indexY': 0, 'width': 16, // 'height': 32, 'height': 256, 'collisionWidth': 16, 'collisionHeight': 32, 'rotate': true }, ] ; var __bulletsParams = [ [ [ [ { 'power': 1, 'x': 0, 'y': -20, 'v': { 'r':12, 'theta': 270, 'w': 0, 'ra': 0, 'wa': 0 }, }, ], [ { 'power': 0.6, 'x': -1, 'y': -20, 'v': { 'r':12, 'theta': 266, 'w': 0, 'ra': 0, 'wa': 0 }, }, { 'power': 0.6, 'x': 1, 'y': -20, 'v': { 'r':12, 'theta': 274, 'w': 0, 'ra': 0, 'wa': 0 }, }, { 'power': 0.50, 'option': 0, 'homing': true, 'nextCount': 50, 'v': { 'r':12, 'theta':210, 'w': 0, 'ra': 0.01, 'wa': 0, 'rrange': { 'max': 10 } }, }, { 'power': 0.50, 'option': 1, 'homing': true, 'nextCount': 50, 'v': { 'r':12, 'theta':330, 'w': 0, 'ra': 0.01, 'wa': 0, 'rrange': { 'max': 10 } }, }, ], [ { 'power': 0.46, 'x': -1, 'y': -20, 'v': { 'r':12, 'theta': 262, 'w': 0, 'ra': 0, 'wa': 0 }, }, { 'power': 0.46, 'x': 0, 'y': -20, 'v': { 'r':12, 'theta': 270, 'w': 0, 'ra': 0, 'wa': 0 }, }, { 'power': 0.46, 'x': 1, 'y': -20, 'v': { 'r':12, 'theta': 278, 'w': 0, 'ra': 0, 'wa': 0 }, }, { 'power': 0.40, 'option': 0, 'homing': true, 'nextCount': 20, 'v': { 'r':12, 'theta':210, 'w': 0, 'ra': 0.01, 'wa': 0, 'rrange': { 'max': 10 } }, }, { 'power': 0.40, 'option': 1, 'homing': true, 'nextCount': 20, 'v': { 'r':12, 'theta':330, 'w': 0, 'ra': 0.01, 'wa': 0, 'rrange': { 'max': 10 } }, }, ], [ { 'power': 0.4, 'x': -3, 'y': -20, 'v': { 'r':12, 'theta': 258, 'w': 0, 'ra': 0, 'wa': 0 }, }, { 'power': 0.4, 'x': -1, 'y': -20, 'v': { 'r':12, 'theta': 266, 'w': 0, 'ra': 0, 'wa': 0 }, }, { 'power': 0.4, 'x': 1, 'y': -20, 'v': { 'r':12, 'theta': 274, 'w': 0, 'ra': 0, 'wa': 0 }, }, { 'power': 0.4, 'x': 3, 'y': -20, 'v': { 'r':12, 'theta': 282, 'w': 0, 'ra': 0, 'wa': 0 }, }, { 'power': 0.30, 'option': 0, 'homing': true, 'nextCount': 10, 'v': { 'r':12, 'theta':210, 'w': 0, 'ra': 0.01, 'wa': 0, 'rrange': { 'max': 10 } }, }, { 'power': 0.30, 'option': 1, 'homing': true, 'nextCount': 10, 'v': { 'r':12, 'theta':330, 'w': 0, 'ra': 0.01, 'wa': 0, 'rrange': { 'max': 10 } }, }, ], ], [ [ { 'power': 1, 'x': 0, 'y': -20, 'v': { 'r':12, 'theta': 270, 'w': 0, 'ra': 0, 'wa': 0 }, }, ], [ { 'power': 0.6, 'x': -1, 'y': -20, 'v': { 'r':12, 'theta': 269, 'w': 0, 'ra': 0, 'wa': 0 }, }, { 'power': 0.6, 'x': 1, 'y': -20, 'v': { 'r':12, 'theta': 271, 'w': 0, 'ra': 0, 'wa': 0 }, }, { 'power': 0.5, 'option': 0, 'homing': true, 'nextCount': 50, 'v': { 'r':12, 'theta':260, 'w': 0, 'ra': 0.01, 'wa': 0, 'rrange': { 'max': 10 } }, }, { 'power': 0.5, 'option': 1, 'homing': true, 'nextCount': 50, 'v': { 'r':12, 'theta':280, 'w': 0, 'ra': 0.01, 'wa': 0, 'rrange': { 'max': 10 } }, }, ], [ { 'power': 0.46, 'x': -1, 'y': -20, 'v': { 'r':12, 'theta': 268, 'w': 0, 'ra': 0, 'wa': 0 }, }, { 'power': 0.46, 'x': 0, 'y': -20, 'v': { 'r':12, 'theta': 270, 'w': 0, 'ra': 0, 'wa': 0 }, }, { 'power': 0.46, 'x': 1, 'y': -20, 'v': { 'r':12, 'theta': 272, 'w': 0, 'ra': 0, 'wa': 0 }, }, { 'power': 0.4, 'option': 0, 'homing': true, 'nextCount': 20, 'v': { 'r':12, 'theta':260, 'w': 0, 'ra': 0.01, 'wa': 0, 'rrange': { 'max': 10 } }, }, { 'power': 0.4, 'option': 1, 'homing': true, 'nextCount': 20, 'v': { 'r':12, 'theta':280, 'w': 0, 'ra': 0.01, 'wa': 0, 'rrange': { 'max': 10 } }, }, ], [ { 'power': 0.4, 'x': -3, 'y': -20, 'v': { 'r':12, 'theta': 267, 'w': 0, 'ra': 0, 'wa': 0 }, }, { 'power': 0.4, 'x': -1, 'y': -20, 'v': { 'r':12, 'theta': 269, 'w': 0, 'ra': 0, 'wa': 0 }, }, { 'power': 0.4, 'x': 1, 'y': -20, 'v': { 'r':12, 'theta': 271, 'w': 0, 'ra': 0, 'wa': 0 }, }, { 'power': 0.4, 'x': 3, 'y': -20, 'v': { 'r':12, 'theta': 273, 'w': 0, 'ra': 0, 'wa': 0 }, }, { 'power': 0.3, 'option': 0, 'homing': true, 'nextCount': 10, 'v': { 'r':12, 'theta':260, 'w': 0, 'ra': 0.01, 'wa': 0, 'rrange': { 'max': 10 } }, }, { 'power': 0.3, 'option': 1, 'homing': true, 'nextCount': 10, 'v': { 'r':12, 'theta':280, 'w': 0, 'ra': 0.01, 'wa': 0, 'rrange': { 'max': 10 } }, }, ] ] ], [ [ [ { 'power': 1, 'x': 0, 'y': -20, 'v': { 'r':12, 'theta': 270, 'w': 0, 'ra': 0, 'wa': 0 }, }, ], [ { 'power': 0.6, 'x': -1, 'y': -20, 'v': { 'r':12, 'theta': 266, 'w': 0, 'ra': 0, 'wa': 0 }, }, { 'power': 0.6, 'x': 1, 'y': -20, 'v': { 'r':12, 'theta': 274, 'w': 0, 'ra': 0, 'wa': 0 }, }, { 'power': 1, 'laser': true, 'option': 0, 'keep': 80, 'waitCount': 50, 'nextCount': 220, 'v': { 'r': 0, 'theta': 270, 'w': 0, 'ra': 0, 'wa': 0 }, }, { 'power': 1, 'laser': true, 'option': 1, 'keep': 80, 'waitCount': 50, 'nextCount': 220, 'v': { 'r': 0, 'theta': 270, 'w': 0, 'ra': 0, 'wa': 0 }, }, ], [ { 'power': 0.46, 'x': -1, 'y': -20, 'v': { 'r':12, 'theta': 262, 'w': 0, 'ra': 0, 'wa': 0 }, }, { 'power': 0.46, 'x': 0, 'y': -20, 'v': { 'r':12, 'theta': 270, 'w': 0, 'ra': 0, 'wa': 0 }, }, { 'power': 0.46, 'x': 1, 'y': -20, 'v': { 'r':12, 'theta': 278, 'w': 0, 'ra': 0, 'wa': 0 }, }, { 'power': 1, 'option': 0, 'laser': true, 'keep': 80, 'waitCount': 40, 'nextCount': 210, 'v': { 'r': 0, 'theta': 270, 'w': 0, 'ra': 0, 'wa': 0 }, }, { 'power': 1, 'option': 1, 'laser': true, 'keep': 80, 'waitCount': 40, 'nextCount': 210, 'v': { 'r': 0, 'theta': 270, 'w': 0, 'ra': 0, 'wa': 0 }, }, ], [ { 'power': 0.4, 'x': -3, 'y': -20, 'v': { 'r':12, 'theta': 258, 'w': 0, 'ra': 0, 'wa': 0 }, }, { 'power': 0.4, 'x': -1, 'y': -20, 'v': { 'r':12, 'theta': 266, 'w': 0, 'ra': 0, 'wa': 0 }, }, { 'power': 0.4, 'x': 1, 'y': -20, 'v': { 'r':12, 'theta': 274, 'w': 0, 'ra': 0, 'wa': 0 }, }, { 'power': 0.4, 'x': 3, 'y': -20, 'v': { 'r':12, 'theta': 282, 'w': 0, 'ra': 0, 'wa': 0 }, }, { 'power': 1, 'option': 0, 'laser': true, 'keep': 80, 'waitCount': 30, 'nextCount': 200, 'v': { 'r': 0, 'theta': 270, 'w': 0, 'ra': 0, 'wa': 0 }, }, { 'power': 1, 'option': 1, 'laser': true, 'keep': 80, 'waitCount': 30, 'nextCount': 200, 'v': { 'r': 0, 'theta': 270, 'w': 0, 'ra': 0, 'wa': 0 }, }, ], ], [ [ { 'power': 1, 'x': 0, 'y': -20, 'v': { 'r':12, 'theta': 270, 'w': 0, 'ra': 0, 'wa': 0 }, }, ], [ { 'power': 0.6, 'x': -1, 'y': -20, 'v': { 'r':12, 'theta': 269, 'w': 0, 'ra': 0, 'wa': 0 }, }, { 'power': 0.6, 'x': 1, 'y': -20, 'v': { 'r':12, 'theta': 271, 'w': 0, 'ra': 0, 'wa': 0 }, }, { 'power': 1, 'option': 0, 'laser': true, 'keep': 80, 'waitCount': 50, 'nextCount': 120, 'v': { 'r': 0, 'theta': 270, 'w': 0, 'ra': 0, 'wa': 0 }, }, { 'power': 1, 'option': 1, 'laser': true, 'keep': 80, 'waitCount': 50, 'nextCount': 120, 'v': { 'r': 0, 'theta': 270, 'w': 0, 'ra': 0, 'wa': 0 }, }, ], [ { 'power': 0.46, 'x': -1, 'y': -20, 'v': { 'r':12, 'theta': 268, 'w': 0, 'ra': 0, 'wa': 0 }, }, { 'power': 0.46, 'x': 0, 'y': -20, 'v': { 'r':12, 'theta': 270, 'w': 0, 'ra': 0, 'wa': 0 }, }, { 'power': 0.46, 'x': 1, 'y': -20, 'v': { 'r':12, 'theta': 272, 'w': 0, 'ra': 0, 'wa': 0 }, }, { 'power': 1, 'option': 0, 'laser': true, 'keep': 80, 'waitCount': 40, 'nextCount': 110, 'v': { 'r': 0, 'theta': 270, 'w': 0, 'ra': 0, 'wa': 0 }, }, { 'power': 1, 'option': 1, 'laser': true, 'keep': 80, 'waitCount': 40, 'nextCount': 110, 'v': { 'r': 0, 'theta': 270, 'w': 0, 'ra': 0, 'wa': 0 }, }, ], [ { 'power': 0.4, 'x': -3, 'y': -20, 'v': { 'r':12, 'theta': 267, 'w': 0, 'ra': 0, 'wa': 0 }, }, { 'power': 0.4, 'x': -1, 'y': -20, 'v': { 'r':12, 'theta': 269, 'w': 0, 'ra': 0, 'wa': 0 }, }, { 'power': 0.4, 'x': 1, 'y': -20, 'v': { 'r':12, 'theta': 271, 'w': 0, 'ra': 0, 'wa': 0 }, }, { 'power': 0.4, 'x': 3, 'y': -20, 'v': { 'r':12, 'theta': 273, 'w': 0, 'ra': 0, 'wa': 0 }, }, { 'power': 1, 'option': 0, 'laser': true, 'keep': 80, 'waitCount': 30, 'nextCount': 100, 'v': { 'r': 0, 'theta': 270, 'w': 0, 'ra': 0, 'wa': 0 }, }, { 'power': 1, 'option': 1, 'laser': true, 'keep': 80, 'waitCount': 30, 'nextCount': 100, 'v': { 'r': 0, 'theta': 270, 'w': 0, 'ra': 0, 'wa': 0 }, }, ] ], ] ] ; var __enemyBulletsParams = [ [ { 'v': { 'r': 5, 'theta': 165, 'w': 0, 'ra': 0.1, 'wa': 0, 'raa': -0.01, 'rrange': { 'min': 2 } }, }, { 'v': { 'r': 5, 'theta': 135, 'w': 0, 'ra': 0.1, 'wa': 0, 'raa': -0.01, 'rrange': { 'min': 2 } }, }, { 'v': { 'r': 5, 'theta': 105, 'w': 0, 'ra': 0.1, 'wa': 0, 'raa': -0.01, 'rrange': { 'min': 2 } }, }, { 'v': { 'r': 5, 'theta': 75, 'w': 0, 'ra': 0.1, 'wa': 0, 'raa': -0.01, 'rrange': { 'min': 2 } }, }, { 'v': { 'r': 5, 'theta': 45, 'w': 0, 'ra': 0.1, 'wa': 0, 'raa': -0.01, 'rrange': { 'min': 2 } }, }, { 'v': { 'r': 5, 'theta': 15, 'w': 0, 'ra': 0.1, 'wa': 0, 'raa': -0.01, 'rrange': { 'min': 2 } }, }, ], [ { 'v': { 'aimed': true, 'r': 5, 'theta': 0, 'w': 0, 'ra': 0.1, 'wa': 0, 'raa': -0.01, 'rrange': { 'min': 3 } }, }, ], [ { 'v': { 'r': 5, 'theta': 0, 'w': 0, 'ra': 0.1, 'wa': 0, 'raa': -0.01, 'rrange': { 'min': 2 } }, }, { 'v': { 'r': 5, 'theta': 23, 'w': 0, 'ra': 0.1, 'wa': 0, 'raa': -0.01, 'rrange': { 'min': 2 } }, }, { 'v': { 'r': 5, 'theta': 45, 'w': 0, 'ra': 0.1, 'wa': 0, 'raa': -0.01, 'rrange': { 'min': 2 } }, }, { 'v': { 'r': 5, 'theta': 68, 'w': 0, 'ra': 0.1, 'wa': 0, 'raa': -0.01, 'rrange': { 'min': 2 } }, }, { 'v': { 'r': 5, 'theta': 90, 'w': 0, 'ra': 0.1, 'wa': 0, 'raa': -0.01, 'rrange': { 'min': 2 } }, }, { 'v': { 'r': 5, 'theta': 113, 'w': 0, 'ra': 0.1, 'wa': 0, 'raa': -0.01, 'rrange': { 'min': 2 } }, }, { 'v': { 'r': 5, 'theta': 135, 'w': 0, 'ra': 0.1, 'wa': 0, 'raa': -0.01, 'rrange': { 'min': 2 } }, }, { 'v': { 'r': 5, 'theta': 158, 'w': 0, 'ra': 0.1, 'wa': 0, 'raa': -0.01, 'rrange': { 'min': 2 } }, }, { 'v': { 'r': 5, 'theta': 180, 'w': 0, 'ra': 0.1, 'wa': 0, 'raa': -0.01, 'rrange': { 'min': 2 } }, }, { 'v': { 'r': 5, 'theta': 203, 'w': 0, 'ra': 0.1, 'wa': 0, 'raa': -0.01, 'rrange': { 'min': 2 } }, }, { 'v': { 'r': 5, 'theta': 225, 'w': 0, 'ra': 0.1, 'wa': 0, 'raa': -0.01, 'rrange': { 'min': 2 } }, }, { 'v': { 'r': 5, 'theta': 248, 'w': 0, 'ra': 0.1, 'wa': 0, 'raa': -0.01, 'rrange': { 'min': 2 } }, }, { 'v': { 'r': 5, 'theta': 270, 'w': 0, 'ra': 0.1, 'wa': 0, 'raa': -0.01, 'rrange': { 'min': 2 } }, }, { 'v': { 'r': 5, 'theta': 293, 'w': 0, 'ra': 0.1, 'wa': 0, 'raa': -0.01, 'rrange': { 'min': 2 } }, }, { 'v': { 'r': 5, 'theta': 315, 'w': 0, 'ra': 0.1, 'wa': 0, 'raa': -0.01, 'rrange': { 'min': 2 } }, }, { 'v': { 'r': 5, 'theta': 338, 'w': 0, 'ra': 0.1, 'wa': 0, 'raa': -0.01, 'rrange': { 'min': 2 } }, }, ], // TODO: simplify [ { 'v': [ { 'count': 0, 'v': { 'r': 0, 'theta': 0, 'w': 0, 'ra': 0, 'wa': 0 } }, { 'count': 5, 'v': { 'r': 0, 'w': 0, 'ra':0.1, 'wa': 0, 'rrange': { 'max': 3 } } }, ] }, { 'v': [ { 'count': 0, 'v': { 'r': 0, 'theta': 5, 'w': 0, 'ra': 0, 'wa': 0 } }, { 'count': 10, 'v': { 'r': 0, 'w': 0, 'ra':0.1, 'wa': 0, 'rrange': { 'max': 3 } } }, ] }, { 'v': [ { 'count': 0, 'v': { 'r': 0, 'theta': 10, 'w': 0, 'ra': 0, 'wa': 0 } }, { 'count': 15, 'v': { 'r': 0, 'w': 0, 'ra':0.1, 'wa': 0, 'rrange': { 'max': 3 } } }, ] }, { 'v': [ { 'count': 0, 'v': { 'r': 0, 'theta': 15, 'w': 0, 'ra': 0, 'wa': 0 } }, { 'count': 20, 'v': { 'r': 0, 'w': 0, 'ra':0.1, 'wa': 0, 'rrange': { 'max': 3 } } }, ] }, { 'v': [ { 'count': 0, 'v': { 'r': 0, 'theta': 20, 'w': 0, 'ra': 0, 'wa': 0 } }, { 'count': 25, 'v': { 'r': 0, 'w': 0, 'ra':0.1, 'wa': 0, 'rrange': { 'max': 3 } } }, ] }, { 'v': [ { 'count': 0, 'v': { 'r': 0, 'theta': 45, 'w': 0, 'ra': 0, 'wa': 0 } }, { 'count': 5, 'v': { 'r': 0, 'w': 0, 'ra':0.1, 'wa': 0, 'rrange': { 'max': 3 } } }, ] }, { 'v': [ { 'count': 0, 'v': { 'r': 0, 'theta': 50, 'w': 0, 'ra': 0, 'wa': 0 } }, { 'count': 10, 'v': { 'r': 0, 'w': 0, 'ra':0.1, 'wa': 0, 'rrange': { 'max': 3 } } }, ] }, { 'v': [ { 'count': 0, 'v': { 'r': 0, 'theta': 55, 'w': 0, 'ra': 0, 'wa': 0 } }, { 'count': 15, 'v': { 'r': 0, 'w': 0, 'ra':0.1, 'wa': 0, 'rrange': { 'max': 3 } } }, ] }, { 'v': [ { 'count': 0, 'v': { 'r': 0, 'theta': 60, 'w': 0, 'ra': 0, 'wa': 0 } }, { 'count': 20, 'v': { 'r': 0, 'w': 0, 'ra':0.1, 'wa': 0, 'rrange': { 'max': 3 } } }, ] }, { 'v': [ { 'count': 0, 'v': { 'r': 0, 'theta': 65, 'w': 0, 'ra': 0, 'wa': 0 } }, { 'count': 25, 'v': { 'r': 0, 'w': 0, 'ra':0.1, 'wa': 0, 'rrange': { 'max': 3 } } }, ] }, { 'v': [ { 'count': 0, 'v': { 'r': 0, 'theta': 90, 'w': 0, 'ra': 0, 'wa': 0 } }, { 'count': 5, 'v': { 'r': 0, 'w': 0, 'ra':0.1, 'wa': 0, 'rrange': { 'max': 3 } } }, ] }, { 'v': [ { 'count': 0, 'v': { 'r': 0, 'theta': 95, 'w': 0, 'ra': 0, 'wa': 0 } }, { 'count': 10, 'v': { 'r': 0, 'w': 0, 'ra':0.1, 'wa': 0, 'rrange': { 'max': 3 } } }, ] }, { 'v': [ { 'count': 0, 'v': { 'r': 0, 'theta': 100, 'w': 0, 'ra': 0, 'wa': 0 } }, { 'count': 15, 'v': { 'r': 0, 'w': 0, 'ra':0.1, 'wa': 0, 'rrange': { 'max': 3 } } }, ] }, { 'v': [ { 'count': 0, 'v': { 'r': 0, 'theta': 105, 'w': 0, 'ra': 0, 'wa': 0 } }, { 'count': 20, 'v': { 'r': 0, 'w': 0, 'ra':0.1, 'wa': 0, 'rrange': { 'max': 3 } } }, ] }, { 'v': [ { 'count': 0, 'v': { 'r': 0, 'theta': 110, 'w': 0, 'ra': 0, 'wa': 0 } }, { 'count': 25, 'v': { 'r': 0, 'w': 0, 'ra':0.1, 'wa': 0, 'rrange': { 'max': 3 } } }, ] }, { 'v': [ { 'count': 0, 'v': { 'r': 0, 'theta': 135, 'w': 0, 'ra': 0, 'wa': 0 } }, { 'count': 5, 'v': { 'r': 0, 'w': 0, 'ra':0.1, 'wa': 0, 'rrange': { 'max': 3 } } }, ] }, { 'v': [ { 'count': 0, 'v': { 'r': 0, 'theta': 140, 'w': 0, 'ra': 0, 'wa': 0 } }, { 'count': 10, 'v': { 'r': 0, 'w': 0, 'ra':0.1, 'wa': 0, 'rrange': { 'max': 3 } } }, ] }, { 'v': [ { 'count': 0, 'v': { 'r': 0, 'theta': 145, 'w': 0, 'ra': 0, 'wa': 0 } }, { 'count': 15, 'v': { 'r': 0, 'w': 0, 'ra':0.1, 'wa': 0, 'rrange': { 'max': 3 } } }, ] }, { 'v': [ { 'count': 0, 'v': { 'r': 0, 'theta': 150, 'w': 0, 'ra': 0, 'wa': 0 } }, { 'count': 20, 'v': { 'r': 0, 'w': 0, 'ra':0.1, 'wa': 0, 'rrange': { 'max': 3 } } }, ] }, { 'v': [ { 'count': 0, 'v': { 'r': 0, 'theta': 155, 'w': 0, 'ra': 0, 'wa': 0 } }, { 'count': 25, 'v': { 'r': 0, 'w': 0, 'ra':0.1, 'wa': 0, 'rrange': { 'max': 3 } } }, ] }, { 'v': [ { 'count': 0, 'v': { 'r': 0, 'theta': 180, 'w': 0, 'ra': 0, 'wa': 0 } }, { 'count': 5, 'v': { 'r': 0, 'w': 0, 'ra':0.1, 'wa': 0, 'rrange': { 'max': 3 } } }, ] }, { 'v': [ { 'count': 0, 'v': { 'r': 0, 'theta': 185, 'w': 0, 'ra': 0, 'wa': 0 } }, { 'count': 10, 'v': { 'r': 0, 'w': 0, 'ra':0.1, 'wa': 0, 'rrange': { 'max': 3 } } }, ] }, { 'v': [ { 'count': 0, 'v': { 'r': 0, 'theta': 190, 'w': 0, 'ra': 0, 'wa': 0 } }, { 'count': 15, 'v': { 'r': 0, 'w': 0, 'ra':0.1, 'wa': 0, 'rrange': { 'max': 3 } } }, ] }, { 'v': [ { 'count': 0, 'v': { 'r': 0, 'theta': 195, 'w': 0, 'ra': 0, 'wa': 0 } }, { 'count': 20, 'v': { 'r': 0, 'w': 0, 'ra':0.1, 'wa': 0, 'rrange': { 'max': 3 } } }, ] }, { 'v': [ { 'count': 0, 'v': { 'r': 0, 'theta': 200, 'w': 0, 'ra': 0, 'wa': 0 } }, { 'count': 25, 'v': { 'r': 0, 'w': 0, 'ra':0.1, 'wa': 0, 'rrange': { 'max': 3 } } }, ] }, { 'v': [ { 'count': 0, 'v': { 'r': 0, 'theta': 225, 'w': 0, 'ra': 0, 'wa': 0 } }, { 'count': 5, 'v': { 'r': 0, 'w': 0, 'ra':0.1, 'wa': 0, 'rrange': { 'max': 3 } } }, ] }, { 'v': [ { 'count': 0, 'v': { 'r': 0, 'theta': 230, 'w': 0, 'ra': 0, 'wa': 0 } }, { 'count': 10, 'v': { 'r': 0, 'w': 0, 'ra':0.1, 'wa': 0, 'rrange': { 'max': 3 } } }, ] }, { 'v': [ { 'count': 0, 'v': { 'r': 0, 'theta': 235, 'w': 0, 'ra': 0, 'wa': 0 } }, { 'count': 15, 'v': { 'r': 0, 'w': 0, 'ra':0.1, 'wa': 0, 'rrange': { 'max': 3 } } }, ] }, { 'v': [ { 'count': 0, 'v': { 'r': 0, 'theta': 240, 'w': 0, 'ra': 0, 'wa': 0 } }, { 'count': 20, 'v': { 'r': 0, 'w': 0, 'ra':0.1, 'wa': 0, 'rrange': { 'max': 3 } } }, ] }, { 'v': [ { 'count': 0, 'v': { 'r': 0, 'theta': 245, 'w': 0, 'ra': 0, 'wa': 0 } }, { 'count': 25, 'v': { 'r': 0, 'w': 0, 'ra':0.1, 'wa': 0, 'rrange': { 'max': 3 } } }, ] }, { 'v': [ { 'count': 0, 'v': { 'r': 0, 'theta': 270, 'w': 0, 'ra': 0, 'wa': 0 } }, { 'count': 5, 'v': { 'r': 0, 'w': 0, 'ra':0.1, 'wa': 0, 'rrange': { 'max': 3 } } }, ] }, { 'v': [ { 'count': 0, 'v': { 'r': 0, 'theta': 275, 'w': 0, 'ra': 0, 'wa': 0 } }, { 'count': 10, 'v': { 'r': 0, 'w': 0, 'ra':0.1, 'wa': 0, 'rrange': { 'max': 3 } } }, ] }, { 'v': [ { 'count': 0, 'v': { 'r': 0, 'theta': 280, 'w': 0, 'ra': 0, 'wa': 0 } }, { 'count': 15, 'v': { 'r': 0, 'w': 0, 'ra':0.1, 'wa': 0, 'rrange': { 'max': 3 } } }, ] }, { 'v': [ { 'count': 0, 'v': { 'r': 0, 'theta': 285, 'w': 0, 'ra': 0, 'wa': 0 } }, { 'count': 20, 'v': { 'r': 0, 'w': 0, 'ra':0.1, 'wa': 0, 'rrange': { 'max': 3 } } }, ] }, { 'v': [ { 'count': 0, 'v': { 'r': 0, 'theta': 290, 'w': 0, 'ra': 0, 'wa': 0 } }, { 'count': 25, 'v': { 'r': 0, 'w': 0, 'ra':0.1, 'wa': 0, 'rrange': { 'max': 3 } } }, ] }, { 'v': [ { 'count': 0, 'v': { 'r': 0, 'theta': 315, 'w': 0, 'ra': 0, 'wa': 0 } }, { 'count': 5, 'v': { 'r': 0, 'w': 0, 'ra':0.1, 'wa': 0, 'rrange': { 'max': 3 } } }, ] }, { 'v': [ { 'count': 0, 'v': { 'r': 0, 'theta': 320, 'w': 0, 'ra': 0, 'wa': 0 } }, { 'count': 10, 'v': { 'r': 0, 'w': 0, 'ra':0.1, 'wa': 0, 'rrange': { 'max': 3 } } }, ] }, { 'v': [ { 'count': 0, 'v': { 'r': 0, 'theta': 325, 'w': 0, 'ra': 0, 'wa': 0 } }, { 'count': 15, 'v': { 'r': 0, 'w': 0, 'ra':0.1, 'wa': 0, 'rrange': { 'max': 3 } } }, ] }, { 'v': [ { 'count': 0, 'v': { 'r': 0, 'theta': 330, 'w': 0, 'ra': 0, 'wa': 0 } }, { 'count': 20, 'v': { 'r': 0, 'w': 0, 'ra':0.1, 'wa': 0, 'rrange': { 'max': 3 } } }, ] }, { 'v': [ { 'count': 0, 'v': { 'r': 0, 'theta': 335, 'w': 0, 'ra': 0, 'wa': 0 } }, { 'count': 25, 'v': { 'r': 0, 'w': 0, 'ra':0.1, 'wa': 0, 'rrange': { 'max': 3 } } }, ] }, ], [ { 'v': { 'r': 5, 'theta': 12, 'w': 0, 'ra': 0.1, 'wa': 0, 'raa': -0.01, 'rrange': { 'min': 2 } }, }, { 'v': { 'r': 5, 'theta': 35, 'w': 0, 'ra': 0.1, 'wa': 0, 'raa': -0.01, 'rrange': { 'min': 2 } }, }, { 'v': { 'r': 5, 'theta': 57, 'w': 0, 'ra': 0.1, 'wa': 0, 'raa': -0.01, 'rrange': { 'min': 2 } }, }, { 'v': { 'r': 5, 'theta': 80, 'w': 0, 'ra': 0.1, 'wa': 0, 'raa': -0.01, 'rrange': { 'min': 2 } }, }, { 'v': { 'r': 5, 'theta': 102, 'w': 0, 'ra': 0.1, 'wa': 0, 'raa': -0.01, 'rrange': { 'min': 2 } }, }, { 'v': { 'r': 5, 'theta': 125, 'w': 0, 'ra': 0.1, 'wa': 0, 'raa': -0.01, 'rrange': { 'min': 2 } }, }, { 'v': { 'r': 5, 'theta': 147, 'w': 0, 'ra': 0.1, 'wa': 0, 'raa': -0.01, 'rrange': { 'min': 2 } }, }, { 'v': { 'r': 5, 'theta': 170, 'w': 0, 'ra': 0.1, 'wa': 0, 'raa': -0.01, 'rrange': { 'min': 2 } }, }, { 'v': { 'r': 5, 'theta': 192, 'w': 0, 'ra': 0.1, 'wa': 0, 'raa': -0.01, 'rrange': { 'min': 2 } }, }, { 'v': { 'r': 5, 'theta': 215, 'w': 0, 'ra': 0.1, 'wa': 0, 'raa': -0.01, 'rrange': { 'min': 2 } }, }, { 'v': { 'r': 5, 'theta': 237, 'w': 0, 'ra': 0.1, 'wa': 0, 'raa': -0.01, 'rrange': { 'min': 2 } }, }, { 'v': { 'r': 5, 'theta': 260, 'w': 0, 'ra': 0.1, 'wa': 0, 'raa': -0.01, 'rrange': { 'min': 2 } }, }, { 'v': { 'r': 5, 'theta': 282, 'w': 0, 'ra': 0.1, 'wa': 0, 'raa': -0.01, 'rrange': { 'min': 2 } }, }, { 'v': { 'r': 5, 'theta': 305, 'w': 0, 'ra': 0.1, 'wa': 0, 'raa': -0.01, 'rrange': { 'min': 2 } }, }, { 'v': { 'r': 5, 'theta': 327, 'w': 0, 'ra': 0.1, 'wa': 0, 'raa': -0.01, 'rrange': { 'min': 2 } }, }, { 'v': { 'r': 5, 'theta': 350, 'w': 0, 'ra': 0.1, 'wa': 0, 'raa': -0.01, 'rrange': { 'min': 2 } }, }, ], [ { 'v': { 'aimed': true, 'r': 5, 'theta':-10, 'w': 0, 'ra': 0.1, 'wa': 0, 'raa': -0.01, 'rrange': { 'min': 3 } }, }, ], [ { 'v': { 'aimed': true, 'r': 5, 'theta': 0, 'w': 0, 'ra': 0.1, 'wa': 0, 'raa': -0.01, 'rrange': { 'min': 3 } }, }, ], [ { 'v': { 'aimed': true, 'r': 5, 'theta': 10, 'w': 0, 'ra': 0.1, 'wa': 0, 'raa': -0.01, 'rrange': { 'min': 3 } }, }, ], [ { 'v': [ { 'count': 0, 'v': { 'r': 0, 'theta': 30, 'w': 0, 'ra': 0.1, 'wa': 0, 'raa': 0.01, 'rrange': { 'max': 3 } } }, ] }, { 'v': [ { 'count': 0, 'v': { 'r': 0, 'theta': 35, 'w': 0, 'ra': 0.1, 'wa': 0, 'raa': 0.01, 'rrange': { 'max': 3.1 } } }, ] }, { 'v': [ { 'count': 0, 'v': { 'r': 0, 'theta': 40, 'w': 0, 'ra': 0.1, 'wa': 0, 'raa': 0.01, 'rrange': { 'max': 3.2 } } }, ] }, { 'v': [ { 'count': 0, 'v': { 'r': 0, 'theta': 45, 'w': 0, 'ra': 0.1, 'wa': 0, 'raa': 0.01, 'rrange': { 'max': 3.3 } } }, ] }, { 'v': [ { 'count': 0, 'v': { 'r': 0, 'theta': 50, 'w': 0, 'ra': 0.1, 'wa': 0, 'raa': 0.01, 'rrange': { 'max': 3.4 } } }, ] }, { 'v': [ { 'count': 0, 'v': { 'r': 0, 'theta': 55, 'w': 0, 'ra': 0.1, 'wa': 0, 'raa': 0.01, 'rrange': { 'max': 3.5 } } }, ] }, { 'v': [ { 'count': 0, 'v': { 'r': 0, 'theta': 60, 'w': 0, 'ra': 0.1, 'wa': 0, 'raa': 0.01, 'rrange': { 'max': 3.6 } } }, ] }, { 'v': [ { 'count': 0, 'v': { 'r': 0, 'theta': 65, 'w': 0, 'ra': 0.1, 'wa': 0, 'raa': 0.01, 'rrange': { 'max': 3.7 } } }, ] }, { 'v': [ { 'count': 0, 'v': { 'r': 0, 'theta': 70, 'w': 0, 'ra': 0.1, 'wa': 0, 'raa': 0.01, 'rrange': { 'max': 3.8 } } }, ] }, { 'v': [ { 'count': 0, 'v': { 'r': 0, 'theta': 75, 'w': 0, 'ra': 0.1, 'wa': 0, 'raa': 0.01, 'rrange': { 'max': 3.9 } } }, ] }, { 'v': [ { 'count': 0, 'v': { 'r': 0, 'theta': 80, 'w': 0, 'ra': 0.1, 'wa': 0, 'raa': 0.01, 'rrange': { 'max': 4.0 } } }, ] }, { 'v': [ { 'count': 0, 'v': { 'r': 0, 'theta': 85, 'w': 0, 'ra': 0.1, 'wa': 0, 'raa': 0.01, 'rrange': { 'max': 4.1 } } }, ] }, { 'v': [ { 'count': 0, 'v': { 'r': 0, 'theta': 90, 'w': 0, 'ra': 0.1, 'wa': 0, 'raa': 0.01, 'rrange': { 'max': 4.2 } } }, ] }, { 'v': [ { 'count': 0, 'v': { 'r': 0, 'theta': 95, 'w': 0, 'ra': 0.1, 'wa': 0, 'raa': 0.01, 'rrange': { 'max': 4.3 } } }, ] }, { 'v': [ { 'count': 0, 'v': { 'r': 0, 'theta': 100, 'w': 0, 'ra': 0.1, 'wa': 0, 'raa': 0.01, 'rrange': { 'max': 4.4 } } }, ] }, { 'v': [ { 'count': 0, 'v': { 'r': 0, 'theta': 105, 'w': 0, 'ra': 0.1, 'wa': 0, 'raa': 0.01, 'rrange': { 'max': 4.5 } } }, ] }, { 'v': [ { 'count': 0, 'v': { 'r': 0, 'theta': 110, 'w': 0, 'ra': 0.1, 'wa': 0, 'raa': 0.01, 'rrange': { 'max': 4.6 } } }, ] }, { 'v': [ { 'count': 0, 'v': { 'r': 0, 'theta': 115, 'w': 0, 'ra': 0.1, 'wa': 0, 'raa': 0.01, 'rrange': { 'max': 4.7 } } }, ] }, { 'v': [ { 'count': 0, 'v': { 'r': 0, 'theta': 120, 'w': 0, 'ra': 0.1, 'wa': 0, 'raa': 0.01, 'rrange': { 'max': 4.8 } } }, ] }, { 'v': [ { 'count': 0, 'v': { 'r': 0, 'theta': 125, 'w': 0, 'ra': 0.1, 'wa': 0, 'raa': 0.01, 'rrange': { 'max': 4.9 } } }, ] }, { 'v': [ { 'count': 0, 'v': { 'r': 0, 'theta': 130, 'w': 0, 'ra': 0.1, 'wa': 0, 'raa': 0.01, 'rrange': { 'max': 5.0 } } }, ] }, { 'v': [ { 'count': 0, 'v': { 'r': 0, 'theta': 135, 'w': 0, 'ra': 0.1, 'wa': 0, 'raa': 0.01, 'rrange': { 'max': 5.1 } } }, ] }, { 'v': [ { 'count': 0, 'v': { 'r': 0, 'theta': 140, 'w': 0, 'ra': 0.1, 'wa': 0, 'raa': 0.01, 'rrange': { 'max': 5.2 } } }, ] }, { 'v': [ { 'count': 0, 'v': { 'r': 0, 'theta': 145, 'w': 0, 'ra': 0.1, 'wa': 0, 'raa': 0.01, 'rrange': { 'max': 5.3 } } }, ] }, { 'v': [ { 'count': 0, 'v': { 'r': 0, 'theta': 150, 'w': 0, 'ra': 0.1, 'wa': 0, 'raa': 0.01, 'rrange': { 'max': 5.4 } } }, ] }, ], [ { 'v': [ { 'count': 0, 'v': { 'r': 0, 'theta': 0, 'w': 0, 'ra': 0.1, 'wa': 0, 'raa': 0.01, 'rrange': { 'max': 3 } } }, ] }, { 'v': [ { 'count': 0, 'v': { 'r': 0, 'theta': 10, 'w': 0, 'ra': 0.1, 'wa': 0, 'raa': 0.01, 'rrange': { 'max': 3.2 } } }, ] }, { 'v': [ { 'count': 0, 'v': { 'r': 0, 'theta': 20, 'w': 0, 'ra': 0.1, 'wa': 0, 'raa': 0.01, 'rrange': { 'max': 3.4 } } }, ] }, { 'v': [ { 'count': 0, 'v': { 'r': 0, 'theta': 30, 'w': 0, 'ra': 0.1, 'wa': 0, 'raa': 0.01, 'rrange': { 'max': 3.6 } } }, ] }, { 'v': [ { 'count': 0, 'v': { 'r': 0, 'theta': 40, 'w': 0, 'ra': 0.1, 'wa': 0, 'raa': 0.01, 'rrange': { 'max': 3.8 } } }, ] }, { 'v': [ { 'count': 0, 'v': { 'r': 0, 'theta': 50, 'w': 0, 'ra': 0.1, 'wa': 0, 'raa': 0.01, 'rrange': { 'max': 4.0 } } }, ] }, { 'v': [ { 'count': 0, 'v': { 'r': 0, 'theta': 60, 'w': 0, 'ra': 0.1, 'wa': 0, 'raa': 0.01, 'rrange': { 'max': 4.2 } } }, ] }, { 'v': [ { 'count': 0, 'v': { 'r': 0, 'theta': 70, 'w': 0, 'ra': 0.1, 'wa': 0, 'raa': 0.01, 'rrange': { 'max': 4.4 } } }, ] }, { 'v': [ { 'count': 0, 'v': { 'r': 0, 'theta': 80, 'w': 0, 'ra': 0.1, 'wa': 0, 'raa': 0.01, 'rrange': { 'max': 4.6 } } }, ] }, { 'v': [ { 'count': 0, 'v': { 'r': 0, 'theta': 90, 'w': 0, 'ra': 0.1, 'wa': 0, 'raa': 0.01, 'rrange': { 'max': 4.8 } } }, ] }, { 'v': [ { 'count': 0, 'v': { 'r': 0, 'theta': 100, 'w': 0, 'ra': 0.1, 'wa': 0, 'raa': 0.01, 'rrange': { 'max': 5.0 } } }, ] }, { 'v': [ { 'count': 0, 'v': { 'r': 0, 'theta': 110, 'w': 0, 'ra': 0.1, 'wa': 0, 'raa': 0.01, 'rrange': { 'max': 5.2 } } }, ] }, { 'v': [ { 'count': 0, 'v': { 'r': 0, 'theta': 120, 'w': 0, 'ra': 0.1, 'wa': 0, 'raa': 0.01, 'rrange': { 'max': 5.4 } } }, ] }, { 'v': [ { 'count': 0, 'v': { 'r': 0, 'theta': 130, 'w': 0, 'ra': 0.1, 'wa': 0, 'raa': 0.01, 'rrange': { 'max': 5.6 } } }, ] }, ], [ { 'v': [ { 'count': 0, 'v': { 'r': 0, 'theta': 175, 'w': 0, 'ra': 0.1, 'wa': 0, 'raa': 0.01, 'rrange': { 'max': 3.1 } } }, ] }, { 'v': [ { 'count': 0, 'v': { 'r': 0, 'theta': 165, 'w': 0, 'ra': 0.1, 'wa': 0, 'raa': 0.01, 'rrange': { 'max': 3.3 } } }, ] }, { 'v': [ { 'count': 0, 'v': { 'r': 0, 'theta': 155, 'w': 0, 'ra': 0.1, 'wa': 0, 'raa': 0.01, 'rrange': { 'max': 3.5 } } }, ] }, { 'v': [ { 'count': 0, 'v': { 'r': 0, 'theta': 145, 'w': 0, 'ra': 0.1, 'wa': 0, 'raa': 0.01, 'rrange': { 'max': 3.7 } } }, ] }, { 'v': [ { 'count': 0, 'v': { 'r': 0, 'theta': 135, 'w': 0, 'ra': 0.1, 'wa': 0, 'raa': 0.01, 'rrange': { 'max': 3.9 } } }, ] }, { 'v': [ { 'count': 0, 'v': { 'r': 0, 'theta': 125, 'w': 0, 'ra': 0.1, 'wa': 0, 'raa': 0.01, 'rrange': { 'max': 4.1 } } }, ] }, { 'v': [ { 'count': 0, 'v': { 'r': 0, 'theta': 115, 'w': 0, 'ra': 0.1, 'wa': 0, 'raa': 0.01, 'rrange': { 'max': 4.3 } } }, ] }, { 'v': [ { 'count': 0, 'v': { 'r': 0, 'theta': 105, 'w': 0, 'ra': 0.1, 'wa': 0, 'raa': 0.01, 'rrange': { 'max': 4.5 } } }, ] }, { 'v': [ { 'count': 0, 'v': { 'r': 0, 'theta': 95, 'w': 0, 'ra': 0.1, 'wa': 0, 'raa': 0.01, 'rrange': { 'max': 4.7 } } }, ] }, { 'v': [ { 'count': 0, 'v': { 'r': 0, 'theta': 85, 'w': 0, 'ra': 0.1, 'wa': 0, 'raa': 0.01, 'rrange': { 'max': 4.9 } } }, ] }, { 'v': [ { 'count': 0, 'v': { 'r': 0, 'theta': 75, 'w': 0, 'ra': 0.1, 'wa': 0, 'raa': 0.01, 'rrange': { 'max': 5.1 } } }, ] }, { 'v': [ { 'count': 0, 'v': { 'r': 0, 'theta': 65, 'w': 0, 'ra': 0.1, 'wa': 0, 'raa': 0.01, 'rrange': { 'max': 5.3 } } }, ] }, { 'v': [ { 'count': 0, 'v': { 'r': 0, 'theta': 55, 'w': 0, 'ra': 0.1, 'wa': 0, 'raa': 0.01, 'rrange': { 'max': 5.5 } } }, ] }, { 'v': [ { 'count': 0, 'v': { 'r': 0, 'theta': 45, 'w': 0, 'ra': 0.1, 'wa': 0, 'raa': 0.01, 'rrange': { 'max': 5.7 } } }, ] }, ], [ { 'laser': true, 'waitCount': 40, 'keep': 150, 'v': { 'r': 0, 'theta': 180, 'w': -0.01, 'ra':0, 'wa': -0.01, 'trange': { 'min': 110 } }, }, { 'laser': true, 'waitCount': 40, 'keep': 150, 'v': { 'r': 0, 'theta': 0, 'w': 0.01, 'ra':0, 'wa': 0.01, 'trange': { 'max': 70 } }, }, ], [ { 'v': { 'r': 5, 'theta': 0, 'w': 0, 'ra': 0, 'wa': 0, 'rrandom': { 'min': 4, 'max': 5 }, 'trandom': { 'min': 0, 'max': 360 } }, }, ], [ { 'v': { 'r': 3, 'theta': 45, 'w': 0, 'ra': 0, 'wa': 0, 'raa': 0 }, }, { 'v': { 'r': 3, 'theta': 135, 'w': 0, 'ra': 0, 'wa': 0, 'raa': 0 }, }, { 'v': { 'r': 3, 'theta': 225, 'w': 0, 'ra': 0, 'wa': 0, 'raa': 0 }, }, { 'v': { 'r': 3, 'theta': 315, 'w': 0, 'ra': 0, 'wa': 0, 'raa': 0 }, }, ], __danmakuHelper.daiYousei1( ), __danmakuHelper.daiYousei2( ), __danmakuHelper.chilno1( ), [ { 'v': { 'r': 2, 'theta': 0, 'w': 0, 'ra': 0, 'wa': 0, 'rrandom': { 'min': 2, 'max': 3 }, 'trandom': { 'min': 0, 'max': 360 }, 'g': { 'r': 0, 'theta': 90, 'ra': 0.05 } }, }, ], __danmakuHelper.chilno2( ), [ { 'v': { 'aimed': true, 'r': 5, 'theta':-15, 'w': 0 }, }, { 'v': { 'aimed': true, 'r': 5, 'theta': -5, 'w': 0 }, }, { 'v': { 'aimed': true, 'r': 5, 'theta': 5, 'w': 0 }, }, { 'v': { 'aimed': true, 'r': 5, 'theta': 15, 'w': 0 }, }, ], [ { 'beam': true, 'v': { 'rrandom': { 'min': 4, 'max': 6 }, 'trandom': { 'min': 180, 'max': 200 }, 'g': { 'r': 0, 'theta': 90, 'ra': 0.3 } }, }, { 'beam': true, 'v': { 'rrandom': { 'min': 4, 'max': 6 }, 'trandom': { 'min': 225, 'max': 245 }, 'g': { 'r': 0, 'theta': 90, 'ra': 0.3 } }, }, { 'beam': true, 'v': { 'rrandom': { 'min': 4, 'max': 6 }, 'trandom': { 'min': 270, 'max': 290 }, 'g': { 'r': 0, 'theta': 90, 'ra': 0.3 } }, }, { 'beam': true, 'v': { 'rrandom': { 'min': 4, 'max': 6 }, 'trandom': { 'min': 340, 'max': 360 }, 'g': { 'r': 0, 'theta': 90, 'ra': 0.3 } }, }, ], ] ; var __enemyBulletTypes = [ { 'indexX': 15, 'indexY': 3, 'width': 16, 'height': 16, 'collisionWidth': 10, 'collisionHeight': 10 }, { 'indexX': 2, 'indexY': 3, 'width': 16, 'height': 16, 'collisionWidth': 10, 'collisionHeight': 10 }, { 'indexX': 8, 'indexY': 3, 'width': 16, 'height': 16, 'collisionWidth': 10, 'collisionHeight': 10 }, { 'indexX': 6, 'indexY': 3, 'width': 16, 'height': 16, 'collisionWidth': 10, 'collisionHeight': 10 }, { 'indexX': 7, 'indexY': 3, 'width': 16, 'height': 16, 'collisionWidth': 10, 'collisionHeight': 10 }, { 'indexX': 13, 'indexY': 4, 'width': 16, 'height': 16, 'collisionWidth': 5, 'collisionHeight': 5, 'rotate': true, }, { 'indexX': 10, 'indexY': 4, 'width': 16, 'height': 16, 'collisionWidth': 5, 'collisionHeight': 5, 'rotate': true, }, { 'indexX': 7, 'indexY': 4, 'width': 16, 'height': 16, 'collisionWidth': 5, 'collisionHeight': 5, 'rotate': true, }, { 'indexX': 1, 'indexY': 5, 'width': 16, 'height': 16, 'collisionWidth': 5, 'collisionHeight': 5, 'rotate': true, }, { 'indexX': 9, 'indexY': 5, 'width': 16, 'height': 16, 'collisionWidth': 5, 'collisionHeight': 5, 'rotate': true, }, ] ; ================================================ FILE: data/danmaku_helper.js ================================================ function DanmakuHelper( ) { } DanmakuHelper.prototype._calculateRadian = function( theta ) { return theta * Math.PI / 180 ; } ; DanmakuHelper.prototype._calculateTheta = function( radian ) { return parseInt( radian * 180 / Math.PI ) ; } ; DanmakuHelper.prototype.daiYousei1 = function( ) { var array = [ ] ; var r = 30 ; for( var i = 0; i < 36; i++ ) { var count = i * 1 ; var t = ( ( i * 10 ) + 90 ) % 360 ; var v = { 'x': r * Math.cos( this._calculateRadian( t ) ), 'y': r * Math.sin( this._calculateRadian( t ) ), 'count': i * 1, 'v': { 'r': 2 + ( i / 50 ), 'theta': t } } ; array.push( v ) ; } return array ; } ; DanmakuHelper.prototype.daiYousei2 = function( ) { var array = [ ] ; var r = 30 ; for( var i = 0; i < 36; i++ ) { var count = i * 1 ; var t = ( ( i * -10 ) + 450 ) % 360 ; var v = { 'x': r * Math.cos( this._calculateRadian( t ) ), 'y': r * Math.sin( this._calculateRadian( t ) ), 'count': count, 'v': { 'r': 2 + ( i / 50 ), 'theta': t } } ; array.push( v ) ; } return array ; } ; DanmakuHelper.prototype.chilno1 = function( ) { var array = [ ] ; var r = 50 ; var r2 = 100 ; var points = [ ] ; var span = 10 ; for( var i = 0; i < 5; i++ ) { points[ i ] = ( 126 + 144 * i ) % 360 ; } for( var i = 0; i < 5; i++ ) { var t1 = points[ i ] ; var t2 = points[ ( i + 1 ) % 5 ] ; var x1 = r * Math.cos( this._calculateRadian( t1 ) ) ; var y1 = r * Math.sin( this._calculateRadian( t1 ) ) ; var x2 = r * Math.cos( this._calculateRadian( t2 ) ) ; var y2 = r * Math.sin( this._calculateRadian( t2 ) ) ; for( var j = 0; j < span; j++ ) { var count = ( j + i * span ) ; var x = x1 + ( x2 - x1 ) / span * j ; var y = y1 + ( y2 - y1 ) / span * j ; var t = this._calculateTheta( Math.atan2( y, x ) ) ; for( var k = 0; k < 5; k++ ) { var at = points[ k ] ; var ax = x + r2 * Math.cos( this._calculateRadian( at ) ) ; var ay = y + r2 * Math.sin( this._calculateRadian( at ) ) ; var v = { 'x': ax, 'y': ay, 'count': count, 'v': [ { 'count': 0, 'v': { 'r': 0, 'theta': t, } }, { 'count': span*6-count, 'v': { 'r': 2, 'w': 0 } } ] } ; array.push( v ) ; } } } return array ; } ; DanmakuHelper.prototype.chilno2 = function( ) { var array = [ ] ; for( var i = 0; i < 200; i++ ) { var count = i * 1 ; var v = { 'count': count, 'v': [ { 'count': 0, 'v': { 'r': 5, 'theta': 0, 'w': 0, 'ra': -0.01, 'wa': 0, 'rrandom': { 'min': 4, 'max': 5 }, 'rrange': { 'min': 2 }, 'trandom': { 'min': 0, 'max': 360 } }, }, { 'count': 200 - count, 'v': { 'r': 0 }, }, { 'count': 400 - count, 'v': { 'r': 1, 'theta': 0, 'w': 0, 'ra': 0.02, 'wa': 0, 'trandom': { 'min': 0, 'max': 360 } }, }, ] } ; array.push( v ) ; } return array ; } ; ================================================ FILE: data/enemies_params.js ================================================ var __stage1EnemiesParams = [ ] ; /* __stage1EnemiesParams.push( { 'count': 100, 'x': 240, 'y': 100, 'vital': 3, 's': [ { 'bullet': 20, 'type': 6, 'shotCount': [ 10 ], 'loop': true }, // { 'bullet': 11, 'type': 6, 'shotCount': [ 100 ], 'loop': true }, // { 'bullet': 8, 'type': 7, 'shotCount': [ 0 ], 'loop': true, 'r': 20 }, ], 'v': { 'r': 0, 'theta': 90, 'w': 0, 'ra': 0, 'wa': 0 }, } ) ; */ for( var i = 0; i < 6 ; i++ ) { __stage1EnemiesParams.push( { 'count': 100 + i * 15, 'x': 50 + i * 20, 'vital': 1, 'powerItem': i % 2 == 0 ? 1 : 0, 'scoreItem': i % 2 == 1 ? 1 : 0, 'v': [ { 'count': 0, 'v': { 'r': 2, 'theta': 90, 'w': 0, 'ra': 0, 'wa': 0 } }, { 'count': 50, 'v': { 'r': 2, 'w': 0, 'ra': 0, 'wa': 0.01, 'trange': { 'max': 135 }, 'wrange': { 'max': 0.5 } } }, ] } ) ; } for( var i = 0; i < 6 ; i++ ) { __stage1EnemiesParams.push( { 'count': 300 + i * 15, 'x': 380 - i * 20, 'vital': 1, 'powerItem': i % 2 == 0 ? 1 : 0, 'scoreItem': i % 2 == 1 ? 1 : 0, 'v': [ { 'count': 0, 'v': { 'r': 2, 'theta': 90, 'w': 0, 'ra': 0, 'wa': 0 } }, { 'count': 50, 'v': { 'r': 2, 'w': 0, 'ra': 0, 'wa': -0.01, 'trange': { 'min': 45 }, 'wrange': { 'min': -0.5 } } }, ] } ) ; } for( var i = 0; i < 6 ; i++ ) { __stage1EnemiesParams.push( { 'count': 500 + i * 15, 'x': 50 + i * 20, 'vital': 1, 'powerItem': i % 2 == 0 ? 1 : 0, 'scoreItem': i % 2 == 1 ? 1 : 0, 'v': [ { 'count': 0, 'v': { 'r': 2, 'theta': 90, 'w': 0, 'ra': 0, 'wa': 0 } }, { 'count': 50, 'v': { 'r': 2, 'w': 0, 'ra': 0, 'wa': 0.01, 'trange': { 'max': 135 }, 'wrange': { 'max': 0.5 } } }, ] } ) ; } for( var i = 0; i < 6 ; i++ ) { __stage1EnemiesParams.push( { 'count': 700 + i * 15, 'x': 380 - i * 20, 'vital': 1, 'powerItem': i % 2 == 0 ? 1 : 0, 'v': [ { 'count': 0, 'v': { 'r': 2, 'theta': 90, 'w': 0, 'ra': 0, 'wa': 0 } }, { 'count': 50, 'v': { 'r': 2, 'w': 0, 'ra': 0, 'wa': -0.01, 'trange': { 'min': 45 }, 'wrange': { 'min': -0.5 } } }, ] } ) ; } for( var i = 0; i < 8 ; i++ ) { __stage1EnemiesParams.push( { 'count': 900 + i * ( 80 - i * 5 ), 'x': 25 + (i%4) * 50, 'vital': 3, 'powerItem': i % 2 == 0 ? 1 : 0, 's': { 'bullet': 0, 'shotCount': [ 40+(i%2)*20 ] }, 'v': [ { 'count': 0, 'v': { 'r': 2, 'theta': 90, 'w': 0, 'ra': 0, 'wa': 0 } }, { 'count': 30+(i%2)*20, 'v': { 'r': 0, 'theta': 90, 'w': 0, 'ra': 0, 'wa': 0 } }, { 'count': 130+(i%2)*20, 'v': { 'r': 2, 'theta': 90, 'w': 0, 'ra': 0, 'wa': 0.1, 'trange': { 'max': 190 } } }, ] } ) ; } for( var i = 0; i < 8 ; i++ ) { __stage1EnemiesParams.push( { 'count': 950 + i * ( 80 - i * 5 ), 'x': 455 - (i%4) * 50, 'vital': 3, 'powerItem': i % 2 == 0 ? 1 : 0, 's': { 'bullet': 0, 'shotCount': [ 40+(i%2)*20 ] }, 'v': [ { 'count': 0, 'v': { 'r': 2, 'theta': 90, 'w': 0, 'ra': 0, 'wa': 0 } }, { 'count': 30+(i%2)*20, 'v': { 'r': 0, 'theta': 90, 'w': 0, 'ra': 0, 'wa': 0 } }, { 'count': 130+(i%2)*20, 'v': { 'r': 2, 'theta': 90, 'w': 0, 'ra': 0, 'wa': -0.1, 'trange': { 'min': -10 } } }, ] } ) ; } for( var i = 0; i < 4 ; i++ ) { __stage1EnemiesParams.push( { 'count': 1400 + i * 20, 'x': 50 + i * 50, 'vital': 1, 'powerItem': i % 4 == 0 ? 1 : 0, 'scoreItem': i % 4 == 2 ? 1 : 0, 's': { 'bullet': 1, 'shotCount': [ 40 ] }, 'v': [ { 'count': 0, 'v': { 'r': 2, 'theta': 90, 'w': 0, 'ra': 0, 'wa': 0 } }, { 'count': 30, 'v': { 'r': 2, 'w': 0, 'ra': 0, 'wa': -0.01, 'trange': { 'min': -30 }, 'wrange': { 'min': -1 } } }, ] } ) ; } for( var i = 0; i < 4 ; i++ ) { __stage1EnemiesParams.push( { 'count': 1410 + i * 10, 'x': 25 + i * 50, 'vital': 1, 'powerItem': i % 4 == 0 ? 1 : 0, 'scoreItem': i % 4 == 2 ? 1 : 0, 's': { 'bullet': 1, 'shotCount': [ 40 ] }, 'v': [ { 'count': 0, 'v': { 'r': 2, 'theta': 90, 'w': 0, 'ra': 0, 'wa': 0 } }, { 'count': 30, 'v': { 'r': 2, 'w': 0, 'ra': 0, 'wa': -0.01, 'trange': { 'min': -30 }, 'wrange': { 'min': -1 } } }, ] } ) ; } for( var i = 0; i < 4 ; i++ ) { __stage1EnemiesParams.push( { 'count': 1420 + i * 20, 'x': 430 - i * 50, 'vital': 1, 'powerItem': i % 4 == 0 ? 1 : 0, 'scoreItem': i % 4 == 2 ? 1 : 0, 's': { 'bullet': 1, 'shotCount': [ 40 ] }, 'v': [ { 'count': 0, 'v': { 'r': 2, 'theta': 90, 'w': 0, 'ra': 0, 'wa': 0 } }, { 'count': 30, 'v': { 'r': 2, 'w': 0, 'ra': 0, 'wa': 0.01, 'trange': { 'max': 210 }, 'wrange': { 'max': 1 } } }, ] } ) ; } for( var i = 0; i < 4 ; i++ ) { __stage1EnemiesParams.push( { 'count': 1430 + i * 10, 'x': 455 - i * 50, 'vital': 1, 'powerItem': i % 4 == 0 ? 1 : 0, 'scoreItem': i % 4 == 2 ? 1 : 0, 's': { 'bullet': 1, 'shotCount': [ 40 ] }, 'v': [ { 'count': 0, 'v': { 'r': 2, 'theta': 90, 'w': 0, 'ra': 0, 'wa': 0 } }, { 'count': 30, 'v': { 'r': 2, 'w': 0, 'ra': 0, 'wa': 0.01, 'trange': { 'max': 210 }, 'wrange': { 'max': 1 } } }, ] } ) ; } for( var i = 0; i < 20 ; i++ ) { __stage1EnemiesParams.push( { 'count':1700 + parseInt( i/2 ) * 10, 'x': ( i%2 == 0 ? 50 : 80 ) + i * 10, 'vital': 1, 'powerItem': i % 4 == 0 ? 1 : 0, 'scoreItem': i % 4 == 2 ? 1 : 0, 'v': [ { 'count': 0, 'v': { 'r': 3, 'theta': 90, 'w': 0, 'ra': 0, 'wa': 0 } }, { 'count': 30, 'v': { 'r': 3, 'w': 0, 'ra': 0, 'wa':-0.02, 'trange': { 'min': -45 }, 'wrange': { 'min': -1 } } }, { 'count': 180, 'v': { 'r': 3, 'w': 0, 'ra': 0, 'wa': 0.02, 'trange': { 'max': 45 }, 'wrange': { 'max': 1 } } }, ] } ) ; } for( var i = 0; i < 20 ; i++ ) { __stage1EnemiesParams.push( { 'count': 1900 + parseInt( i/2 ) * 10, 'x': ( i%2 == 0 ? 430 : 400 ) - i * 10, 'vital': 1, 'powerItem': i % 4 == 0 ? 1 : 0, 'scoreItem': i % 4 == 2 ? 1 : 0, 'v': [ { 'count': 0, 'v': { 'r': 3, 'theta': 90, 'w': 0, 'ra': 0, 'wa': 0 } }, { 'count': 30, 'v': { 'r': 3, 'w': 0, 'ra': 0, 'wa': 0.02, 'trange': { 'max': 225 }, 'wrange': { 'max': 1 } } }, { 'count': 180, 'v': { 'r': 3, 'w': 0, 'ra': 0, 'wa':-0.02, 'trange': { 'min': 135 }, 'wrange': { 'min': -1 } } }, ] } ) ; } for( var i = 0; i < 8 ; i++ ) { __stage1EnemiesParams.push( { 'count': 2300 + i * ( 80 - i * 5 ), 'x': 25 + (i%4) * 50, 'vital': 3, 'powerItem': i % 2 == 0 ? 1 : 0, 'scoreItem': i % 2 == 1 ? 1 : 0, 's': { 'bullet': 0, 'shotCount': [ 40+(i%2)*20 ] }, 'v': [ { 'count': 0, 'v': { 'r': 2, 'theta': 90, 'w': 0, 'ra': 0, 'wa': 0 } }, { 'count': 30+(i%2)*20, 'v': { 'r': 0, 'theta': 90, 'w': 0, 'ra': 0, 'wa': 0 } }, { 'count': 130+(i%2)*20, 'v': { 'r': 2, 'theta': 90, 'w': 0, 'ra': 0, 'wa': 0.1, 'trange': { 'max': 190 } } }, ] } ) ; } for( var i = 0; i < 8 ; i++ ) { __stage1EnemiesParams.push( { 'count': 2350 + i * ( 80 - i * 5 ), 'x': 455 - (i%4) * 50, 'vital': 3, 'powerItem': i % 2 == 0 ? 1 : 0, 'scoreItem': i % 2 == 1 ? 1 : 0, 's': { 'bullet': 0, 'shotCount': [ 40+(i%2)*20 ] }, 'v': [ { 'count': 0, 'v': { 'r': 2, 'theta': 90, 'w': 0, 'ra': 0, 'wa': 0 } }, { 'count': 30+(i%2)*20, 'v': { 'r': 0, 'theta': 90, 'w': 0, 'ra': 0, 'wa': 0 } }, { 'count': 130+(i%2)*20, 'v': { 'r': 2, 'theta': 90, 'w': 0, 'ra': 0, 'wa': -0.1, 'trange': { 'min': -10 } } }, ] } ) ; } for( var i = 0; i < 8 ; i++ ) { __stage1EnemiesParams.push( { 'count': 2500 + i * ( 80 - i * 5 ), 'x': 25 + (i%4) * 50, 'vital': 3, 'powerItem': i % 2 == 0 ? 1 : 0, 'scoreItem': i % 2 == 1 ? 1 : 0, 's': { 'bullet': 0, 'shotCount': [ 40+(i%2)*20 ] }, 'v': [ { 'count': 0, 'v': { 'r': 2, 'theta': 90, 'w': 0, 'ra': 0, 'wa': 0 } }, { 'count': 30+(i%2)*20, 'v': { 'r': 0, 'theta': 90, 'w': 0, 'ra': 0, 'wa': 0 } }, { 'count': 130+(i%2)*20, 'v': { 'r': 2, 'theta': 90, 'w': 0, 'ra': 0, 'wa': 0.1, 'trange': { 'max': 190 } } }, ] } ) ; } for( var i = 0; i < 8 ; i++ ) { __stage1EnemiesParams.push( { 'count': 2550 + i * ( 80 - i * 5 ), 'x': 455 - (i%4) * 50, 'vital': 3, 'powerItem': i % 2 == 0 ? 1 : 0, 'scoreItem': i % 2 == 1 ? 1 : 0, 's': { 'bullet': 0, 'shotCount': [ 40+(i%2)*20 ] }, 'v': [ { 'count': 0, 'v': { 'r': 2, 'theta': 90, 'w': 0, 'ra': 0, 'wa': 0 } }, { 'count': 30+(i%2)*20, 'v': { 'r': 0, 'theta': 90, 'w': 0, 'ra': 0, 'wa': 0 } }, { 'count': 130+(i%2)*20, 'v': { 'r': 2, 'theta': 90, 'w': 0, 'ra': 0, 'wa': -0.1, 'trange': { 'min': -10 } } }, ] } ) ; } for( var i = 0; i < 8 ; i++ ) { __stage1EnemiesParams.push( { 'count': 2700 + i * ( 80 - i * 5 ), 'x': 25 + (i%4) * 50, 'vital': 3, 'powerItem': i % 2 == 0 ? 1 : 0, 'scoreItem': i % 2 == 1 ? 1 : 0, 's': { 'bullet': 0, 'shotCount': [ 40+(i%2)*20 ] }, 'v': [ { 'count': 0, 'v': { 'r': 2, 'theta': 90, 'w': 0, 'ra': 0, 'wa': 0 } }, { 'count': 30+(i%2)*20, 'v': { 'r': 0, 'theta': 90, 'w': 0, 'ra': 0, 'wa': 0 } }, { 'count': 130+(i%2)*20, 'v': { 'r': 2, 'theta': 90, 'w': 0, 'ra': 0, 'wa': 0.1, 'trange': { 'max': 190 } } }, ] } ) ; } for( var i = 0; i < 8 ; i++ ) { __stage1EnemiesParams.push( { 'count': 2750 + i * ( 80 - i * 5 ), 'x': 455 - (i%4) * 50, 'vital': 3, 'powerItem': i % 2 == 0 ? 1 : 0, 'scoreItem': i % 2 == 1 ? 1 : 0, 's': { 'bullet': 0, 'shotCount': [ 40+(i%2)*20 ] }, 'v': [ { 'count': 0, 'v': { 'r': 2, 'theta': 90, 'w': 0, 'ra': 0, 'wa': 0 } }, { 'count': 30+(i%2)*20, 'v': { 'r': 0, 'theta': 90, 'w': 0, 'ra': 0, 'wa': 0 } }, { 'count': 130+(i%2)*20, 'v': { 'r': 2, 'theta': 90, 'w': 0, 'ra': 0, 'wa': -0.1, 'trange': { 'min': -10 } } }, ] } ) ; } var __stage2EnemiesParams = [ ] ; for( var i = 0; i < 100 ; i++ ) { __stage2EnemiesParams.push( { 'count': 100 + i * 5, 'x': parseInt(__randomizer.random() * 480), 'vital': 1, 'powerItem': i % 2 == 0 ? 1 : 0, 'scoreItem': i % 2 == 1 ? 1 : 0, 's': { 'bullet': 13, 'shotCount': [ 10 ] }, 'v': [ { 'count': 0, 'v': { 'r': 3, 'theta': 90, 'w': 0, 'ra': 0, 'wa': 0 } }, ] } ) ; } for( var i = 0; i < 6 ; i++ ) { __stage2EnemiesParams.push( { 'count': 500 + i * 15, 'x': 50 + i * 20, 'vital': 1, 'powerItem': i % 2 == 0 ? 1 : 0, 'scoreItem': i % 2 == 1 ? 1 : 0, 'v': [ { 'count': 0, 'v': { 'r': 2, 'theta': 90, 'w': 0, 'ra': 0, 'wa': 0 } }, { 'count': 50, 'v': { 'r': 2, 'w': 0, 'ra': 0, 'wa': 0.01, 'trange': { 'max': 135 }, 'wrange': { 'max': 0.5 } } }, ] } ) ; } for( var i = 0; i < 6 ; i++ ) { __stage2EnemiesParams.push( { 'count': 700 + i * 15, 'x': 380 - i * 20, 'vital': 1, 'powerItem': i % 2 == 0 ? 1 : 0, 'v': [ { 'count': 0, 'v': { 'r': 2, 'theta': 90, 'w': 0, 'ra': 0, 'wa': 0 } }, { 'count': 50, 'v': { 'r': 2, 'w': 0, 'ra': 0, 'wa': -0.01, 'trange': { 'min': 45 }, 'wrange': { 'min': -0.5 } } }, ] } ) ; } for( var i = 0; i < 8 ; i++ ) { __stage2EnemiesParams.push( { 'count': 900 + i * ( 80 - i * 5 ), 'x': 25 + (i%4) * 50, 'vital': 3, 'powerItem': i % 2 == 0 ? 1 : 0, 's': { 'bullet': 0, 'shotCount': [ 40+(i%2)*20 ] }, 'v': [ { 'count': 0, 'v': { 'r': 2, 'theta': 90, 'w': 0, 'ra': 0, 'wa': 0 } }, { 'count': 30+(i%2)*20, 'v': { 'r': 0, 'theta': 90, 'w': 0, 'ra': 0, 'wa': 0 } }, { 'count': 130+(i%2)*20, 'v': { 'r': 2, 'theta': 90, 'w': 0, 'ra': 0, 'wa': 0.1, 'trange': { 'max': 190 } } }, ] } ) ; } for( var i = 0; i < 8 ; i++ ) { __stage2EnemiesParams.push( { 'count': 950 + i * ( 80 - i * 5 ), 'x': 455 - (i%4) * 50, 'vital': 3, 'powerItem': i % 2 == 0 ? 1 : 0, 's': { 'bullet': 0, 'shotCount': [ 40+(i%2)*20 ] }, 'v': [ { 'count': 0, 'v': { 'r': 2, 'theta': 90, 'w': 0, 'ra': 0, 'wa': 0 } }, { 'count': 30+(i%2)*20, 'v': { 'r': 0, 'theta': 90, 'w': 0, 'ra': 0, 'wa': 0 } }, { 'count': 130+(i%2)*20, 'v': { 'r': 2, 'theta': 90, 'w': 0, 'ra': 0, 'wa': -0.1, 'trange': { 'min': -10 } } }, ] } ) ; } for( var i = 0; i < 4 ; i++ ) { __stage2EnemiesParams.push( { 'count': 1400 + i * 20, 'x': 50 + i * 50, 'vital': 1, 'powerItem': i % 4 == 0 ? 1 : 0, 'scoreItem': i % 4 == 2 ? 1 : 0, 's': { 'bullet': 1, 'shotCount': [ 40 ] }, 'v': [ { 'count': 0, 'v': { 'r': 2, 'theta': 90, 'w': 0, 'ra': 0, 'wa': 0 } }, { 'count': 30, 'v': { 'r': 2, 'w': 0, 'ra': 0, 'wa': -0.01, 'trange': { 'min': -30 }, 'wrange': { 'min': -1 } } }, ] } ) ; } for( var i = 0; i < 4 ; i++ ) { __stage2EnemiesParams.push( { 'count': 1410 + i * 10, 'x': 25 + i * 50, 'vital': 1, 'powerItem': i % 4 == 0 ? 1 : 0, 'scoreItem': i % 4 == 2 ? 1 : 0, 's': { 'bullet': 1, 'shotCount': [ 40 ] }, 'v': [ { 'count': 0, 'v': { 'r': 2, 'theta': 90, 'w': 0, 'ra': 0, 'wa': 0 } }, { 'count': 30, 'v': { 'r': 2, 'w': 0, 'ra': 0, 'wa': -0.01, 'trange': { 'min': -30 }, 'wrange': { 'min': -1 } } }, ] } ) ; } for( var i = 0; i < 4 ; i++ ) { __stage2EnemiesParams.push( { 'count': 1420 + i * 20, 'x': 430 - i * 50, 'vital': 1, 'powerItem': i % 4 == 0 ? 1 : 0, 'scoreItem': i % 4 == 2 ? 1 : 0, 's': { 'bullet': 1, 'shotCount': [ 40 ] }, 'v': [ { 'count': 0, 'v': { 'r': 2, 'theta': 90, 'w': 0, 'ra': 0, 'wa': 0 } }, { 'count': 30, 'v': { 'r': 2, 'w': 0, 'ra': 0, 'wa': 0.01, 'trange': { 'max': 210 }, 'wrange': { 'max': 1 } } }, ] } ) ; } for( var i = 0; i < 4 ; i++ ) { __stage2EnemiesParams.push( { 'count': 1430 + i * 10, 'x': 455 - i * 50, 'vital': 1, 'powerItem': i % 4 == 0 ? 1 : 0, 'scoreItem': i % 4 == 2 ? 1 : 0, 's': { 'bullet': 1, 'shotCount': [ 40 ] }, 'v': [ { 'count': 0, 'v': { 'r': 2, 'theta': 90, 'w': 0, 'ra': 0, 'wa': 0 } }, { 'count': 30, 'v': { 'r': 2, 'w': 0, 'ra': 0, 'wa': 0.01, 'trange': { 'max': 210 }, 'wrange': { 'max': 1 } } }, ] } ) ; } for( var i = 0; i < 20 ; i++ ) { __stage2EnemiesParams.push( { 'count':1700 + parseInt( i/2 ) * 10, 'x': ( i%2 == 0 ? 50 : 80 ) + i * 10, 'vital': 1, 'powerItem': i % 4 == 0 ? 1 : 0, 'scoreItem': i % 4 == 2 ? 1 : 0, 'v': [ { 'count': 0, 'v': { 'r': 3, 'theta': 90, 'w': 0, 'ra': 0, 'wa': 0 } }, { 'count': 30, 'v': { 'r': 3, 'w': 0, 'ra': 0, 'wa':-0.02, 'trange': { 'min': -45 }, 'wrange': { 'min': -1 } } }, { 'count': 180, 'v': { 'r': 3, 'w': 0, 'ra': 0, 'wa': 0.02, 'trange': { 'max': 45 }, 'wrange': { 'max': 1 } } }, ] } ) ; } for( var i = 0; i < 20 ; i++ ) { __stage2EnemiesParams.push( { 'count': 1900 + parseInt( i/2 ) * 10, 'x': ( i%2 == 0 ? 430 : 400 ) - i * 10, 'vital': 1, 'powerItem': i % 4 == 0 ? 1 : 0, 'scoreItem': i % 4 == 2 ? 1 : 0, 'v': [ { 'count': 0, 'v': { 'r': 3, 'theta': 90, 'w': 0, 'ra': 0, 'wa': 0 } }, { 'count': 30, 'v': { 'r': 3, 'w': 0, 'ra': 0, 'wa': 0.02, 'trange': { 'max': 225 }, 'wrange': { 'max': 1 } } }, { 'count': 180, 'v': { 'r': 3, 'w': 0, 'ra': 0, 'wa':-0.02, 'trange': { 'min': 135 }, 'wrange': { 'min': -1 } } }, ] } ) ; } for( var i = 0; i < 8 ; i++ ) { __stage2EnemiesParams.push( { 'count': 2300 + i * ( 80 - i * 5 ), 'x': 25 + (i%4) * 50, 'vital': 3, 'powerItem': i % 2 == 0 ? 1 : 0, 'scoreItem': i % 2 == 1 ? 1 : 0, 's': { 'bullet': 0, 'shotCount': [ 40+(i%2)*20 ] }, 'v': [ { 'count': 0, 'v': { 'r': 2, 'theta': 90, 'w': 0, 'ra': 0, 'wa': 0 } }, { 'count': 30+(i%2)*20, 'v': { 'r': 0, 'theta': 90, 'w': 0, 'ra': 0, 'wa': 0 } }, { 'count': 130+(i%2)*20, 'v': { 'r': 2, 'theta': 90, 'w': 0, 'ra': 0, 'wa': 0.1, 'trange': { 'max': 190 } } }, ] } ) ; } for( var i = 0; i < 8 ; i++ ) { __stage2EnemiesParams.push( { 'count': 2350 + i * ( 80 - i * 5 ), 'x': 455 - (i%4) * 50, 'vital': 3, 'powerItem': i % 2 == 0 ? 1 : 0, 'scoreItem': i % 2 == 1 ? 1 : 0, 's': { 'bullet': 0, 'shotCount': [ 40+(i%2)*20 ] }, 'v': [ { 'count': 0, 'v': { 'r': 2, 'theta': 90, 'w': 0, 'ra': 0, 'wa': 0 } }, { 'count': 30+(i%2)*20, 'v': { 'r': 0, 'theta': 90, 'w': 0, 'ra': 0, 'wa': 0 } }, { 'count': 130+(i%2)*20, 'v': { 'r': 2, 'theta': 90, 'w': 0, 'ra': 0, 'wa': -0.1, 'trange': { 'min': -10 } } }, ] } ) ; } for( var i = 0; i < 8 ; i++ ) { __stage2EnemiesParams.push( { 'count': 2500 + i * ( 80 - i * 5 ), 'x': 25 + (i%4) * 50, 'vital': 3, 'powerItem': i % 2 == 0 ? 1 : 0, 'scoreItem': i % 2 == 1 ? 1 : 0, 's': { 'bullet': 0, 'shotCount': [ 40+(i%2)*20 ] }, 'v': [ { 'count': 0, 'v': { 'r': 2, 'theta': 90, 'w': 0, 'ra': 0, 'wa': 0 } }, { 'count': 30+(i%2)*20, 'v': { 'r': 0, 'theta': 90, 'w': 0, 'ra': 0, 'wa': 0 } }, { 'count': 130+(i%2)*20, 'v': { 'r': 2, 'theta': 90, 'w': 0, 'ra': 0, 'wa': 0.1, 'trange': { 'max': 190 } } }, ] } ) ; } for( var i = 0; i < 8 ; i++ ) { __stage2EnemiesParams.push( { 'count': 2550 + i * ( 80 - i * 5 ), 'x': 455 - (i%4) * 50, 'vital': 3, 'powerItem': i % 2 == 0 ? 1 : 0, 'scoreItem': i % 2 == 1 ? 1 : 0, 's': { 'bullet': 0, 'shotCount': [ 40+(i%2)*20 ] }, 'v': [ { 'count': 0, 'v': { 'r': 2, 'theta': 90, 'w': 0, 'ra': 0, 'wa': 0 } }, { 'count': 30+(i%2)*20, 'v': { 'r': 0, 'theta': 90, 'w': 0, 'ra': 0, 'wa': 0 } }, { 'count': 130+(i%2)*20, 'v': { 'r': 2, 'theta': 90, 'w': 0, 'ra': 0, 'wa': -0.1, 'trange': { 'min': -10 } } }, ] } ) ; } for( var i = 0; i < 8 ; i++ ) { __stage2EnemiesParams.push( { 'count': 2700 + i * ( 80 - i * 5 ), 'x': 25 + (i%4) * 50, 'vital': 3, 'powerItem': i % 2 == 0 ? 1 : 0, 'scoreItem': i % 2 == 1 ? 1 : 0, 's': { 'bullet': 0, 'shotCount': [ 40+(i%2)*20 ] }, 'v': [ { 'count': 0, 'v': { 'r': 2, 'theta': 90, 'w': 0, 'ra': 0, 'wa': 0 } }, { 'count': 30+(i%2)*20, 'v': { 'r': 0, 'theta': 90, 'w': 0, 'ra': 0, 'wa': 0 } }, { 'count': 130+(i%2)*20, 'v': { 'r': 2, 'theta': 90, 'w': 0, 'ra': 0, 'wa': 0.1, 'trange': { 'max': 190 } } }, ] } ) ; } for( var i = 0; i < 8 ; i++ ) { __stage2EnemiesParams.push( { 'count': 2750 + i * ( 80 - i * 5 ), 'x': 455 - (i%4) * 50, 'vital': 3, 'powerItem': i % 2 == 0 ? 1 : 0, 'scoreItem': i % 2 == 1 ? 1 : 0, 's': { 'bullet': 0, 'shotCount': [ 40+(i%2)*20 ] }, 'v': [ { 'count': 0, 'v': { 'r': 2, 'theta': 90, 'w': 0, 'ra': 0, 'wa': 0 } }, { 'count': 30+(i%2)*20, 'v': { 'r': 0, 'theta': 90, 'w': 0, 'ra': 0, 'wa': 0 } }, { 'count': 130+(i%2)*20, 'v': { 'r': 2, 'theta': 90, 'w': 0, 'ra': 0, 'wa': -0.1, 'trange': { 'min': -10 } } }, ] } ) ; } var __enemiesParams = [ ] ; __enemiesParams.push( __stage1EnemiesParams ) ; __enemiesParams.push( __stage2EnemiesParams ) ; ================================================ FILE: data/stage_params.js ================================================ var __stage1Params = { 'title': 'Nothing Special', 'bgScale': [ { 'beginCount': 0, 'endCount': 1, 'a': 0.5 }, { 'beginCount': 500, 'endCount': 1500, 'd': 0.0002 }, { 'beginCount': 2500, 'endCount': 3000, 'd': -0.0004 }, ] } ; var __stage2Params = { 'title': 'Something Special', 'bgScale': [ { 'beginCount': 0, 'endCount': 1, 'a': 1.0 }, { 'beginCount': 500, 'endCount': 1500, 'd': -0.0001 }, { 'beginCount': 2500, 'endCount': 3000, 'd': -0.0006 }, ] } ; var __stageParams = [ ] ; __stageParams.push( __stage1Params ) ; __stageParams.push( __stage2Params ) ; ================================================ FILE: data/talk_params.js ================================================ var __reimuBossTalkParams = [ ] ; var __marisaBossTalkParams = [ ] ; __reimuBossTalkParams.push( { 'serif': 'Hi, how\'re you doing, Rumia?', 'left': { 'character': 'reimu', 'active': true }, 'right': { 'character': 'rumia' }, } ) ; __reimuBossTalkParams.push( { 'serif': 'Good. But hungry. Can I eat you?', 'left': { 'character': 'reimu' }, 'right': { 'character': 'rumia', 'active': true }, } ) ; __reimuBossTalkParams.push( { 'serif': 'Sorry, I\'m busy now.\nI can play with you after I solve the Ihen.', 'left': { 'character': 'reimu', 'active': true }, 'right': { 'character': 'rumia' }, } ) ; __marisaBossTalkParams.push( { 'serif': 'Hi, Marisa. What are you doing now?', 'left': { 'character': 'marisa' }, 'right': { 'character': 'rumia', 'active': true }, } ) ; __marisaBossTalkParams.push( { 'serif': 'Ah? I just enjoy flying now.', 'left': { 'character': 'marisa', 'active': true}, 'right': { 'character': 'rumia' }, } ) ; __marisaBossTalkParams.push( { 'serif': 'So-nano-ka-?', 'left': { 'character': 'marisa' }, 'right': { 'character': 'rumia', 'active': true }, } ) ; var __stage1BossTalkParams = [ ] ; __stage1BossTalkParams.push( __reimuBossTalkParams ) ; __stage1BossTalkParams.push( __marisaBossTalkParams ) ; var __reimuClearTalkParams = [ ] ; __reimuClearTalkParams.push( { 'serif': 'Got tired.', 'left': { 'character': 'reimu', 'active': true }, } ) ; var __marisaClearTalkParams = [ ] ; __marisaClearTalkParams.push( { 'serif': 'I\'ve done it.', 'left': { 'character': 'marisa', 'active': true }, } ) ; var __stage1ClearTalkParams = [ ] ; __stage1ClearTalkParams.push( __reimuClearTalkParams ) ; __stage1ClearTalkParams.push( __marisaClearTalkParams ) ; var __stage1TalksParams = [ ] ; __stage1TalksParams.push( __stage1BossTalkParams ) ; __stage1TalksParams.push( __stage1ClearTalkParams ) ; var __reimuBossTalk2Params = [ ] ; __reimuBossTalk2Params.push( { 'serif': 'Sorry, I have no topics.', 'left': { 'character': 'reimu', 'active': true }, 'right': { 'character': 'chilno' }, } ) ; __reimuBossTalk2Params.push( { 'serif': 'W-What\'s!?', 'left': { 'character': 'reimu' }, 'right': { 'character': 'chilno', 'active': true }, } ) ; var __marisaBossTalk2Params = [ ] ; __marisaBossTalk2Params.push( { 'serif': 'Sorry, I have no topics.', 'left': { 'character': 'marisa', 'active': true }, 'right': { 'character': 'chilno' }, } ) ; __marisaBossTalk2Params.push( { 'serif': 'W-What\'s!?', 'left': { 'character': 'marisa' }, 'right': { 'character': 'chilno', 'active': true }, } ) ; var __stage2BossTalkParams = [ ] ; __stage2BossTalkParams.push( __reimuBossTalk2Params ) ; __stage2BossTalkParams.push( __marisaBossTalk2Params ) ; var __stage2TalksParams = [ ] ; __stage2TalksParams.push( __stage2BossTalkParams ) ; __stage2TalksParams.push( __stage1ClearTalkParams ) ; // TODO: temporal var __talkParams = [ ] ; __talkParams.push( __stage1TalksParams ) ; __talkParams.push( __stage2TalksParams ) ; ================================================ FILE: index.html ================================================
How to play
Turn your hardware acceleration on to fully enjoy this game.
See "chrome://gpu" and "chrome://flags" on your chrome to check if your hardware acceleration is enabled.
Thanks for all the images and musics.
This game is made by @suprehoge
================================================ FILE: index2.html ================================================How to play
Turn your hardware acceleration on to fully enjoy this game.
See "chrome://gpu" and "chrome://flags" on your chrome to check if your hardware acceleration is enabled.
Thanks for all the images and musics.
This game is made by @suprehoge
================================================ FILE: replay/replay1.txt ================================================ { user: 'takahirox', characterIndex: 0, seed: 57914, params: [ {count: 34, z: true}, {count: 46, l: true}, {count: 46, z: false}, {count: 80, u: true}, {count: 81, l: false}, {count: 102, l: true}, {count: 104, u: false}, {count: 111, l: false}, {count: 130, z: true}, {count: 136, r: true}, {count: 168, l: true}, {count: 168, r: false}, {count: 203, z: false}, {count: 205, u: true}, {count: 205, l: false}, {count: 235, r: true}, {count: 240, u: false}, {count: 250, r: false}, {count: 261, r: true}, {count: 263, r: false}, {count: 268, r: true}, {count: 271, r: false}, {count: 278, r: true}, {count: 282, r: false}, {count: 288, r: true}, {count: 295, d: true}, {count: 310, d: false}, {count: 350, z: true}, {count: 352, l: true}, {count: 353, r: false}, {count: 390, r: true}, {count: 391, l: false}, {count: 424, u: true}, {count: 425, z: false}, {count: 428, r: false}, {count: 443, l: true}, {count: 447, u: false}, {count: 461, l: false}, {count: 473, l: true}, {count: 477, l: false}, {count: 481, l: true}, {count: 493, l: false}, {count: 493, d: true}, {count: 522, l: true}, {count: 526, d: false}, {count: 574, z: true}, {count: 574, r: true}, {count: 574, l: false}, {count: 610, l: true}, {count: 611, r: false}, {count: 611, z: false}, {count: 648, u: true}, {count: 651, l: false}, {count: 667, r: true}, {count: 670, u: false}, {count: 687, r: false}, {count: 697, r: true}, {count: 702, r: false}, {count: 705, r: true}, {count: 714, d: true}, {count: 740, d: false}, {count: 764, z: true}, {count: 769, r: false}, {count: 772, l: true}, {count: 780, s: true}, {count: 812, s: false}, {count: 813, r: true}, {count: 814, l: false}, {count: 844, u: true}, {count: 846, r: false}, {count: 868, l: true}, {count: 869, u: false}, {count: 884, l: false}, {count: 892, l: true}, {count: 903, d: true}, {count: 904, l: false}, {count: 955, l: true}, {count: 956, d: false}, {count: 961, s: true}, {count: 987, s: false}, {count: 1025, u: true}, {count: 1026, l: false}, {count: 1041, r: true}, {count: 1043, u: false}, {count: 1055, d: true}, {count: 1062, d: false}, {count: 1076, d: true}, {count: 1090, d: false}, {count: 1091, l: true}, {count: 1091, r: false}, {count: 1137, l: false}, {count: 1137, u: true}, {count: 1165, u: false}, {count: 1166, r: true}, {count: 1177, d: true}, {count: 1188, d: false}, {count: 1191, r: false}, {count: 1216, l: true}, {count: 1248, l: false}, {count: 1254, u: true}, {count: 1264, u: false}, {count: 1272, r: true}, {count: 1277, r: false}, {count: 1297, r: true}, {count: 1324, r: false}, {count: 1329, d: true}, {count: 1367, d: false}, {count: 1385, r: true}, {count: 1399, u: true}, {count: 1400, r: false}, {count: 1429, u: false}, {count: 1439, l: true}, {count: 1473, l: false}, {count: 1481, u: true}, {count: 1538, l: true}, {count: 1539, u: false}, {count: 1545, l: false}, {count: 1549, r: true}, {count: 1562, d: true}, {count: 1571, r: false}, {count: 1633, r: true}, {count: 1636, d: false}, {count: 1652, r: false}, {count: 1660, r: true}, {count: 1678, u: true}, {count: 1679, r: false}, {count: 1693, l: true}, {count: 1695, u: false}, {count: 1710, u: true}, {count: 1712, l: false}, {count: 1738, r: true}, {count: 1738, u: false}, {count: 1742, d: true}, {count: 1747, r: false}, {count: 1806, l: true}, {count: 1807, d: false}, {count: 1823, r: true}, {count: 1824, l: false}, {count: 1848, r: false}, {count: 1849, l: true}, {count: 1873, u: true}, {count: 1874, l: false}, {count: 1906, r: true}, {count: 1907, u: false}, {count: 1916, r: false}, {count: 1936, r: true}, {count: 1944, d: true}, {count: 1960, d: false}, {count: 1985, r: false}, {count: 1986, l: true}, {count: 1999, l: false}, {count: 2002, l: true}, {count: 2033, l: false}, {count: 2035, r: true}, {count: 2079, u: true}, {count: 2082, r: false}, {count: 2095, l: true}, {count: 2096, u: false}, {count: 2121, l: false}, {count: 2130, l: true}, {count: 2132, l: false}, {count: 2136, l: true}, {count: 2152, l: false}, {count: 2156, r: true}, {count: 2192, s: true}, {count: 2199, d: true}, {count: 2200, r: false}, {count: 2214, d: false}, {count: 2272, d: true}, {count: 2292, d: false}, {count: 2293, l: true}, {count: 2335, u: true}, {count: 2337, l: false}, {count: 2379, l: true}, {count: 2380, u: false}, {count: 2385, l: false}, {count: 2395, d: true}, {count: 2428, d: false}, {count: 2430, l: true}, {count: 2446, l: false}, {count: 2451, l: true}, {count: 2456, l: false}, {count: 2461, l: true}, {count: 2465, l: false}, {count: 2469, l: true}, {count: 2473, l: false}, {count: 2475, l: true}, {count: 2490, u: true}, {count: 2491, l: false}, {count: 2511, u: false}, {count: 2516, l: true}, {count: 2521, l: false}, {count: 2539, d: true}, {count: 2576, d: false}, {count: 2580, r: true}, {count: 2602, r: false}, {count: 2607, r: true}, {count: 2610, r: false}, {count: 2620, u: true}, {count: 2649, u: false}, {count: 2651, r: true}, {count: 2677, r: false}, {count: 2682, d: true}, {count: 2703, d: false}, {count: 2708, r: true}, {count: 2713, r: false}, {count: 2717, r: true}, {count: 2720, r: false}, {count: 2723, r: true}, {count: 2724, r: false}, {count: 2728, r: true}, {count: 2729, r: false}, {count: 2733, r: true}, {count: 2735, r: false}, {count: 2737, r: true}, {count: 2740, r: false}, {count: 2744, r: true}, {count: 2746, r: false}, {count: 2749, r: true}, {count: 2752, r: false}, {count: 2756, r: true}, {count: 2757, r: false}, {count: 2760, r: true}, {count: 2785, s: false}, {count: 2792, r: false}, {count: 2799, d: true}, {count: 2814, l: true}, {count: 2814, d: false}, {count: 2831, l: false}, {count: 2832, u: true}, {count: 2846, u: false}, {count: 2847, r: true}, {count: 2853, d: true}, {count: 2858, r: false}, {count: 2864, d: false}, {count: 2868, l: true}, {count: 2895, l: false}, {count: 2896, u: true}, {count: 2903, u: false}, {count: 2904, l: true}, {count: 2959, l: false}, {count: 2960, r: true}, {count: 3025, r: false}, {count: 3025, l: true}, {count: 3068, d: true}, {count: 3069, l: false}, {count: 3076, l: true}, {count: 3077, d: false}, {count: 3102, u: true}, {count: 3104, l: false}, {count: 3120, u: false}, {count: 3121, r: true}, {count: 3130, d: true}, {count: 3134, r: false}, {count: 3139, d: false}, {count: 3176, d: true}, {count: 3182, d: false}, {count: 3196, d: true}, {count: 3201, d: false}, {count: 3212, r: true}, {count: 3221, r: false}, {count: 3241, u: true}, {count: 3248, u: false}, {count: 3249, l: true}, {count: 3276, u: true}, {count: 3276, l: false}, {count: 3285, u: false}, {count: 3298, d: true}, {count: 3304, d: false}, {count: 3314, r: true}, {count: 3319, r: false}, {count: 3324, r: true}, {count: 3327, r: false}, {count: 3331, r: true}, {count: 3337, r: false}, {count: 3338, r: true}, {count: 3344, r: false}, {count: 3372, d: true}, {count: 3375, r: true}, {count: 3376, d: false}, {count: 3380, r: false}, {count: 3393, r: true}, {count: 3397, r: false}, {count: 3400, r: true}, {count: 3408, r: false}, {count: 3422, l: true}, {count: 3426, l: false}, {count: 3437, l: true}, {count: 3440, l: false}, {count: 3459, r: true}, {count: 3464, u: true}, {count: 3468, r: false}, {count: 3471, l: true}, {count: 3471, u: false}, {count: 3477, l: false}, {count: 3484, l: true}, {count: 3488, l: false}, {count: 3493, l: true}, {count: 3519, l: false}, {count: 3520, r: true}, {count: 3540, r: false}, {count: 3566, r: true}, {count: 3570, r: false}, {count: 3576, d: true}, {count: 3581, d: false}, {count: 3592, r: true}, {count: 3604, r: false}, {count: 3612, l: true}, {count: 3620, l: false}, {count: 3621, d: true}, {count: 3628, d: false}, {count: 3639, r: true}, {count: 3645, u: true}, {count: 3647, r: false}, {count: 3666, u: false}, {count: 3667, r: true}, {count: 3674, r: false}, {count: 3677, d: true}, {count: 3684, d: false}, {count: 3691, l: true}, {count: 3711, l: false}, {count: 3724, r: true}, {count: 3730, r: false}, {count: 3735, u: true}, {count: 3742, u: false}, {count: 3755, l: true}, {count: 3760, l: false}, {count: 3783, d: true}, {count: 3791, d: false}, {count: 3795, r: true}, {count: 3809, u: true}, {count: 3813, r: false}, {count: 3829, r: true}, {count: 3831, u: false}, {count: 3839, d: true}, {count: 3856, d: false}, {count: 3867, r: false}, {count: 3891, z: false}, {count: 3907, l: true}, {count: 3912, u: true}, {count: 3914, l: false}, {count: 3921, u: false}, {count: 3987, z: true}, {count: 4034, z: true}, {count: 4050, z: true}, {count: 4066, z: true}, {count: 4077, l: true}, {count: 4087, s: true}, {count: 4097, l: false}, {count: 4098, d: true}, {count: 4105, r: true}, {count: 4106, d: false}, {count: 4114, d: true}, {count: 4116, r: false}, {count: 4121, d: false}, {count: 4131, l: true}, {count: 4136, l: false}, {count: 4147, l: true}, {count: 4150, l: false}, {count: 4159, l: true}, {count: 4163, l: false}, {count: 4169, l: true}, {count: 4173, l: false}, {count: 4176, l: true}, {count: 4182, l: false}, {count: 4193, r: true}, {count: 4217, d: true}, {count: 4219, r: false}, {count: 4230, d: false}, {count: 4285, l: true}, {count: 4288, l: false}, {count: 4312, u: true}, {count: 4316, u: false}, {count: 4320, l: true}, {count: 4324, l: false}, {count: 4329, l: true}, {count: 4334, l: false}, {count: 4346, u: true}, {count: 4349, u: false}, {count: 4365, u: true}, {count: 4367, u: false}, {count: 4372, u: true}, {count: 4377, u: false}, {count: 4421, l: true}, {count: 4427, l: false}, {count: 4491, r: true}, {count: 4502, r: false}, {count: 4575, r: true}, {count: 4584, r: false}, {count: 4597, d: true}, {count: 4603, d: false}, {count: 4605, r: true}, {count: 4617, d: true}, {count: 4623, r: false}, {count: 4627, d: false}, {count: 4666, l: true}, {count: 4674, l: false}, {count: 4707, s: false}, {count: 4709, l: true}, {count: 4720, l: false}, {count: 4721, u: true}, {count: 4757, s: true}, {count: 4765, u: false}, {count: 4774, d: true}, {count: 4828, d: false}, {count: 4831, l: true}, {count: 4837, l: false}, {count: 4859, r: true}, {count: 4865, r: false}, {count: 5126, r: true}, {count: 5142, d: true}, {count: 5149, d: false}, {count: 5155, r: false}, {count: 5163, r: true}, {count: 5171, r: false}, {count: 5185, r: true}, {count: 5189, r: false}, {count: 5208, r: true}, {count: 5215, r: false}, {count: 5225, r: true}, {count: 5239, r: false}, {count: 5268, d: true}, {count: 5284, r: true}, {count: 5285, d: false}, {count: 5290, r: false}, {count: 5305, l: true}, {count: 5317, l: false}, {count: 5325, d: true}, {count: 5334, d: false}, {count: 5336, l: true}, {count: 5341, l: false}, {count: 5353, l: true}, {count: 5358, l: false}, {count: 5387, l: true}, {count: 5392, l: false}, {count: 5410, r: true}, {count: 5420, r: false}, {count: 5433, l: true}, {count: 5443, l: false}, {count: 5450, l: true}, {count: 5453, l: false}, {count: 5466, r: true}, {count: 5474, r: false}, {count: 5482, u: true}, {count: 5490, u: false}, {count: 5492, l: true}, {count: 5500, l: false}, {count: 5515, r: true}, {count: 5519, r: false}, {count: 5543, l: true}, {count: 5548, l: false}, {count: 5564, r: true}, {count: 5573, r: false}, {count: 5582, l: true}, {count: 5598, l: false}, {count: 5628, d: true}, {count: 5635, d: false}, {count: 5637, r: true}, {count: 5643, r: false}, {count: 5674, r: true}, {count: 5679, r: false}, {count: 5692, r: true}, {count: 5699, r: false}, {count: 5710, r: true}, {count: 5712, r: false}, {count: 5725, r: true}, {count: 5729, r: false}, {count: 5747, s: false}, {count: 5749, u: true}, {count: 5821, s: true}, {count: 5823, u: false}, {count: 5826, r: true}, {count: 5831, r: false}, {count: 5856, l: true}, {count: 5860, l: false}, {count: 5874, d: true}, {count: 5885, d: false}, {count: 5900, d: true}, {count: 5906, d: false}, {count: 5930, r: true}, {count: 5934, r: false}, {count: 5959, l: true}, {count: 5963, l: false}, {count: 5997, l: true}, {count: 5999, u: true}, {count: 6000, l: false}, {count: 6014, u: false}, {count: 6018, r: true}, {count: 6021, r: false}, {count: 6050, r: true}, {count: 6055, r: false}, {count: 6058, u: true}, {count: 6075, l: true}, {count: 6075, u: false}, {count: 6080, u: true}, {count: 6080, l: false}, {count: 6084, u: false}, {count: 6086, r: true}, {count: 6093, r: false}, {count: 6115, l: true}, {count: 6123, l: false}, {count: 6128, u: true}, {count: 6132, u: false}, {count: 6144, l: true}, {count: 6147, l: false}, {count: 6163, r: true}, {count: 6166, r: false}, {count: 6175, u: true}, {count: 6179, u: false}, {count: 6184, r: true}, {count: 6187, r: false}, {count: 6200, r: true}, {count: 6203, r: false}, {count: 6209, l: true}, {count: 6211, l: false}, {count: 6215, l: true}, {count: 6219, l: false}, {count: 6224, r: true}, {count: 6231, r: false}, {count: 6235, l: true}, {count: 6244, l: false}, {count: 6258, u: true}, {count: 6261, u: false}, {count: 6264, r: true}, {count: 6268, r: false}, ] } ================================================ FILE: replay/replay2.txt ================================================ { user: 'takahirox', characterIndex: 1, seed: 11249, params: [ {count: 26, d: true}, {count: 33, d: false}, {count: 40, z: true}, {count: 46, l: true}, {count: 91, r: true}, {count: 92, l: false}, {count: 131, r: false}, {count: 131, l: true}, {count: 163, l: false}, {count: 164, r: true}, {count: 194, l: true}, {count: 194, r: false}, {count: 224, l: false}, {count: 225, u: true}, {count: 243, u: false}, {count: 244, r: true}, {count: 249, z: false}, {count: 253, r: false}, {count: 272, r: true}, {count: 277, r: false}, {count: 314, r: true}, {count: 319, r: false}, {count: 330, r: true}, {count: 380, l: true}, {count: 381, r: false}, {count: 382, z: true}, {count: 412, r: true}, {count: 412, l: false}, {count: 439, z: false}, {count: 440, u: true}, {count: 441, r: false}, {count: 470, l: true}, {count: 473, u: false}, {count: 480, l: false}, {count: 490, l: true}, {count: 495, l: false}, {count: 501, l: true}, {count: 506, l: false}, {count: 513, l: true}, {count: 516, l: false}, {count: 519, d: true}, {count: 547, l: true}, {count: 549, d: false}, {count: 588, z: true}, {count: 594, r: true}, {count: 595, l: false}, {count: 626, l: true}, {count: 626, r: false}, {count: 650, u: true}, {count: 651, l: false}, {count: 653, z: false}, {count: 682, r: true}, {count: 683, u: false}, {count: 693, r: false}, {count: 701, r: true}, {count: 706, r: false}, {count: 718, r: true}, {count: 724, d: true}, {count: 765, l: true}, {count: 766, z: true}, {count: 766, d: false}, {count: 767, r: false}, {count: 793, r: true}, {count: 794, l: false}, {count: 825, u: true}, {count: 826, r: false}, {count: 829, z: false}, {count: 865, l: true}, {count: 867, u: false}, {count: 880, l: false}, {count: 887, l: true}, {count: 892, l: false}, {count: 902, d: true}, {count: 911, z: true}, {count: 939, s: true}, {count: 945, l: true}, {count: 946, d: false}, {count: 990, d: true}, {count: 991, l: false}, {count: 1002, l: true}, {count: 1002, d: false}, {count: 1032, u: true}, {count: 1032, l: false}, {count: 1052, r: true}, {count: 1052, u: false}, {count: 1076, d: true}, {count: 1079, r: false}, {count: 1088, d: false}, {count: 1114, l: true}, {count: 1138, u: true}, {count: 1140, l: false}, {count: 1161, u: false}, {count: 1172, r: true}, {count: 1181, d: true}, {count: 1185, r: false}, {count: 1196, d: false}, {count: 1200, d: true}, {count: 1210, r: true}, {count: 1212, d: false}, {count: 1215, d: true}, {count: 1217, r: false}, {count: 1223, r: true}, {count: 1224, d: false}, {count: 1234, r: false}, {count: 1249, r: true}, {count: 1256, r: false}, {count: 1259, u: true}, {count: 1263, l: true}, {count: 1264, u: false}, {count: 1302, r: true}, {count: 1302, s: false}, {count: 1303, l: false}, {count: 1327, r: false}, {count: 1378, r: true}, {count: 1388, r: false}, {count: 1466, l: true}, {count: 1493, l: false}, {count: 1523, u: true}, {count: 1571, u: false}, {count: 1575, r: true}, {count: 1582, d: true}, {count: 1592, d: false}, {count: 1594, r: false}, {count: 1600, d: true}, {count: 1605, r: true}, {count: 1610, r: false}, {count: 1627, d: false}, {count: 1684, u: true}, {count: 1726, u: false}, {count: 1732, d: true}, {count: 1781, l: true}, {count: 1782, d: false}, {count: 1793, l: false}, {count: 1793, r: true}, {count: 1827, l: true}, {count: 1828, r: false}, {count: 1862, u: true}, {count: 1864, l: false}, {count: 1882, u: false}, {count: 1883, r: true}, {count: 1901, r: false}, {count: 1918, r: true}, {count: 1922, r: false}, {count: 1932, r: true}, {count: 1936, r: false}, {count: 1944, r: true}, {count: 1956, d: true}, {count: 1970, s: true}, {count: 1976, d: false}, {count: 1977, r: false}, {count: 1978, l: true}, {count: 2012, r: true}, {count: 2012, s: false}, {count: 2013, l: false}, {count: 2050, r: false}, {count: 2050, u: true}, {count: 2069, l: true}, {count: 2070, u: false}, {count: 2091, l: false}, {count: 2097, l: true}, {count: 2101, l: false}, {count: 2105, l: true}, {count: 2110, l: false}, {count: 2115, l: true}, {count: 2121, l: false}, {count: 2123, l: true}, {count: 2128, l: false}, {count: 2131, r: true}, {count: 2153, s: true}, {count: 2156, d: true}, {count: 2158, r: false}, {count: 2186, d: false}, {count: 2192, r: true}, {count: 2196, r: false}, {count: 2207, r: true}, {count: 2212, r: false}, {count: 2217, r: true}, {count: 2221, r: false}, {count: 2226, r: true}, {count: 2230, r: false}, {count: 2242, d: true}, {count: 2247, d: false}, {count: 2261, l: true}, {count: 2265, l: false}, {count: 2270, l: true}, {count: 2273, l: false}, {count: 2279, l: true}, {count: 2283, l: false}, {count: 2286, l: true}, {count: 2315, l: false}, {count: 2317, u: true}, {count: 2322, u: false}, {count: 2345, u: true}, {count: 2348, u: false}, {count: 2353, u: true}, {count: 2355, u: false}, {count: 2359, u: true}, {count: 2363, u: false}, {count: 2367, l: true}, {count: 2371, l: false}, {count: 2375, l: true}, {count: 2379, l: false}, {count: 2406, d: true}, {count: 2413, d: false}, {count: 2440, l: true}, {count: 2442, l: false}, {count: 2447, l: true}, {count: 2473, l: false}, {count: 2475, u: true}, {count: 2477, s: false}, {count: 2503, u: false}, {count: 2504, s: true}, {count: 2513, d: true}, {count: 2542, l: true}, {count: 2543, d: false}, {count: 2548, d: true}, {count: 2549, l: false}, {count: 2557, r: true}, {count: 2559, d: false}, {count: 2563, r: false}, {count: 2576, r: true}, {count: 2580, r: false}, {count: 2584, r: true}, {count: 2588, r: false}, {count: 2601, r: true}, {count: 2606, r: false}, {count: 2610, r: true}, {count: 2613, r: false}, {count: 2624, u: true}, {count: 2624, s: false}, {count: 2647, u: false}, {count: 2647, r: true}, {count: 2659, s: true}, {count: 2665, d: true}, {count: 2666, r: false}, {count: 2679, d: false}, {count: 2706, d: true}, {count: 2712, d: false}, {count: 2716, r: true}, {count: 2744, r: false}, {count: 2753, d: true}, {count: 2758, d: false}, {count: 2765, r: true}, {count: 2770, r: false}, {count: 2772, d: true}, {count: 2784, d: false}, {count: 2818, l: true}, {count: 2821, l: false}, {count: 2840, r: true}, {count: 2843, r: false}, {count: 2880, l: true}, {count: 2915, l: false}, {count: 2919, u: true}, {count: 2960, u: false}, {count: 2968, d: true}, {count: 2993, d: false}, {count: 3007, l: true}, {count: 3024, l: false}, {count: 3062, l: true}, {count: 3066, l: false}, {count: 3074, l: true}, {count: 3078, l: false}, {count: 3082, l: true}, {count: 3099, l: false}, {count: 3105, s: false}, {count: 3108, r: true}, {count: 3149, r: false}, {count: 3150, l: true}, {count: 3205, r: true}, {count: 3206, l: false}, {count: 3235, d: true}, {count: 3238, r: false}, {count: 3249, l: true}, {count: 3250, d: false}, {count: 3279, u: true}, {count: 3280, l: false}, {count: 3308, r: true}, {count: 3308, u: false}, {count: 3327, d: true}, {count: 3331, r: false}, {count: 3341, l: true}, {count: 3342, d: false}, {count: 3366, r: true}, {count: 3368, l: false}, {count: 3378, d: true}, {count: 3390, d: false}, {count: 3399, r: false}, {count: 3412, l: true}, {count: 3416, l: false}, {count: 3457, l: true}, {count: 3475, l: false}, {count: 3478, u: true}, {count: 3485, u: false}, {count: 3492, l: true}, {count: 3497, l: false}, {count: 3505, u: true}, {count: 3511, u: false}, {count: 3525, d: true}, {count: 3534, d: false}, {count: 3539, r: true}, {count: 3548, r: false}, {count: 3595, r: true}, {count: 3607, d: true}, {count: 3608, r: false}, {count: 3614, d: false}, {count: 3629, r: true}, {count: 3634, r: false}, {count: 3641, l: true}, {count: 3653, l: false}, {count: 3659, r: true}, {count: 3667, r: false}, {count: 3670, u: true}, {count: 3686, u: false}, {count: 3696, d: true}, {count: 3703, d: false}, {count: 3718, l: true}, {count: 3743, l: false}, {count: 3745, r: true}, {count: 3753, r: false}, {count: 3762, r: true}, {count: 3766, r: false}, {count: 3793, r: true}, {count: 3804, r: false}, {count: 3810, d: true}, {count: 3816, d: false}, {count: 3842, r: true}, {count: 3848, r: false}, {count: 3861, u: true}, {count: 3879, u: false}, {count: 3891, d: true}, {count: 3903, d: false}, {count: 3920, l: true}, {count: 3924, l: false}, {count: 3961, u: true}, {count: 3970, u: false}, {count: 3973, l: true}, {count: 3979, l: false}, {count: 3991, r: true}, {count: 3998, r: false}, {count: 4002, r: true}, {count: 4012, r: false}, {count: 4037, u: true}, {count: 4050, u: false}, {count: 4050, r: true}, {count: 4069, d: true}, {count: 4091, l: true}, {count: 4092, r: false}, {count: 4092, d: false}, {count: 4122, z: false}, {count: 4128, l: false}, {count: 4147, r: true}, {count: 4163, r: false}, {count: 4213, z: true}, {count: 4236, z: true}, {count: 4250, z: true}, {count: 4270, z: true}, {count: 4282, l: true}, {count: 4292, s: true}, {count: 4295, l: false}, {count: 4302, r: true}, {count: 4310, r: false}, {count: 4321, d: true}, {count: 4328, d: false}, {count: 4330, r: true}, {count: 4335, r: false}, {count: 4357, r: true}, {count: 4361, r: false}, {count: 4381, l: true}, {count: 4387, l: false}, {count: 4392, l: true}, {count: 4394, l: false}, {count: 4414, r: true}, {count: 4419, r: false}, {count: 4442, d: true}, {count: 4448, d: false}, {count: 4458, u: true}, {count: 4463, u: false}, {count: 4495, l: true}, {count: 4499, l: false}, {count: 4514, l: true}, {count: 4516, l: false}, {count: 4529, u: true}, {count: 4532, u: false}, {count: 4540, l: true}, {count: 4544, l: false}, {count: 4596, l: true}, {count: 4597, l: false}, {count: 4623, l: true}, {count: 4626, l: false}, {count: 4694, r: true}, {count: 4697, r: false}, {count: 4702, r: true}, {count: 4705, r: false}, {count: 4710, r: true}, {count: 4713, r: false}, {count: 4715, r: true}, {count: 4719, r: false}, {count: 4739, l: true}, {count: 4741, l: false}, {count: 4747, l: true}, {count: 4752, l: false}, {count: 4774, r: true}, {count: 4778, r: false}, {count: 4795, r: true}, {count: 4798, r: false}, {count: 4831, d: true}, {count: 4836, d: false}, {count: 4847, r: true}, {count: 4849, r: false}, {count: 4874, l: true}, {count: 4878, l: false}, {count: 4909, l: true}, {count: 4913, l: false}, {count: 4925, u: true}, {count: 4928, u: false}, {count: 4932, u: true}, {count: 4936, u: false}, {count: 4941, u: true}, {count: 4945, u: false}, {count: 4961, l: true}, {count: 4963, l: false}, {count: 5000, d: true}, {count: 5002, d: false}, {count: 5013, l: true}, {count: 5016, l: false}, {count: 5032, r: true}, {count: 5034, r: false}, {count: 5051, l: true}, {count: 5055, l: false}, {count: 5075, r: true}, {count: 5077, r: false}, {count: 5094, l: true}, {count: 5097, l: false}, {count: 5137, l: true}, {count: 5147, l: false}, {count: 5157, r: true}, {count: 5171, r: false}, {count: 5179, l: true}, {count: 5185, l: false}, {count: 5205, r: true}, {count: 5208, r: false}, {count: 5239, l: true}, {count: 5245, l: false}, {count: 5264, r: true}, {count: 5266, r: false}, {count: 5295, l: true}, {count: 5299, l: false}, {count: 5314, r: true}, {count: 5318, r: false}, {count: 5346, l: true}, {count: 5350, l: false}, {count: 5361, r: true}, {count: 5369, r: false}, {count: 5383, l: true}, {count: 5390, l: false}, {count: 5413, r: true}, {count: 5421, d: true}, {count: 5421, r: false}, {count: 5430, d: false}, {count: 5481, r: true}, {count: 5488, r: false}, {count: 5511, l: true}, {count: 5516, l: false}, {count: 5528, r: true}, {count: 5536, r: false}, {count: 5548, l: true}, {count: 5556, l: false}, {count: 5578, l: true}, {count: 5587, l: false}, {count: 5608, l: true}, {count: 5614, l: false}, {count: 5628, r: true}, {count: 5632, r: false}, {count: 5638, r: true}, {count: 5643, r: false}, {count: 5651, l: true}, {count: 5657, l: false}, {count: 5663, l: true}, {count: 5665, l: false}, {count: 5669, u: true}, {count: 5675, u: false}, {count: 5691, d: true}, {count: 5696, d: false}, {count: 5706, r: true}, {count: 5710, r: false}, {count: 5740, l: true}, {count: 5749, l: false}, {count: 5760, r: true}, {count: 5767, r: false}, {count: 5794, l: true}, {count: 5803, l: false}, {count: 5818, r: true}, {count: 5828, r: false}, {count: 5846, l: true}, {count: 5852, l: false}, {count: 5874, r: true}, {count: 5882, r: false}, {count: 5894, l: true}, {count: 5905, l: false}, {count: 5961, r: true}, {count: 5966, r: false}, {count: 5981, l: true}, {count: 5991, l: false}, {count: 6003, r: true}, {count: 6010, r: false}, {count: 6029, l: true}, {count: 6036, l: false}, {count: 6051, r: true}, {count: 6057, r: false}, {count: 6080, l: true}, {count: 6086, l: false}, {count: 6102, r: true}, {count: 6108, r: false}, {count: 6127, r: true}, {count: 6135, r: false}, {count: 6165, u: true}, {count: 6169, u: false}, {count: 6173, r: true}, {count: 6182, r: false}, {count: 6203, d: true}, {count: 6207, d: false}, {count: 6214, r: true}, {count: 6219, r: false}, {count: 6242, l: true}, {count: 6242, s: false}, {count: 6247, u: true}, {count: 6247, l: false}, {count: 6280, s: true}, {count: 6281, u: false}, {count: 6289, d: true}, {count: 6295, d: false}, {count: 6316, d: true}, {count: 6320, d: false}, {count: 6326, d: true}, {count: 6330, d: false}, {count: 6334, d: true}, {count: 6339, d: false}, {count: 6395, d: true}, {count: 6400, d: false}, {count: 6461, l: true}, {count: 6464, l: false}, {count: 6481, l: true}, {count: 6484, l: false}, {count: 6493, r: true}, {count: 6496, r: false}, {count: 6500, d: true}, {count: 6503, d: false}, {count: 6588, d: true}, {count: 6593, d: false}, {count: 6599, l: true}, {count: 6602, l: false}, {count: 6645, l: true}, {count: 6649, l: false}, {count: 6663, r: true}, {count: 6667, r: false}, {count: 6725, r: true}, {count: 6729, r: false}, {count: 6738, r: true}, {count: 6741, r: false}, {count: 6754, r: true}, {count: 6759, r: false}, {count: 6770, l: true}, {count: 6785, l: false}, {count: 6810, l: true}, {count: 6812, l: false}, {count: 6819, r: true}, {count: 6826, r: false}, {count: 6838, u: true}, {count: 6841, u: false}, {count: 6844, r: true}, {count: 6849, r: false}, {count: 6865, d: true}, {count: 6870, d: false}, {count: 6874, r: true}, {count: 6878, r: false}, {count: 6894, r: true}, {count: 6897, r: false}, {count: 6918, u: true}, {count: 6924, u: false}, {count: 6926, l: true}, {count: 6932, l: false}, {count: 6992, l: true}, {count: 6997, l: false}, {count: 7058, r: true}, {count: 7064, r: false}, {count: 7067, r: true}, {count: 7070, r: false}, {count: 7090, l: true}, {count: 7095, l: false}, {count: 7123, l: true}, {count: 7127, l: false}, {count: 7157, r: true}, {count: 7161, r: false}, {count: 7180, l: true}, {count: 7190, l: false}, {count: 7218, d: true}, {count: 7220, d: false}, {count: 7240, l: true}, {count: 7243, l: false}, {count: 7283, u: true}, {count: 7289, u: false}, {count: 7295, r: true}, {count: 7303, d: true}, {count: 7305, r: false}, {count: 7311, d: false}, {count: 7314, r: true}, {count: 7321, r: false}, {count: 7345, r: true}, {count: 7348, r: false}, {count: 7363, u: true}, {count: 7370, u: false}, {count: 7371, l: true}, {count: 7379, l: false}, {count: 7424, d: true}, {count: 7427, d: false}, {count: 7431, l: true}, {count: 7435, l: false}, {count: 7471, l: true}, {count: 7474, l: false}, {count: 7477, l: true}, {count: 7482, l: false}, {count: 7501, r: true}, {count: 7510, s: false}, {count: 7511, r: false}, {count: 7512, z: false}, {count: 7513, u: true}, {count: 7531, u: false}, {count: 7566, r: true}, {count: 7583, r: false}, {count: 7635, z: true}, {count: 7698, z: true}, {count: 7716, z: true}, {count: 7720, d: true}, {count: 7734, d: false}, {count: 7734, l: true}, {count: 7789, r: true}, {count: 7790, l: false}, {count: 7835, l: true}, {count: 7835, r: false}, {count: 7880, r: true}, {count: 7881, l: false}, {count: 7910, r: false}, {count: 7915, l: true}, {count: 7923, l: false}, {count: 7939, l: true}, {count: 7950, l: false}, {count: 7953, r: true}, {count: 7961, d: true}, {count: 7964, r: false}, {count: 7968, l: true}, {count: 7969, d: false}, {count: 7985, l: false}, {count: 7990, d: true}, {count: 7996, d: false}, {count: 8005, r: true}, {count: 8022, r: false}, {count: 8041, u: true}, {count: 8051, u: false}, {count: 8056, x: true}, {count: 8070, u: true}, {count: 8088, u: false}, {count: 8089, r: true}, {count: 8095, d: true}, {count: 8097, r: false}, {count: 8110, l: true}, {count: 8110, d: false}, {count: 8132, l: false}, {count: 8135, r: true}, {count: 8182, l: true}, {count: 8182, r: false}, {count: 8238, r: true}, {count: 8239, l: false}, {count: 8280, r: false}, {count: 8281, l: true}, {count: 8303, l: false}, {count: 8309, r: true}, {count: 8322, r: false}, {count: 8328, x: true}, {count: 8337, u: true}, {count: 8362, u: false}, {count: 8413, d: true}, {count: 8441, d: false}, {count: 8441, l: true}, {count: 8471, r: true}, {count: 8471, l: false}, {count: 8528, r: false}, {count: 8536, u: true}, {count: 8596, l: true}, {count: 8597, u: false}, {count: 8609, d: true}, {count: 8610, l: false}, {count: 8660, s: true}, {count: 8672, l: true}, {count: 8672, d: false}, {count: 8727, u: true}, {count: 8728, l: false}, {count: 8749, r: true}, {count: 8750, u: false}, {count: 8759, d: true}, {count: 8766, r: false}, {count: 8768, r: true}, {count: 8781, d: false}, {count: 8783, r: false}, {count: 8785, d: true}, {count: 8791, d: false}, {count: 8795, l: true}, {count: 8826, u: true}, {count: 8827, l: false}, {count: 8858, r: true}, {count: 8859, u: false}, {count: 8876, d: true}, {count: 8877, r: false}, {count: 8885, d: false}, {count: 8893, d: true}, {count: 8902, d: false}, {count: 8907, l: true}, {count: 8916, l: false}, {count: 8929, u: true}, {count: 8935, u: false}, {count: 8943, d: true}, {count: 8955, l: true}, {count: 8955, d: false}, {count: 8972, l: false}, {count: 8985, d: true}, {count: 8991, r: true}, {count: 8992, d: false}, {count: 9023, r: false}, {count: 9054, r: true}, {count: 9062, d: true}, {count: 9063, r: false}, {count: 9070, d: false}, {count: 9085, r: true}, {count: 9091, r: false}, {count: 9098, u: true}, {count: 9133, u: false}, {count: 9135, l: true}, {count: 9161, l: false}, {count: 9166, d: true}, {count: 9174, l: true}, {count: 9175, d: false}, {count: 9191, l: false}, {count: 9195, u: true}, {count: 9248, u: false}, {count: 9251, r: true}, {count: 9251, s: false}, {count: 9258, r: false}, {count: 9271, r: true}, {count: 9278, d: true}, {count: 9283, r: false}, {count: 9326, r: true}, {count: 9331, d: false}, {count: 9337, r: false}, {count: 9354, u: true}, {count: 9371, u: false}, {count: 9380, u: true}, {count: 9416, u: false}, {count: 9421, d: true}, {count: 9475, l: true}, {count: 9476, d: false}, {count: 9490, r: true}, {count: 9491, l: false}, {count: 9526, l: true}, {count: 9527, r: false}, {count: 9557, u: true}, {count: 9558, l: false}, {count: 9573, u: false}, {count: 9575, l: true}, {count: 9584, l: false}, {count: 9587, r: true}, {count: 9615, r: false}, {count: 9639, r: true}, {count: 9647, d: true}, {count: 9650, s: true}, {count: 9675, d: false}, {count: 9679, l: true}, {count: 9679, r: false}, {count: 9686, s: false}, {count: 9718, r: true}, {count: 9718, l: false}, {count: 9757, u: true}, {count: 9759, r: false}, {count: 9779, l: true}, {count: 9781, u: false}, {count: 9802, l: false}, {count: 9816, l: true}, {count: 9819, l: false}, {count: 9824, l: true}, {count: 9828, l: false}, {count: 9838, s: true}, {count: 9851, l: true}, {count: 9856, l: false}, {count: 9861, d: true}, {count: 9866, d: false}, {count: 9875, r: true}, {count: 9880, r: false}, {count: 9883, d: true}, {count: 9888, d: false}, {count: 9897, l: true}, {count: 9901, l: false}, {count: 9910, d: true}, {count: 9913, d: false}, {count: 9937, d: true}, {count: 9940, d: false}, {count: 9983, r: true}, {count: 9986, r: false}, {count: 9997, d: true}, {count: 9999, d: false}, {count: 10004, d: true}, {count: 10009, d: false}, {count: 10031, d: true}, {count: 10035, d: false}, {count: 10039, d: true}, {count: 10041, d: false}, {count: 10048, r: true}, {count: 10051, r: false}, {count: 10066, u: true}, {count: 10069, u: false}, {count: 10073, u: true}, {count: 10075, u: false}, {count: 10081, u: true}, {count: 10084, u: false}, {count: 10089, u: true}, {count: 10104, l: true}, {count: 10105, u: false}, {count: 10144, d: true}, {count: 10145, l: false}, {count: 10157, d: false}, {count: 10159, l: true}, {count: 10165, l: false}, {count: 10210, u: true}, {count: 10226, u: false}, {count: 10229, r: true}, {count: 10230, s: false}, {count: 10238, r: false}, {count: 10246, r: true}, {count: 10268, r: false}, {count: 10276, s: true}, {count: 10282, d: true}, {count: 10286, d: false}, {count: 10288, r: true}, {count: 10293, r: false}, {count: 10296, d: true}, {count: 10299, r: true}, {count: 10300, d: false}, {count: 10303, r: false}, {count: 10316, d: true}, {count: 10320, d: false}, {count: 10324, d: true}, {count: 10327, d: false}, {count: 10335, l: true}, {count: 10338, l: false}, {count: 10341, l: true}, {count: 10343, l: false}, {count: 10357, u: true}, {count: 10376, u: false}, {count: 10412, s: false}, {count: 10423, l: true}, {count: 10428, l: false}, {count: 10428, s: true}, {count: 10432, d: true}, {count: 10438, d: false}, {count: 10453, l: true}, {count: 10455, l: false}, {count: 10458, d: true}, {count: 10467, d: false}, {count: 10469, r: true}, {count: 10473, r: false}, {count: 10491, u: true}, {count: 10493, u: false}, {count: 10496, u: true}, {count: 10499, u: false}, {count: 10501, u: true}, {count: 10505, u: false}, {count: 10508, u: true}, {count: 10511, u: false}, {count: 10515, u: true}, {count: 10518, u: false}, {count: 10521, u: true}, {count: 10525, u: false}, {count: 10551, d: true}, {count: 10565, d: false}, {count: 10569, l: true}, {count: 10588, d: true}, {count: 10588, l: false}, {count: 10597, d: false}, {count: 10607, d: true}, {count: 10611, d: false}, {count: 10625, r: true}, {count: 10627, r: false}, {count: 10643, r: true}, {count: 10645, r: false}, {count: 10663, l: true}, {count: 10666, l: false}, {count: 10683, u: true}, {count: 10695, u: false}, {count: 10701, s: false}, {count: 10701, r: true}, {count: 10725, d: true}, {count: 10728, s: true}, {count: 10728, r: false}, {count: 10741, d: false}, {count: 10742, l: true}, {count: 10754, l: false}, {count: 10766, r: true}, {count: 10770, r: false}, {count: 10774, r: true}, {count: 10777, r: false}, {count: 10780, r: true}, {count: 10782, r: false}, {count: 10799, r: true}, {count: 10802, r: false}, {count: 10810, u: true}, {count: 10829, u: false}, {count: 10861, l: true}, {count: 10885, l: false}, {count: 10916, d: true}, {count: 10920, d: false}, {count: 10942, r: true}, {count: 10945, r: false}, {count: 10948, r: true}, {count: 10951, r: false}, {count: 11007, s: false}, {count: 11035, d: true}, {count: 11046, d: false}, {count: 11047, l: true}, {count: 11093, l: false}, {count: 11093, r: true}, {count: 11144, l: true}, {count: 11145, r: false}, {count: 11190, u: true}, {count: 11191, l: false}, {count: 11211, u: false}, {count: 11251, r: true}, {count: 11263, r: false}, {count: 11285, u: true}, {count: 11291, u: false}, {count: 11293, r: true}, {count: 11299, r: false}, {count: 11318, d: true}, {count: 11326, d: false}, {count: 11334, l: true}, {count: 11345, l: false}, {count: 11350, d: true}, {count: 11357, d: false}, {count: 11359, l: true}, {count: 11364, l: false}, {count: 11388, d: true}, {count: 11393, d: false}, {count: 11397, d: true}, {count: 11401, d: false}, {count: 11415, d: true}, {count: 11420, d: false}, {count: 11451, r: true}, {count: 11464, r: false}, {count: 11480, d: true}, {count: 11485, r: true}, {count: 11486, d: false}, {count: 11491, r: false}, {count: 11521, r: true}, {count: 11526, r: false}, {count: 11547, l: true}, {count: 11552, l: false}, {count: 11560, r: true}, {count: 11565, r: false}, {count: 11568, u: true}, {count: 11583, u: false}, {count: 11598, d: true}, {count: 11604, d: false}, {count: 11613, l: true}, {count: 11633, l: false}, {count: 11634, d: true}, {count: 11640, d: false}, {count: 11644, l: true}, {count: 11651, l: false}, {count: 11659, r: true}, {count: 11672, r: false}, {count: 11694, r: true}, {count: 11702, r: false}, {count: 11719, d: true}, {count: 11724, d: false}, {count: 11735, r: true}, {count: 11741, r: false}, {count: 11745, r: true}, {count: 11747, r: false}, {count: 11755, u: true}, {count: 11775, u: false}, {count: 11792, d: true}, {count: 11797, d: false}, {count: 11815, l: true}, {count: 11828, l: false}, {count: 11829, l: true}, {count: 11837, d: true}, {count: 11837, l: false}, {count: 11845, l: true}, {count: 11846, d: false}, {count: 11858, l: false}, {count: 11862, r: true}, {count: 11886, r: false}, {count: 11901, r: true}, {count: 11916, r: false}, {count: 11931, u: true}, {count: 11954, u: false}, {count: 11955, r: true}, {count: 11978, d: true}, {count: 11982, r: false}, {count: 11995, l: true}, {count: 11996, d: false}, {count: 12016, l: false}, {count: 12017, z: false}, {count: 12021, r: true}, {count: 12039, r: false}, {count: 12042, u: true}, {count: 12059, u: false}, {count: 12122, z: true}, {count: 12143, z: true}, {count: 12166, z: true}, {count: 12173, l: true}, {count: 12182, s: true}, {count: 12188, l: false}, {count: 12190, d: true}, {count: 12197, d: false}, {count: 12202, l: true}, {count: 12203, l: false}, {count: 12244, d: true}, {count: 12246, d: false}, {count: 12251, d: true}, {count: 12253, d: false}, {count: 12260, l: true}, {count: 12263, l: false}, {count: 12273, d: true}, {count: 12277, d: false}, {count: 12279, r: true}, {count: 12281, r: false}, {count: 13182, s: false}, {count: 13190, r: true}, {count: 13203, r: false}, {count: 13207, l: true}, {count: 13233, s: true}, {count: 13237, l: false}, {count: 13239, r: true}, {count: 13262, l: true}, {count: 13262, r: false}, {count: 13278, r: true}, {count: 13279, l: false}, {count: 13301, r: false}, {count: 13312, l: true}, {count: 13320, l: false}, {count: 13325, d: true}, {count: 13344, d: false}, {count: 13360, l: true}, {count: 13381, u: true}, {count: 13382, l: false}, {count: 13386, s: false}, {count: 13398, s: true}, {count: 13399, u: false}, {count: 13412, r: true}, {count: 13419, d: true}, {count: 13423, r: false}, {count: 13424, d: false}, {count: 13429, d: true}, {count: 13434, d: false}, {count: 13436, l: true}, {count: 13443, l: false}, {count: 13447, l: true}, {count: 13458, l: false}, {count: 13458, u: true}, {count: 13463, u: false}, {count: 13464, r: true}, {count: 13471, r: false}, {count: 13488, r: true}, {count: 13492, r: false}, {count: 13494, r: true}, {count: 13498, r: false}, {count: 13514, d: true}, {count: 13523, r: true}, {count: 13528, d: false}, {count: 13533, r: false}, {count: 13540, r: true}, {count: 13542, d: true}, {count: 13545, r: false}, {count: 13551, r: true}, {count: 13552, d: false}, {count: 13557, r: false}, {count: 13653, l: true}, {count: 13658, l: false}, {count: 13689, r: true}, {count: 13692, r: false}, {count: 13897, r: true}, {count: 13900, u: true}, {count: 13903, r: false}, {count: 13911, u: false}, {count: 13915, l: true}, {count: 13925, l: false}, {count: 13939, r: true}, {count: 13945, r: false}, {count: 13958, l: true}, {count: 13967, l: false}, {count: 14015, r: true}, {count: 14019, r: false}, {count: 14299, d: true}, {count: 14311, l: true}, {count: 14312, d: false}, {count: 14319, l: false}, {count: 14341, r: true}, {count: 14346, r: false}, {count: 14353, u: true}, {count: 14360, u: false}, {count: 14383, r: true}, {count: 14400, r: false}, {count: 14434, l: true}, {count: 14438, l: false}, {count: 14483, l: true}, {count: 14487, l: false}, {count: 14685, d: true}, {count: 14691, d: false}, {count: 14706, s: false}, {count: 14710, l: true}, {count: 14717, l: false}, {count: 14717, u: true}, {count: 14717, z: false}, {count: 14768, z: true}, {count: 14777, s: true}, {count: 14780, u: false}, {count: 14796, d: true}, {count: 14856, d: false}, {count: 14879, u: true}, {count: 14885, u: false}, {count: 14902, l: true}, {count: 14908, l: false}, {count: 14910, u: true}, {count: 14921, u: false}, {count: 14945, l: true}, {count: 14955, l: false}, {count: 14968, r: true}, {count: 14975, r: false}, {count: 14983, r: true}, {count: 14987, r: false}, {count: 14998, d: true}, {count: 15014, l: true}, {count: 15014, d: false}, {count: 15019, l: false}, {count: 15030, u: true}, {count: 15041, u: false}, {count: 15045, r: true}, {count: 15048, r: false}, {count: 15072, d: true}, {count: 15076, d: false}, {count: 15128, r: true}, {count: 15137, r: false}, {count: 15143, r: true}, {count: 15151, r: false}, {count: 15153, u: true}, {count: 15158, l: true}, {count: 15158, u: false}, {count: 15164, l: false}, {count: 15180, l: true}, {count: 15183, l: false}, {count: 15185, l: true}, {count: 15202, l: false}, {count: 15204, r: true}, {count: 15209, d: true}, {count: 15211, x: true}, {count: 15215, r: false}, {count: 15215, d: false}, {count: 15219, u: true}, {count: 15228, r: true}, {count: 15228, u: false}, {count: 15232, r: false}, {count: 15233, u: true}, {count: 15261, u: false}, {count: 15265, d: true}, {count: 15294, d: false}, {count: 15350, d: true}, {count: 15356, d: false}, {count: 15363, l: true}, {count: 15370, l: false}, {count: 15389, r: true}, {count: 15392, r: false}, {count: 15483, l: true}, {count: 15500, l: false}, {count: 15519, r: true}, {count: 15525, r: false}, {count: 15533, r: true}, {count: 15536, r: false}, {count: 15554, l: true}, {count: 15563, l: false}, {count: 15572, r: true}, {count: 15575, r: false}, {count: 15597, r: true}, {count: 15602, r: false}, {count: 15627, r: true}, {count: 15629, r: false}, {count: 15643, d: true}, {count: 15654, d: false}, {count: 15666, r: true}, {count: 15676, r: false}, {count: 15692, r: true}, {count: 15697, r: false}, {count: 15707, u: true}, {count: 15712, l: true}, {count: 15713, u: false}, {count: 15719, l: false}, {count: 15731, l: true}, {count: 15734, l: false}, {count: 15750, u: true}, {count: 15756, u: false}, {count: 15766, r: true}, {count: 15771, r: false}, {count: 15776, r: true}, {count: 15785, u: true}, {count: 15786, r: false}, {count: 15791, l: true}, {count: 15791, u: false}, {count: 15802, l: false}, {count: 15844, l: true}, {count: 15848, l: false}, {count: 15861, u: true}, {count: 15870, u: false}, {count: 15875, r: true}, {count: 15892, r: false}, {count: 15910, l: true}, {count: 15918, l: false}, {count: 15918, d: true}, {count: 15933, l: true}, {count: 15933, x: true}, {count: 15934, d: false}, {count: 15937, l: false}, {count: 15945, u: true}, {count: 15973, u: false}, {count: 15997, d: true}, {count: 16007, d: false}, {count: 16020, r: true}, {count: 16025, d: true}, {count: 16034, d: false}, {count: 16038, z: false}, {count: 16039, s: false}, {count: 16059, r: false}, {count: 16063, u: true}, {count: 16071, l: true}, {count: 16072, u: false}, {count: 16082, l: false}, {count: 16132, z: true}, {count: 16178, z: true}, ] } ================================================ FILE: replay/replay_list.txt ================================================ [ { id: 1, user: 'takahirox', characterIndex: 0, datetime: 1381201800000 }, { id: 2, user: 'takahirox', characterIndex: 1, datetime: 1381201932580 }, ] ================================================ FILE: source/Background.js ================================================ function BackgroundManager(gameState) { this.parent = ElementManager; this.parent.call(this, gameState); this.activeIndex = 0; this.drawers = []; this.effectTextures = []; this._init(); }; __inherit(BackgroundManager, ElementManager); BackgroundManager.prototype._MAX_NUM = 5; BackgroundManager.prototype._initMaxNum = function() { return this._MAX_NUM; }; /** * Unnecessary to have factory. */ BackgroundManager.prototype._initFactory = function() { }; BackgroundManager.prototype._init = function() { this.elements.length = 0; this.add(new Background(this.gameState, this.gameState.maxX, this.gameState.maxY)); this.add(new Background(this.gameState, this.gameState.maxX, this.gameState.maxY)); }; BackgroundManager.prototype.initDrawer = function(layer, image) { this.drawers.length = 0; this.drawers.push(new BackgroundDrawer( this.get(0), layer, this.gameState.getImage(Game._IMG_BG1))); this.drawers.push(new BackgroundDrawer( this.get(1), layer, this.gameState.getImage(Game._IMG_BG2))); this.effectTextures.length = 0; this._initForwardBlackEffect(layer); }; /** * TODO: is there a way to generate non-premultiplied image? */ BackgroundManager.prototype._initForwardBlackEffect = function(layer) { var h = 3; var loop = 40; var width = layer.calculateSquareValue(this.gameState.getWidth()); var height = layer.calculateSquareValue(h*loop); var canvas = document.createElement('canvas'); canvas.width = width; canvas.height = height; var surface = canvas.getContext('2d'); surface.fillStyle = 'rgb(0, 0, 0)'; for(var i = 0; i < loop; i++) { surface.globalAlpha = 0.4 - i * 0.01; surface.fillRect(0, i * h, width, h); } var texture = layer.generateTexture(canvas); texture.width = width; texture.height = height; this.effectTextures.push(texture); }; BackgroundManager.prototype.setDarkness = function(d) { this.get(this.activeIndex).getView().setDarkness(d); }; BackgroundManager.prototype.draw = function(layer, darken) { var d = darken ? 0.4 : 1.0; this.setDarkness(d); this.drawers[this.activeIndex].draw(layer); if(! darken) this._drawEffect(layer); }; BackgroundManager.prototype._drawEffect = function(layer) { var texture = this.effectTextures[0]; layer.viewport(); layer.ortho(0.1, 10.0); mat4.identity(layer.mvMatrix); layer.drawOneTexture(texture, texture.width/2, texture.height/2, -1.0, texture.width, texture.height, 1.0, 1.0); }; /** * should not call parent reset() method to * keep elements available. */ BackgroundManager.prototype.reset = function() { this.activeIndex = 0; for(var i = 0; i < this.getNum(); i++) { this.get(i).reset(); } }; BackgroundManager.prototype.goNextStage = function() { this.activeIndex++; }; function BackgroundView(element) { this.parent = ElementView; this.parent.call(this, element); }; __inherit(BackgroundView, ElementView); BackgroundView.prototype.setDarkness = function(d) { this.d = d; }; BackgroundView.prototype._initVertices = function() { this.vertices[0] = -2.0; this.vertices[1] = 2.0; this.vertices[2] = 0.0; this.vertices[3] = 2.0; this.vertices[4] = 2.0; this.vertices[5] = 0.0; this.vertices[6] = 2.0; this.vertices[7] = -8.0; this.vertices[8] = 0.0; this.vertices[9] = -2.0; this.vertices[10] = -8.0; this.vertices[11] = 0.0; }; BackgroundView.prototype._initCoordinates = function() { this.coordinates[0] = 0.0; this.coordinates[1] = 10.0; this.coordinates[2] = 4.0; this.coordinates[3] = 10.0; this.coordinates[4] = 4.0; this.coordinates[5] = 0.0; this.coordinates[6] = 0.0; this.coordinates[7] = 0.0; }; function BackgroundDrawer(elementManager, gl, image) { this.parent = ElementDrawer; this.parent.call(this, elementManager, gl, image); }; __inherit(BackgroundDrawer, ElementDrawer); // only for reference BackgroundDrawer.prototype.Math = Math; BackgroundDrawer.prototype.mat4 = mat4; BackgroundDrawer.prototype._project = function(layer) { layer.perspective(60, 0.1, 100.0); }; BackgroundDrawer.prototype._prepareDraw = function(layer) { this.mat4.rotate(layer.mvMatrix, this.Math.PI/180*50, [-1, 0, 0]); }; /** * independent of fighter so far. * TODO: remove magic numbers. */ BackgroundDrawer.prototype.lookAtFromViewpointTarget = function(layer) { var eye = this._VIEWPOINTS_CONTAINERS[0]; var center = this._VIEWPOINTS_CONTAINERS[1]; var up = this._VIEWPOINTS_CONTAINERS[2]; eye[0] = 0; eye[1] = -0.4; eye[2] = 0.1; center[0] = 0; center[1] = 0; center[2] = 0; layer.lookAt(eye, center, up); }; function Background(gameState, maxX, maxY) { this.parent = Element; this.parent.call(this, gameState, maxX, maxY); this._initView(); }; __inherit(Background, Element); /** * Excepts not to call this method unlike other Element inherit class. * TODO: bad design. */ Background.prototype.init = function(params, image) { this.image = image; // Prolly unnecessary to call perent init() // this.parent.prototype.init.call(this, params, image); }; Background.prototype.reset = function() { this.count = 0; this.x = 0; this.y = 0; this.z = 0; }; Background.prototype._generateView = function() { return new BackgroundView(this); }; // not implemented yet and no plan to implement. Background.prototype.display = function(surface) { }; // TODO: temporal Background.prototype.Element_runStep = Element.prototype.runStep; Background.prototype.runStep = function() { this.Element_runStep(); // TODO: should be in BackgroundView? this.y = (this.count%200)/200; this.z = -this.gameState.bgScale; }; ================================================ FILE: source/Bomb.js ================================================ function BombManager( gameState ) { this.parent = ElementManager ; this.parent.call( this, gameState ) ; } __inherit( BombManager, ElementManager ) ; BombManager.prototype._MAX_NUM = 40; BombManager.prototype._initMaxNum = function() { return this._MAX_NUM; }; BombManager.prototype._initFactory = function( ) { this.factory = new BombFactory( this.gameState, this.gameState.getWidth( ), this.gameState.getHeight( ) ) ; } ; BombManager.prototype.initDrawer = function(layer, image) { this.drawer = new BombDrawer(this, layer, this.gameState.getImage(Game._IMG_BOMB)); }; // TODO: temporal BombManager.prototype.create = function( fighter ) { var bombs = this.factory.create( fighter ) ; for( var i = 0; i < bombs.length; i++ ) this.addElement( bombs[ i ] ) ; } ; function BombFactory( gameState, maxX, maxY ) { this.parent = ElementFactory ; this.parent.call( this, gameState, maxX, maxY ) ; this.params = [ ] ; this._initBomb( ) ; this.image = null; // TODO: temporal } __inherit( BombFactory, ElementFactory ) ; BombFactory.prototype._NUM = 20 ; BombFactory.prototype._BULLET_NUM = 10 ; BombFactory.prototype._initFreelist = function() { this.freelist = new BombFreeList(this._NUM, this.gameState); }; BombFactory.prototype._initBomb = function() { var num = this._BULLET_NUM; for(var i = 0; i < num; i++) { this.params.push( { 'x': 0, 'y': 0, 'v': { 'r': 0, 'theta': ((360 / num) | 0) * i, 'w': 1, 'ra': 0.2 } } ) ; } } ; BombFactory.prototype.create = function( fighter ) { var bombs = [ ] ; for( var i = 0; i < this.params.length; i++ ) { this.params[ i ].x = fighter.getX( ) ; this.params[ i ].y = fighter.getY( ) ; var bomb = this.freelist.get( ) ; bomb.init( this.params[ i ], this._getImage( this.params[ i ] ), fighter ) ; bombs.push( bomb ) ; } return bombs ; } ; /** * TODO: temporal */ BombFactory.prototype._getImage = function(params) { if(this.image === null) this.image = this.gameState.getImage(Game._IMG_BOMB); return this.image; }; function BombFreeList( num, gameState ) { this.parent = ElementFreeList ; this.parent.call( this, num, gameState ) ; } __inherit( BombFreeList, ElementFreeList ) ; BombFreeList.prototype._generateElement = function( ) { return new Bomb( this.gameState, this.gameState.getWidth( ), this.gameState.getHeight( ) ) ; } ; function BombDrawer(elementManager, layer, image) { this.parent = ElementDrawer; this.parent.call(this, elementManager, layer, image); }; __inherit(BombDrawer, ElementDrawer); BombDrawer.prototype.Layer = Layer; BombDrawer.prototype._getBlend = function() { return this.Layer._BLEND_ADD_ALPHA; }; function BombView(element) { this.parent = ElementView; this.parent.call(this, element); this.a = 0.4; }; __inherit(BombView, ElementView); /** * Currently Bomb represents just a big bullet. */ function Bomb( gameState, maxX, maxY ) { this.parent = Element ; this.parent.call( this, gameState, maxX, maxY ) ; } __inherit( Bomb, Element ) ; Bomb.prototype._WIDTH = 128 ; Bomb.prototype._HEIGHT = 128 ; Bomb.prototype._OUT_RANGE = 200 ; Bomb.prototype.Element_init = Element.prototype.init; Bomb.prototype.init = function( params, image, fighter ) { this.Element_init(params, image); this.setX( fighter.getX( ) ) ; this.setY( fighter.getY( ) ) ; this.width = this._WIDTH ; this.height = this._HEIGHT ; this.collisionWidth = this.width ; this.collisionHeight = this.height ; this.indexX = 0 ; this.indexY = 3 ; this._initView(); } ; Bomb.prototype._generateView = function() { return new BombView(this); }; Bomb.prototype.display = function( surface ) { // surface.save( ) ; surface.globalAlpha = 0.6 ; this.parent.prototype.display.call( this, surface ) ; surface.globalAlpha = 1.0 ; // surface.restore( ) ; } ; Bomb.prototype._outOfTheField = function( ) { if( this.getX( ) < -this._OUT_RANGE || this.getX( ) > this.maxX + this._OUT_RANGE || this.getY( ) < -this._OUT_RANGE || this.getY( ) > this.maxY + this._OUT_RANGE ) return true ; return false ; } ; ================================================ FILE: source/Boss.js ================================================ function BossManager( gameState, params ) { this.parent = ElementManager ; this.parent.call( this, gameState ) ; for( var i = 0; i < params.length; i++ ) { params[ i ].sort( function( a, b ) { return a.count - b.count ; } ) ; } this.params = params ; this.index = 0 ; this.stageIndex = 0 ; // TODO: temporal this.drawers = null; this.activeType = null; } ; __inherit( BossManager, ElementManager ) ; BossManager.prototype._MAX_NUM = 4; BossManager.prototype._initMaxNum = function() { return this._MAX_NUM; }; BossManager.prototype._initFactory = function( ) { this.factory = new BossFactory( this.gameState, this.gameState.getWidth( ), this.gameState.getHeight( ) ) ; } ; /** * TODO: consider the design. To use drawers is easy to handle, * but not smart. To extend BossDrawer is smarter. */ BossManager.prototype.initDrawer = function(layer, image) { this.drawers = []; this._generateDrawer(this.Boss._TYPE_RUMIA, layer); this._generateDrawer(this.Boss._TYPE_DAIYOUSEI, layer); this._generateDrawer(this.Boss._TYPE_CHIRNO, layer); }; BossManager.prototype._generateDrawer = function(key, layer) { this.drawers[key] = new BossDrawer(this, layer, this._getImage(key)); }; /** * TODO: consider who should manage image. */ BossManager.prototype._getImage = function(type) { var key; switch(type) { case this.Boss._TYPE_RUMIA: key = Game._IMG_ENEMY_RUMIA; break; case this.Boss._TYPE_DAIYOUSEI: key = Game._IMG_ENEMY_DAIYOUSEI; break; case this.Boss._TYPE_CHIRNO: key = Game._IMG_ENEMY_CHILNO; break; // TODO: temporal default: key = Game._IMG_ENEMY_MOKOU; break; } return this.gameState.getImage(key); }; __copyParentMethod(BossManager, ElementManager, 'reset'); BossManager.prototype.reset = function() { this.ElementManager_reset(); this.index = 0; this.stageIndex = 0; this.activeType = null; }; /** * assumes only one boss in a display. */ BossManager.prototype.draw = function(layer) { if(! this.existBoss()) return; this.drawers[this.activeType].draw(layer); }; BossManager.prototype.goNextStage = function() { this.ElementManager_reset(this); this.index = 0; this.stageIndex++; }; __copyParentMethod(BossManager, ElementManager, 'runStep'); BossManager.prototype.runStep = function() { this._generateBoss(); this.ElementManager_runStep(); }; BossManager.prototype._generateBoss = function() { if(this.gameState.isBossExist()) return; while(this.index < this.params[this.stageIndex].length && this.params[this.stageIndex][this.index].count + this.gameState.pending <= this.gameState.count) { var params = this.params[this.stageIndex][this.index]; var boss = this.factory.create(params); this.activeType = this._str2type(params.character); this.gameState.notifyBossAppeared(boss); this.addElement(boss); this.index++; } }; BossManager.prototype._str2type = function(str) { switch(str) { case 'rumia': return this.Boss._TYPE_RUMIA; case 'daiyousei': return this.Boss._TYPE_DAIYOUSEI; case 'chilno': return this.Boss._TYPE_CHIRNO; // TODO: temporal default: return null; } }; /** * TODO: temporal */ __copyParentMethod(BossManager, ElementManager, 'checkLoss'); BossManager.prototype.checkLoss = function() { this.ElementManager_checkLoss(this); }; /** * TODO: temporal */ BossManager.prototype.notifyCheckLoss = function(element) { if(element.dead != 'escape') this.gameState.notifyBossVanishEnd(element); }; /** * TODO: temporal. implement multi bosses? */ BossManager.prototype.getBoss = function() { return (this.existBoss()) > 0 ? this.elements[0] : null; }; BossManager.prototype.existBoss = function() { return this.getNum( ) > 0 ? true : false; }; /** * TODO: temporal. I wanna use the parent method but bigger one should be the argument of this method. */ __copyParentMethod(BossManager, ElementManager, 'checkCollisionWith'); BossManager.prototype.checkCollisionWith = function(fighter) { this.ElementManager_checkCollisionWith(null, fighter, this); }; BossManager.prototype.checkCollisionWithFighters = function(fighters) { for(var i = 0; i < fighters.length; i++) { this.checkCollisionWith(fighters[i]); } }; BossManager.prototype.notifyCollision = function(id, fighter, boss) { fighter.die(); this.gameState.notifyFighterDead(fighter, boss); }; function BossFactory( gameState, maxX, maxY ) { this.parent = ElementFactory ; this.parent.call( this, gameState, maxX, maxY ) ; } ; __inherit( BossFactory, ElementFactory ) ; BossFactory.prototype._NUM = 2 ; BossFactory.prototype._initFreelist = function() { this.freelist = new BossFreeList(this._NUM, this.gameState); }; BossFactory.prototype._getImage = function( params ) { switch( params.character ) { case 'rumia': return this.gameState.getImage( Game._IMG_ENEMY_RUMIA ) ; case 'chilno': return this.gameState.getImage( Game._IMG_ENEMY_CHILNO ) ; case 'daiyousei': return this.gameState.getImage( Game._IMG_ENEMY_DAIYOUSEI ) ; // TODO: temporal default: return this.gameState.getImage( Game._IMG_ENEMY_MOKOU ) ; } } ; function BossFreeList( num, gameState ) { this.parent = ElementFreeList ; this.parent.call( this, num, gameState ) ; } __inherit( BossFreeList, ElementFreeList ) ; BossFreeList.prototype._generateElement = function( ) { return new Boss( this.gameState, this.gameState.getWidth( ), this.gameState.getHeight( ) ) ; } ; function BossDrawer(elementManager, layer, image) { this.parent = ElementDrawer; this.parent.call(this, elementManager, layer, image); }; __inherit(BossDrawer, ElementDrawer); function BossView(element) { this.parent = ElementView; this.parent.call(this, element); }; __inherit(BossView, ElementView); /** * no rotate. * TODO: no rotate impl should be in parent class? */ BossView.prototype.rotate = function() { }; BossView.prototype.doRotateForViewpoint = function() { return true; }; BossView.prototype.animate = function() { this._initCoordinates(); if(this.element.inVanishing()) { this.a = this._inVanishingEffect(); } else if(this.element.effects && this.element.effects['vanish']) { this.a = this._vanishEffect(this.element.effects['vanish']); } else { this.a = 1.0; } }; /** * TODO: temporal. especially name. */ BossView.prototype._inVanishingEffect = function() { return (this.element._VANISH_COUNT - this.element.vanishingCount + 1) * 0.01; }; /** * TODO: temporal. especially name. */ BossView.prototype._vanishEffect = function(params) { var count = this.element._getCountFromBase(params, -1); if(count >= params['count'] && count < params['count'] + params['length']) { return 1.0 - ((count - params['count']) / params['length']) ; } return 1.0; }; function Boss( gameState, maxX, maxY ) { this.parent = Element ; this.parent.call( this, gameState, maxX, maxY ) ; this.params = null ; this.index = 0 ; this.maxVital = 0 ; this.appearedTalk = null ; this.vanishedTalk = null ; this.character = null ; this.score = null ; this.dead = null ; this.animation = null ; this.spellCard = false ; this.effect = null ; this.escaping = false; this.vanishing = false; this.vanishingCount = 0; /* this.powerItem = powerItem ? powerItem : 0 ; this.lpowerItem = lpowerItem ? lpowerItem : 0 ; this.scoreItem = scoreItem ? scoreItem : 0 ; */ this.shots = [ ] ; this.shotIndices = [ ] ; } __inherit( Boss, Element ) ; Boss.prototype._WIDTH = 128 ; Boss.prototype._HEIGHT = 128 ; Boss.prototype._APPEAR_COUNT = 100 ; Boss.prototype._APPEAR_WAIT_COUNT = 50 ; Boss.prototype._VANISH_COUNT = 100; Boss.prototype._TYPE_RUMIA = 0; Boss.prototype._TYPE_DAIYOUSEI = 1; Boss.prototype._TYPE_CHIRNO = 2; Boss.prototype._ESCAPE_VECTOR = {'r': 0, 'theta': 225, 'ra': 0.1}; __copyParentMethod(Boss, Element, 'init'); Boss.prototype.init = function(params, image) { this.Element_init(params, image); this.params = params.params ; this.index = 0 ; this.maxVital = 0 ; this.appearedTalk = params.appearedTalk ; this.vanishedTalk = params.vanishedTalk ; this.character = params.character ; this.score = params.score ; this.dead = params.dead ; this.animation = params.animation ; // TODO: temporal this.spellCard = false ; this.effect = null ; this.escaping = false; this.vanishing = false; this.vanishingCount = 0; /* this.powerItem = powerItem ? powerItem : 0 ; this.lpowerItem = lpowerItem ? lpowerItem : 0 ; this.scoreItem = scoreItem ? scoreItem : 0 ; */ this.shots.length = 0 ; this.shotIndices.length = 0 ; this._initState( ) ; this._initView(); } ; Boss.prototype._generateView = function() { return new BossView(this); }; Boss.prototype._shot = function( ) { if( this.shots.length == 0 ) return ; if(this.vanishing || this.escaping) return; var offset = this._APPEAR_COUNT + this._APPEAR_WAIT_COUNT ; if( this.count < offset ) return ; for( var i = 0; i < this.shots.length; i++ ) { var count = this.count - offset ; if( this.shots[ i ].baseCount ) count = count % this.shots[ i ].baseCount ; if( count == 0 ) { this.shotIndices[ i ] = 0 ; } if( this.shotIndices[ i ] >= this.shots[ i ].shotCount.length ) { continue ; } if( count >= this.shots[ i ].shotCount[ this.shotIndices[ i ] ] ) { // TODO: temporal this.gameState.notifyEnemyDoShot( this, this.shots[ i ] ) ; this.shotIndices[ i ]++ ; } } } ; // TODO: temporal __copyParentMethod(Boss, Element, 'runStep'); Boss.prototype.runStep = function() { if(this.isFlagSet(this._FLAG_UNHITTABLE) && this.count + 1 >= this._APPEAR_COUNT + this._APPEAR_WAIT_COUNT) { this.clearFlag(this._FLAG_UNHITTABLE); if(this.index == 0) this.gameState.notifyBossBeginTalk(this); else this.gameState.notifyBossBecameActive(this); } this._shot(); this._doEffect(); this.Element_runStep(); // for animation this._checkState(); // TODO: temporal if(this.getXDirection() == 1) { this.indexX = 2; this.indexY = 3; } else if(this.getXDirection() == -1) { this.indexX = 2; this.indexY = 1; } else { this.indexX = 0; if(this.count % 4 == 0) { this.indexY++; if(this.indexY > this.animation) this.indexY = 0; } } if(this.vanishing) this.vanishingCount++; }; /** * TODO: temporal */ Boss.prototype._getCountFromBase = function(params, o) { var o = o ? o : 0; var offset = this._APPEAR_COUNT + this._APPEAR_WAIT_COUNT; return (this.count - offset + o) % params['baseCount']; }; Boss.prototype._doEffect = function() { if(this.effects && this.effects['shockwave'] !== void 0) { // TODO: temporal for(var i = 0; i < this.effects['shockwave'].length; i++) { var params = this.effects['shockwave'][i]; var count = this._getCountFromBase(params); if(count == params['count']) this.gameState.notifyDoEffect(this, 'shockwave', params.params); } } }; /** * TODO: temporal */ Boss.prototype._checkState = function() { if(this.vanishing || this.escaping) return; if(this.vital <= 0) { this.index++; if(this.index >= this.params.length) { this.die(); this.gameState.notifyBossVanished(this); if(this.dead == 'escape') this._beginEscape(); else this._beginVanish(); } else { this.gameState.notifyBossMovedNextStage(this); this._initState(); } } }; Boss.prototype._initState = function( ) { // TODO: temporal this.count = 0 ; // TODO: temporal var shots = this.params[ this.index ].s ; // TODO: temporal this.vectorIndex = 0 ; this.vectors.length = 0 ; for( var i = 0; i < this.params[ this.index ].v.length; i++ ) { this.vectors.push( this.params[ this.index ].v[ i ] ) ; } // this.vectors = this.params[ this.index ].v ; this.vectors.unshift( { 'count': -this._APPEAR_WAIT_COUNT, 'v': { 'r': 0, 'theta': 0, 'w': 0, 'ra': 0, 'wa': 0, 'raa': 0, } } ) ; this.vectors.unshift( { 'count': 0, 'v': { 'r': 0, 'theta': 0, 'w': 0, 'ra': 0, 'wa': 0, 'raa': 0, 'target': { 'x': this.params[ this.index ].x, 'y': this.params[ this.index ].y, 'count': this._APPEAR_COUNT } } } ) ; this.baseVectorCount = this._APPEAR_COUNT + this._APPEAR_WAIT_COUNT ; this._initVector( ) ; this.shots.length = 0; if(shots === void 0) { } else if(shots instanceof Array) { for( var i = 0; i < shots.length; i++ ) this.shots.push( shots[ i ] ) ; } else { shots = [ shots ] ; this.shots.push( shots[ 0 ] ) ; } // TODO: temporal this.shotIndices.length = 0 ; for( var i = 0; i < this.shots.length; i++ ) { this.shotIndices.push( 0 ) ; } this.vital = this.params[ this.index ].vital ; this.maxVital = this.vital ; this.spellCard = this.params[ this.index ].spellCard ; this.effects = this.params[ this.index ].e ; this.setFlag( this._FLAG_UNHITTABLE ) ; this.gameState.notifyBossStageChanged( this ) ; } ; __copyParentMethod(Boss, Element, 'getXDirection'); Boss.prototype.getXDirection = function() { if(this.vector && this.vector.r == 0) return 0; return this.Element_getXDirection(); }; __copyParentMethod(Boss, Element, '_outOfTheField'); Boss.prototype._outOfTheField = function() { if(this.Element_outOfTheField()) this._beInTheField(); return false; }; /** * TODO: temporal function name */ Boss.prototype.outOfTheField = function() { return this.Element_outOfTheField(); }; Boss.prototype._beginEscape = function() { this.escaping = true; this.gravity = null; // TODO: temporal this.vector = this.moveVectorManager.create(this._ESCAPE_VECTOR); // TODO: these parameters should move to EffectFactory. this.gameState.notifyDoEffect(this, 'shockwave', { 'w': 5, 'g': 5, 'a': 0.1, 'b': 20, 'endCount': 100 }); }; Boss.prototype._beginVanish = function() { this.vanishing = true; this.vanishingCount = 0; this.gravity = null; this.vector = null; // TODO: these parameters should move to EffectFactory. this.gameState.notifyDoEffect(this, 'shockwave', { 'w': 5, 'g': 5, 'a': 0.1, 'b': 10, 'endCount': 100 }); this.gameState.effectManager.createBigExplosion(this); // TODO: who manages this logic? Boss? StageState? if(this.dead == 'escape' && this.vanishedTalk) { this.gameState.notifyBeginTalk(); } }; Boss.prototype.inVanishing = function() { return (this.vanishing && this.vanishingCount < this._VANISH_COUNT); }; Boss.prototype.overVanishing = function() { return (this.vanishing && this.vanishingCount >= this._VANISH_COUNT); }; /** * TODO: temporal workaround. */ __copyParentMethod(Boss, Element, '_checkVectorChange'); Boss.prototype._checkVectorChange = function() { if(this.escaping || this.vanishing) return false; return this.Element_checkVectorChange(); }; /** * TODO: temporal logic. */ __copyParentMethod(Boss, Element, 'checkLoss'); Boss.prototype.checkLoss = function() { if(this.escaping) return this.Element_outOfTheField(); if(! this.vanishing) return this.Element_checkLoss(); var tmp = this.state; this.state = this._STATE_ALIVE; var value = this.Element_checkLoss(); this.state = tmp; if(value) return value; return this.overVanishing(); }; // TODO: temporal Boss.prototype.isVanishingOrEscaping = function() { return (this.vanishing || this.escaping); }; // TODO: remove the followings because they complicate the design. // only for reference // TODO: temporal BossManager.prototype.Boss = Boss.prototype; ================================================ FILE: source/Bullet.js ================================================ function BulletManager( gameState, params ) { this.parent = ElementManager ; this.parent.call( this, gameState ) ; this.params = params ; this.laserCounts = [0, 0]; // TODO: temporal } ; __inherit( BulletManager, ElementManager ) ; BulletManager.prototype._MAX_NUM = 500; BulletManager.prototype._initMaxNum = function() { return this._MAX_NUM; }; BulletManager.prototype._initFactory = function( ) { this.factory = new BulletFactory( this.gameState, this.gameState.getWidth( ), this.gameState.getHeight( ) ) ; } ; BulletManager.prototype.initDrawer = function(layer, image) { this.drawer = new BulletDrawer(this, layer, this.gameState.getImage(Game._IMG_SHOT)); }; __copyParentMethod(BulletManager, ElementManager, 'reset'); BulletManager.prototype.reset = function() { this.ElementManager_reset(); for(var i = 0; i < this.laserCounts.length; i++) { this.laserCounts[i] = 0; } }; /** * TODO: temporal. to make the logic straightforward. */ BulletManager.prototype.create = function( fighter ) { var params = this.params[ fighter.characterIndex ][ fighter.getBulletIndex( ) ][ fighter.getPowerLevel( ) ] ; var flag = false ; var count = 0 ; var id = fighter.getID(); for( var i = 0; i < params.length; i++ ) { // TODO: temporal if( ( params[ i ].laser || params[ i ].homing ) && params[ i ].nextCount ) { if( this.count < this.laserCounts[id] + params[ i ].nextCount ) { continue ; } flag = true ; if( this.count > count ) count = this.count ; } this.addElement( this.factory.create( params[ i ], fighter ) ) ; } if( flag ) this.laserCounts[id] = count ; } ; __copyParentMethod(BulletManager, ElementManager, 'checkCollisionWith'); BulletManager.prototype.checkCollisionWithEnemies = function(enemies) { var self = this; for(var i = 0; i < enemies.length; i++) { this.ElementManager_checkCollisionWith(null, enemies[i], this); } }; BulletManager.prototype.notifyCollision = function(id, enemy, bullet) { // TODO: temporal if(bullet._ID !== this._ID_LASER) bullet.die(); // TODO: temporal enemy.vital -= bullet.power; this.gameState.notifyBulletHit(bullet, enemy); if(enemy.vital <= 0) { this.gameState.notifyEnemyVanished(bullet, enemy); enemy.die(); } }; /** * TODO: temporal */ __copyParentMethod(BulletManager, ElementManager, 'checkCollisionWith2'); BulletManager.prototype.checkCollisionWithBoss = function(boss) { if(boss.isFlagSet(boss._FLAG_UNHITTABLE)) return; var self = this; this.ElementManager_checkCollisionWith2(null, boss, this); }; BulletManager.prototype.notifyCollision2 = function(id, boss, bullet) { // TODO: temporal if(bullet._ID !== this._ID_LASER) bullet.die(); boss.vital -= bullet.power; this.gameState.notifyBulletHit(bullet, boss); }; function BulletFactory( gameState, maxX, maxY ) { this.parent = ElementFactory ; this.homingFreelist = null ; this.laserFreelist = null ; this.parent.call( this, gameState, maxX, maxY ) ; this.types = __bulletTypes ; // TODO: temporal this.image = null; // TODO: temporal } __inherit( BulletFactory, ElementFactory ) ; BulletFactory.prototype._BULLET_NUM = 100 ; BulletFactory.prototype._HOMING_NUM = 100 ; BulletFactory.prototype._LASER_NUM = 10 ; BulletFactory.prototype._initFreelist = function() { this.freelist = new BulletFreeList(this._BULLET_NUM, this.gameState); this.homingFreelist = new HomingFreeList(this._HOMING_NUM, this.gameState); this.laserFreelist = new LaserFreeList( this._LASER_NUM, this.gameState); }; BulletFactory.prototype.create = function( params, fighter ) { if( params.laser ) { var laser = this.laserFreelist.get( ) ; laser.init( params, this._getImage( params ), fighter.getOption(params.option), // TODO: temporal this.types[ 3 ]) ; // TODO: temporal return laser ; } if( params.homing ) { var homing = this.homingFreelist.get( ) ; homing.init( params, this._getImage( params ), fighter.getOption(params.option), // TODO: temporal this.types[ 2 ]) ; // TODO: temporal return homing ; } var key = fighter.characterIndex ; var bullet = this.freelist.get( ) ; bullet.init( params, this._getImage( params ), this.types[ key ], fighter ) ; return bullet ; } ; BulletFactory.prototype.free = function( bullet ) { switch(bullet._ID) { case this.BulletManager._ID_BULLET: this.freelist.free( bullet ) ; return; case this.BulletManager._ID_LASER: this.laserFreelist.free( bullet ) ; return; case this.BulletManager._ID_HOMING: this.homingFreelist.free( bullet ) ; return; default: // throw exception? } }; /** * TODO: temporal */ BulletFactory.prototype._getImage = function(params) { if(this.image === null) this.image = this.gameState.getImage(Game._IMG_SHOT); return this.image; }; function BulletFreeList( num, gameState ) { this.parent = ElementFreeList ; this.parent.call( this, num, gameState ) ; } __inherit( BulletFreeList, ElementFreeList ) ; BulletFreeList.prototype._generateElement = function( ) { return new Bullet( this.gameState, this.gameState.getWidth( ), this.gameState.getHeight( ) ) ; } ; function BulletDrawer(elementManager, layer, image) { this.parent = ElementDrawer; this.parent.call(this, elementManager, layer, image); }; __inherit(BulletDrawer, ElementDrawer); function BulletView(element) { this.parent = ElementView; this.parent.call(this, element); this.a = 0.8; }; __inherit(BulletView, ElementView); function Bullet( gameState, maxX, maxY ) { this.parent = Element ; this.parent.call( this, gameState, maxX, maxY ) ; this.rotate = null ; this.power = null ; this.fighter = null; } __inherit( Bullet, Element ) ; Bullet.prototype._WIDTH = 16 ; Bullet.prototype._HEIGHT = 32 ; /** * TODO: temporal. params2 should be renamed. */ __copyParentMethod(Bullet, Element, 'init'); Bullet.prototype.init = function(params, image, params2, fighter) { this.fighter = fighter; this.Element_init(params, image); this.setX(this.getX() + this.fighter.getX()); this.setY(this.getY() + this.fighter.getY()); // TODO: temporal. Wanna combine this logic with parent init( ). this.indexX = params2.indexX !== void 0 ? params2.indexX : 0; this.indexY = params2.indexY !== void 0 ? params2.indexY : 0; this.width = params2.width !== void 0 ? params2.width : 0; this.height = params2.height !== void 0 ? params2.height : 0; this.collisionWidth = params2.collisionWidth !== void 0 ? params2.collisionWidth : 0; this.collisionHeight = params2.collisionHeight !== void 0 ? params2.collisionHeight : 0; this.power = params.power !== void 0 ? params.power : 1; this.rotate = params2.rotate !== void 0 ? params2.rotate : 0; this._initView(); }; Bullet.prototype._generateView = function() { return new BulletView(this); }; /** * TODO: which is faster save&restore or doing by my hand? */ Bullet.prototype.display = function( surface ) { // surface.save( ) ; surface.globalAlpha = 0.8 ; this.parent.prototype.display.call( this, surface, true ) ; surface.globalAlpha = 1.0 ; // surface.restore( ) ; } ; function LaserFreeList( num, gameState ) { this.parent = ElementFreeList ; this.parent.call( this, num, gameState ) ; } __inherit( LaserFreeList, ElementFreeList ) ; LaserFreeList.prototype._generateElement = function( ) { return new Laser( this.gameState, this.gameState.getWidth( ), this.gameState.getHeight( ) ) ; } ; /** * TODO: consider the option to use add blend. */ function LaserView(element) { this.parent = ElementView; this.parent.call(this, element); }; __inherit(LaserView, ElementView); LaserView.prototype._getElementX = function() { return this.element.option.getCenterX() + this.element.getX(); }; LaserView.prototype._getElementY = function() { return this.element.option.getCenterY() + this.element.getY(); }; LaserView.prototype._getElementZ = function() { return this.element.option.getZ(); }; /** * assumes that image height is 256 and master image size is 256. * TODO: temporal */ __copyParentMethod(LaserView, ElementView, '_initVertices'); LaserView.prototype._initVertices = function() { this.ElementView_initVertices(); this.vertices[1] = 0; this.vertices[4] = 0; this.vertices[7] *= 4; this.vertices[10] *= 4; }; /** * assumes that image height is 256 and master image size is 256. * TODO: temporal */ __copyParentMethod(LaserView, ElementView, '_initCoordinates'); LaserView.prototype._initCoordinates = function() { this.ElementView_initCoordinates(); this.coordinates[1] *= 2; this.coordinates[3] *= 2; }; /** * TODO: should be in Laser? */ LaserView.prototype.animate = function() { if(this.element.count < this.element.waitCount || this.element.count + 10 > this.element.keepAlive ) this.a = 0.2; else this.a = 0.8; }; /** * TODO: temporal */ function Laser( gameState, maxX, maxY ) { this.parent = Element ; this.parent.call( this, gameState, maxX, maxY ) ; this.rotate = null ; this.option = null ; this.power = null ; } __inherit( Laser, Element ) ; Laser.prototype._WIDTH = 16 ; Laser.prototype._HEIGHT = 16 ; __copyParentMethod(Laser, Element, 'init'); Laser.prototype.init = function(params, image, option, params2) { this.Element_init(params, image); this.option = option; // TODO: temporal. Wanna combine this logic with parent init( ). this.keepAlive = this._getValueOrDefaultValue(params.keep, 0); this.indexX = params2.indexX !== void 0 ? params2.indexX : 0; this.indexY = params2.indexY !== void 0 ? params2.indexY : 0; this.width = params2.width !== void 0 ? params2.width : 0; this.height = params2.height !== void 0 ? params2.height : 0; this.collisionWidth = params2.collisionWidth !== void 0 ? params2.collisionWidth : 0; this.collisionHeight = params2.collisionHeight !== void 0 ? params2.collisionHeight : 0; this.power = params.power !== void 0 ? params.power : 1; this.waitCount = params.waitCount !== void 0 ? params.waitCount : 50; this.rotate = params2.rotate !== void 0 ? params2.rotate : 0; this._initView(); }; Laser.prototype._generateView = function() { return new LaserView(this); }; /** * TODO: temporal */ Laser.prototype.display = function( surface ) { var x = Math.round( this.option.getCenterX( ) + this.getLeftX( ) ) ; var y = Math.round( this.option.getCenterY( ) + this.getCenterY( ) ) ; // surface.save( ) ; if( this.count < this.waitCount || this.count + 10 > this.keepAlive ) surface.globalAlpha = 0.2 ; else surface.globalAlpha = 0.6 ; while( y > 0 ) { surface.drawImage( this.image, this.width * this.indexX, this.height * this.indexY, this.width, this.height, x, y, this.width, -this.height ) ; y -= this.height ; } surface.globalAlpha = 1.0 ; // surface.restore( ) ; } ; /** * TODO: temporal */ Laser.prototype.checkCollision = function( enemy ) { if( this.count < this.waitCount ) return false ; // TODO: temporal if( this.count % 3 != 0 ) return false ; // TODO: temporal if( this.vector.theta != 270 ) return false ; if( enemy.getCollisionUpY( ) > this.y + this.option.getCenterY( ) ) return false ; if( enemy.getCollisionRightX( ) < this.x + this.option.getCenterX( ) - this.width/2 ) return false ; if( enemy.getCollisionLeftX( ) > this.x + this.option.getCenterX( ) + this.width/2 ) return false ; return true ; } ; /** * TODO: temporal */ Laser.prototype.checkLoss = function( ) { if( this.isDead( ) ) return true ; if( this.keepAlive && this.count >= this.keepAlive ) return true ; return false ; } ; function HomingFreeList( num, gameState ) { this.parent = ElementFreeList ; this.parent.call( this, num, gameState ) ; } __inherit( HomingFreeList, ElementFreeList ) ; HomingFreeList.prototype._generateElement = function( ) { return new Homing( this.gameState, this.gameState.getWidth( ), this.gameState.getHeight( ) ) ; } ; /** * TODO: temporal */ function Homing( gameState, maxX, maxY ) { this.parent = Element ; this.parent.call( this, gameState, maxX, maxY ) ; this.rotate = null ; this.option = null ; this.power = null ; this.target = null ; this.targetIsDead = false ; } __inherit( Homing, Element ) ; Homing.prototype.Math = Math; Homing.prototype._SEARCH_SPAN = 1000; Homing.prototype._HOMING_SPAN = 2; Homing.prototype._HOMING_COUNT = 50; Homing.prototype._HOMING_LAG = 5; Homing.prototype._HOMING_REACH = 10; Homing.prototype._OUT_RANGE = 30; __copyParentMethod(Homing, Element, 'init'); Homing.prototype.init = function(params, image, option, params2) { this.Element_init(params, image); this.option = option; this.setX(this.getX() + option.getCenterX()); this.setY(this.getY() + option.getCenterY()); // TODO: temporal. Wanna combine this logic with parent init( ). this.keepAlive = this._getValueOrDefaultValue(params.keep, 0); this.indexX = params2.indexX !== void 0 ? params2.indexX : 0; this.indexY = params2.indexY !== void 0 ? params2.indexY : 0; this.width = params2.width !== void 0 ? params2.width : 0; this.height = params2.height !== void 0 ? params2.height : 0; this.collisionWidth = params2.collisionWidth !== void 0 ? params2.collisionWidth : 0; this.collisionHeight = params2.collisionHeight !== void 0 ? params2.collisionHeight : 0; this.power = params.power !== void 0 ? params.power : 1; this.waitCount = params.waitCount !== void 0 ? params.waitCount : 50; this.rotate = params2.rotate !== void 0 ? params2.rotate : false; this.target = null; this.targetIsDead = false; this._initView(); }; /** * unnecessary to have Homing special view. */ Homing.prototype._generateView = function() { return new BulletView(this); }; Homing.prototype.display = function( surface ) { // surface.save( ) ; surface.globalAlpha = 0.8 ; this.parent.prototype.display.call( this, surface, true ) ; surface.globalAlpha = 1.0 ; // surface.restore( ) ; } ; /** * TODO: temporal */ __copyParentMethod(Homing, Element, 'runStep'); Homing.prototype.runStep = function() { if(this.count % this._SEARCH_SPAN == 0) this._searchNearestEnemy(); if(this.count % this._HOMING_SPAN == 0) this._calculateHomingPoint(); this.Element_runStep(this); }; /** * TODO: temporal */ Homing.prototype._searchNearestEnemy = function( ) { // TODO: temporal if( this.targetIsDead) return ; var min = 1000 * 1000 ; // TODO: temporary var nearest = null ; for( var i = 0; i < this.gameState.enemyManager.elements.length; i++ ) { var e = this.gameState.enemyManager.elements[ i ] ; var d = this.Math.pow( this.getX( ) - e.getX( ), 2 ) + this.Math.pow( this.getY( ) - e.getY( ), 2 ) ; if( d < min ) { min = d ; nearest = e ; } } if( this.gameState.bossManager.existBoss( ) ) { var b = this.gameState.bossManager.getBoss( ) ; if(! b.vanishing && ! b.escaping) { var d = this.Math.pow( this.getX( ) - b.getX( ), 2 ) + this.Math.pow( this.getY( ) - b.getY( ), 2 ) ; if( d < min ) { min = d ; nearest = b ; } } } // TODO: temporary if( nearest ) this.target = nearest ; } ; /** * TODO: temporal */ Homing.prototype._calculateHomingPoint = function( ) { if( ! this.target ) return ; // TODO: how handles the case if target is used for the other alive element soon again? if(this.target.isDead() || this.target.isFlagSet(this._FLAG_UNHITTABLE) || this.target.isVanishingOrEscaping()) { this.targetIsDead = true ; return ; } var ax = this.target.getX( ) - this.getX( ) ; var ay = this.target.getY( ) - this.getY( ) ; var t = this._calculateTheta( this.Math.atan2( ay, ax ) ) ; /* var diff = t - this.vector.theta ; if( Math.cos( this._calculateRadian( diff ) ) > Math.cos( this._calculateRadian( Homing._HOMING_REACH ) ) ) { this.vector.theta = t ; } else if( Math.sin( this._calculateRadian( diff ) ) > 0 ) { this.vector.theta += Homing._HOMING_REACH ; } else if( Math.sin( this._calculateRadian( diff ) ) < 0 ) { this.vector.theta -= Homing._HOMING_REACH ; } else { */ this.vector.theta = t ; /* } */ return ; } ; Homing.prototype._outOfTheField = function( ) { if( this.getX( ) < -this._OUT_RANGE || this.getX( ) > this.maxX + this._OUT_RANGE || this.getY( ) < -this._OUT_RANGE || this.getY( ) > this.maxY + this._OUT_RANGE ) return true ; return false ; } ; // TODO: remove the followings because they complicate the design. BulletManager.prototype._ID_BULLET = 0; BulletManager.prototype._ID_LASER = 1; BulletManager.prototype._ID_HOMING = 2; BulletFactory.prototype.BulletManager = BulletManager.prototype; Bullet.prototype._ID = BulletManager.prototype._ID_BULLET; Laser.prototype._ID = BulletManager.prototype._ID_LASER; Homing.prototype._ID = BulletManager.prototype._ID_HOMING; ================================================ FILE: source/CharacterSelectState.js ================================================ function CharacterSelectState( game ) { this.parent = GameState ; this.parent.call( this, game ) ; this.elements = [ ] ; this.index = 0 ; this.count = 0 ; } __inherit( CharacterSelectState, GameState ) ; CharacterSelectState._APPEAR_SPAN = 10 ; CharacterSelectState.prototype.init = function( ) { this.count = 0 ; // TODO: magic number for( var i = 0; i < 2; i++ ) { this.elements[ i ] = { } ; this.elements[ i ].width = 400 ; this.elements[ i ].height = 600 ; } this.index = 0 ; } ; CharacterSelectState.prototype.runStep = function( ) { this.count++ ; } ; CharacterSelectState.prototype.updateDisplay = function( surface ) { this.game.clear( surface ) ; this._displayBG( surface ) ; this._displayMessage( surface ) ; this._displayCharacters( surface ) ; } ; /** * TODO: temporal */ CharacterSelectState.prototype._displayBG = function( surface ) { surface.save( ) ; surface.fillStyle = 'rgb( 0, 0, 0 )' ; surface.fillRect( 0, 0, this.getWidth( ), this.getHeight( ) ) ; surface.fillStyle = 'rgb( 255, 255, 255 )' ; surface.fillRect( 0, 50, this.getWidth( ), this.getHeight( ) - 100 ) ; surface.globalAlpha = 0.05 ; surface.drawImage( this.game.getImage( Game._IMG_TITLE_BG ), 0, 0, TitleState._WIDTH, TitleState._HEIGHT, 0, 0, this.getWidth( ), this.getHeight( ) ) ; surface.restore( ) ; } ; CharacterSelectState.prototype._displayMessage = function( surface ) { surface.save( ) ; surface.font = "30px 'Comic Sans MS'" ; surface.textAlign = 'center' ; surface.textBaseAlign = 'middle' ; surface.fillStyle = 'rgb( 255, 255, 255 )' ; surface.fillText( 'Character Select', this.getWidth( ) / 2, 35 ) ; surface.restore( ) ; } ; CharacterSelectState.prototype._displayCharacters = function( surface ) { surface.save( ) ; if( this.index == 0 ) { surface.globalAlpha = 0.6 ; this._displayMarisa( surface ) ; surface.globalAlpha = 1.0 ; this._displayReimu( surface ) ; } else { surface.globalAlpha = 0.6 ; this._displayReimu( surface ) ; surface.globalAlpha = 1.0 ; this._displayMarisa( surface ) ; } surface.restore( ) ; } ; CharacterSelectState.prototype._displayReimu = function( surface ) { surface.save( ) ; var target = 0 ; var from = this.getWidth( ) ; var w = from - ( from - target ) * this.count / CharacterSelectState._APPEAR_SPAN ; if( w < target ) w = target ; surface.drawImage( this.game.getImage( Game._IMG_STAND_REIMU ), w, 0 ) ; surface.restore( ) ; } ; CharacterSelectState.prototype._displayMarisa = function( surface ) { surface.save( ) ; var target = this.getWidth( ) - this.elements[ 1 ].width ; var from = -this.elements[ 1 ].width ; var w = from - ( from - target ) * this.count / CharacterSelectState._APPEAR_SPAN ; if( w > target ) w = target ; surface.drawImage( this.game.getImage( Game._IMG_STAND_MARISA ), w, 0 ) ; surface.restore( ) ; } ; CharacterSelectState.prototype.handleKeyDown = function( e ) { // TODO: temporal if( this.count < CharacterSelectState._APPEAR_SPAN ) return ; switch( e.keyCode ) { case 37: // left this.index++ ; if( this.index > 1 ) this.index = 0 ; this._soundEffect( Game._SE_SELECT ) ; break ; case 39: // right this.index-- ; if( this.index < 0 ) this.index = 1 ; this._soundEffect( Game._SE_SELECT ) ; break ; case 88: // x this.game.notifyLoadingConclusion( this.index ) ; // TODO: temporal break ; case 90: // z this.game.notifyCharacterSelectConclusion( this.index ) ; break ; } ; } ; CharacterSelectState.prototype.handleKeyUp = function( e ) { } ; ================================================ FILE: source/Effect.js ================================================ /** * TODO: optimize this file. * some codes and parameters are no longer used * because of the design change. */ /** * Effect represents an element which just shows on a screen, * and not affect any other elements. */ function EffectManager(gameState) { this.parent = ElementManager; this.parent.call(this, gameState); }; __inherit(EffectManager, ElementManager); // only for reference EffectManager.prototype.Layer = Layer; EffectManager.prototype.Math = Math; EffectManager.prototype._MAX_NUM = 200; // TODO: for each so far EffectManager.prototype._initMaxNum = function() { return this._MAX_NUM; }; EffectManager.prototype._initFactory = function() { this.factory = new EffectFactory(this.gameState, this.gameState.getWidth(), this.gameState.getHeight()); }; /** * TODO: consider the design. To use drawers is easy to handle, * but not smart. To extend Drawer could be smarter and * performance could be better. */ EffectManager.prototype.initDrawer = function(layer, image) { this.drawers = []; this.drawers.push(this._generateShockWaveDrawer(layer)); this.drawers.push(this._generateGrazeDrawer(layer)); this.drawers.push(this._generateExplosionDrawer(layer)); this.drawers.push(this._generateDamageDrawer(layer)); this.drawers.push(this._generateBigShockWaveDrawer(layer)); this.drawers.push(this._generateBigExplosionDrawer(layer)); }; EffectManager.prototype._generateShockWaveDrawer = function(layer) { return new ShockWaveDrawer(this, layer, this._generateShockWaveImage()); }; EffectManager.prototype._generateGrazeDrawer = function(layer) { return new GrazeDrawer(this, layer, this._generateGrazeImage()); }; EffectManager.prototype._generateExplosionDrawer = function(layer) { return new ExplosionDrawer(this, layer, this._generateExplosionImage()); }; EffectManager.prototype._generateBigShockWaveDrawer = function(layer) { return new BigShockWaveDrawer(this, layer, this._generateBigShockWaveImage()); }; EffectManager.prototype._generateBigExplosionDrawer = function(layer) { return new BigExplosionDrawer(this, layer, this._generateBigExplosionImage()); }; EffectManager.prototype._generateDamageDrawer = function(layer) { return new DamageDrawer(this, layer, this._generateDamageImage()); }; /** * create ShockWaveEffect. * TODO: rename or combine with other create methods. */ EffectManager.prototype.create = function(element, type, params) { this.addElement(this.factory.create(element, type, params)); }; /** * TODO: temporal. combine with create()? */ EffectManager.prototype.createGraze = function(element, params) { this.addElement(this.factory.createGraze(element, params)); }; /** * TODO: temporal. combine with create()? */ EffectManager.prototype.createDamageEffect = function(enemy) { this.addElement(this.factory.createDamageEffect(enemy)); }; /** * TODO: temporal. combine with create()? */ EffectManager.prototype.createExplosion = function(enemy) { this.addElement(this.factory.createExplosion(enemy)); }; /** * TODO: temporal. combine with create()? */ EffectManager.prototype.createBigShockWave = function(enemy, type, params) { this.addElement(this.factory.createBigShockWave(enemy, type, params)); }; /** * TODO: temporal. combine with create()? */ EffectManager.prototype.createBigExplosion = function(enemy) { this.addElement(this.factory.createBigExplosion(enemy)); }; /** * TODO: should move into ShockWave? */ EffectManager.prototype._generateShockWaveImage = function() { var cvs = document.createElement('canvas'); cvs.width = this.Layer.calculateSquareValue(this.ShockWaveEffect._WIDTH); cvs.height = this.Layer.calculateSquareValue( this.ShockWaveEffect._HEIGHT*this.ShockWaveEffect._END_COUNT); var ctx = cvs.getContext('2d'); var w = this.ShockWaveEffect._WIDTH; var h = this.ShockWaveEffect._HEIGHT; for(var i = 0; i < this.ShockWaveEffect._END_COUNT; i++) { var x = w/2; var y = h*i + h/2; var r = this.ShockWaveEffect._SPEED * i; var s = 1 - this.ShockWaveEffect._GRADATION/(this.ShockWaveEffect._SPEED*i); if(r <= 1) r = 1; if(s < 0) s = 0.0; ctx.beginPath(); var g = ctx.createRadialGradient(x, y, 0, x, y, r); g.addColorStop(s, 'rgba(255, 255, 255, 0.0)'); g.addColorStop(1.00, 'rgba(255, 255, 255, 1.0)'); ctx.fillStyle = g; ctx.arc(x, y, r, 0, this.Math.PI * 2); ctx.fill(); } return cvs; }; /** * TODO: should move into Graze? */ EffectManager.prototype._generateGrazeImage = function() { var cvs = document.createElement('canvas'); cvs.width = this.Layer.calculateSquareValue(this.GrazeEffect._SIZE); cvs.height = this.Layer.calculateSquareValue(this.GrazeEffect._SIZE); var ctx = cvs.getContext('2d'); var w = this.GrazeEffect._SIZE; var h = this.GrazeEffect._SIZE; ctx.fillStyle = 'rgb(255, 255, 255)'; ctx.fillRect(0, 0, w, h); return cvs; }; /** * TODO: should move into Explosion? */ EffectManager.prototype._generateExplosionImage = function() { var cvs = document.createElement('canvas'); cvs.width = this.Layer.calculateSquareValue(this.ExplosionEffect._WIDTH); cvs.height = this.Layer.calculateSquareValue( this.ExplosionEffect._HEIGHT*this.ExplosionEffect._END_COUNT); var ctx = cvs.getContext('2d'); var w = this.ExplosionEffect._WIDTH; var h = this.ExplosionEffect._HEIGHT; for(var i = 0; i < this.ExplosionEffect._END_COUNT; i++) { var x = w/2; var y = h*i + h/2; var r = w/2 * i/this.ExplosionEffect._END_COUNT - 2; if(r <= 1) r = 1; ctx.beginPath(); ctx.fillStyle = 'rgb(255, 255, 255)'; ctx.globalAlpha = 0.5; ctx.arc(x, y, r, 0, this.Math.PI * 2); ctx.fill(); ctx.beginPath(); ctx.strokeStyle = 'rgb(255, 255, 255)'; ctx.globalAlpha = 1; ctx.lineWidth = 4; ctx.arc(x, y, r, 0, this.Math.PI * 2); ctx.stroke(); } return cvs; }; /** * TODO: should move into DamageEffect? */ EffectManager.prototype._generateDamageImage = function() { var cvs = document.createElement('canvas'); cvs.width = this.Layer.calculateSquareValue(this.DamageEffect._WIDTH); cvs.height = this.Layer.calculateSquareValue(this.DamageEffect._HEIGHT); var ctx = cvs.getContext('2d'); var w = this.DamageEffect._WIDTH; var h = this.DamageEffect._HEIGHT; var x = w/2; var y = h/2; var r = w/2-4; ctx.beginPath(); ctx.fillStyle = 'rgb(255, 255, 255)'; ctx.globalAlpha = 0.5; ctx.arc(x, y, r, 0, this.Math.PI * 2); ctx.fill(); return cvs; }; /** * TODO: should move into BigShockWave? * TODO: can share the logic with _generateShockWaveImage()? */ EffectManager.prototype._generateBigShockWaveImage = function() { var cvs = document.createElement('canvas'); cvs.width = this.Layer.calculateSquareValue(this.BigShockWaveEffect._WIDTH); cvs.height = this.Layer.calculateSquareValue(this.BigShockWaveEffect._HEIGHT); var ctx = cvs.getContext('2d'); var w = this.BigShockWaveEffect._WIDTH; var h = this.BigShockWaveEffect._HEIGHT; var x = w/2; var y = h/2; var r = w/2; // TODO: remove magic numbers. var s = 1 - (5*4)/(10*10); if(r <= 1) r = 1; if(s < 0) s = 0.0; ctx.beginPath(); var g = ctx.createRadialGradient(x, y, 0, x, y, r); // TODO: bad to get params from other class. g.addColorStop(s, 'rgba(255, 255, 255, 0.0)'); g.addColorStop(1.00, 'rgba(255, 255, 255, 1.0)'); ctx.fillStyle = g; ctx.arc(x, y, r, 0, this.Math.PI * 2); ctx.fill(); return cvs; }; /** * TODO: should move into BigExplosion? */ EffectManager.prototype._generateBigExplosionImage = function() { var cvs = document.createElement('canvas'); cvs.width = this.Layer.calculateSquareValue(this.BigExplosionEffect._WIDTH); cvs.height = this.Layer.calculateSquareValue(this.BigExplosionEffect._HEIGHT); var ctx = cvs.getContext('2d'); var w = this.BigExplosionEffect._WIDTH; var h = this.BigExplosionEffect._HEIGHT; var x = w/2; var y = h/2; var r = w/2 - 2; ctx.beginPath(); ctx.fillStyle = 'rgb(255, 255, 255)'; ctx.globalAlpha = 0.5; ctx.arc(x, y, r, 0, this.Math.PI * 2); ctx.fill(); ctx.beginPath(); ctx.strokeStyle = 'rgb(255, 255, 255)'; ctx.globalAlpha = 1; ctx.lineWidth = 4; ctx.arc(x, y, r, 0, this.Math.PI * 2); ctx.stroke(); return cvs; }; EffectManager.prototype.draw = function(layer) { for(var i = 0; i < this.drawers.length; i++) { this.drawers[i].draw(layer); } }; function EffectFactory(gameState, maxX, maxY) { this.parent = ElementFactory; this.grazeFreelist = null; this.damageFreelist = null; this.explosionFreelist = null; this.bShockWaveFreelist = null; this.bExplosionFreelist = null; this.parent.call(this, gameState, maxX, maxY); this.image = null; } ; __inherit(EffectFactory, ElementFactory); EffectFactory.prototype._SHOCKWAVE_NUM = 200 ; EffectFactory.prototype._GRAZE_NUM = 200 ; EffectFactory.prototype._DAMAGE_NUM = 200; EffectFactory.prototype._EXPLOSION_NUM = 200; EffectFactory.prototype._BIG_SHOCKWAVE_NUM = 10; EffectFactory.prototype._BIG_EXPLOSION_NUM = 10; // TODO: temporal EffectFactory.prototype._PARAMS = [ {'w': 4, 'g': 5, 'a': 0.1, 'b': 10, 'endCount': 10, 'default': true}, {'x': 0, 'y': 0} ]; EffectFactory.prototype._initFreelist = function() { this.freelist = new ShockWaveEffectFreeList(this._SHOCKWAVE_NUM, this.gameState); this.grazeFreelist = new GrazeEffectFreeList(this._GRAZE_NUM, this.gameState); this.damageFreelist = new DamageEffectFreeList(this._DAMAGE_NUM, this.gameState); this.explosionFreelist = new ExplosionEffectFreeList( this._EXPLOSION_NUM, this.gameState); this.bShockWaveFreelist = new BigShockWaveEffectFreeList( this._BIG_SHOCKWAVE_NUM, this.gameState); this.bExplosionFreelist = new BigExplosionEffectFreeList( this._BIG_EXPLOSION_NUM, this.gameState); }; /** * */ EffectFactory.prototype.create = function( element, type, params ) { // TODO: temporal if( ! params ) params = this._PARAMS[0]; params.x = element.getX( ) ; params.y = element.getY( ) ; var effect = this.freelist.get( ) ; effect.init( params, this._getImage( params ), element ) ; return effect ; } ; /** * TODO: temporal. combine this method with create( )? */ EffectFactory.prototype.createGraze = function(fighter, bullet) { params = this._PARAMS[1]; params.x = fighter.getX(); params.y = fighter.getY(); var effect = this.grazeFreelist.get(); effect.init(params, this._getImage(params), fighter, bullet); return effect; }; /** * TODO: temporal. combine this method with create( )? */ EffectFactory.prototype.createDamageEffect = function(enemy) { var effect = this.damageFreelist.get(); effect.init(enemy, this.gameState.getImage(Game._IMG_DAMAGE), enemy); return effect; }; /** * TODO: temporal. combine this method with create( )? */ EffectFactory.prototype.createExplosion = function(enemy) { var effect = this.explosionFreelist.get(); effect.init(enemy, this.gameState.getImage(Game._IMG_VANISHED), enemy); return effect; }; /** * TODO: temporal. combine this method with create( )? */ EffectFactory.prototype.createBigShockWave = function(element, type, params) { params.x = element.getX(); params.y = element.getY(); var effect = this.bShockWaveFreelist.get(); effect.init(params, this._getImage(params), element); return effect; }; /** * TODO: temporal. combine this method with create( )? */ EffectFactory.prototype.createBigExplosion = function(enemy) { var effect = this.bExplosionFreelist.get(); effect.init(enemy, this.gameState.getImage(Game._IMG_VANISHED), enemy); return effect; }; EffectFactory.prototype.free = function(element) { switch(element._ID) { case this.EffectManager._ID_GRAZE: this.grazeFreelist.free(element); return; case this.EffectManager._ID_DAMAGE: this.damageFreelist.free(element); return; case this.EffectManager._ID_EXPLOSION: this.explosionFreelist.free(element); return; case this.EffectManager._ID_BIG_SHOCKWAVE: this.bShockWaveFreelist.free(element); return; case this.EffectManager._ID_BIG_EXPLOSION: this.bExplosionFreelist.free(element); return; default: // this.EffectManager._ID_SHOCKWAVE: this.freelist.free(element); return; } }; /** * TODO: temporal */ EffectFactory.prototype._getImage = function(params) { if(this.image === null) this.image = this.gameState.getImage(Game._IMG_SHOCK_WAVE); return this.image; }; function ShockWaveEffectFreeList( num, gameState ) { this.parent = ElementFreeList ; this.parent.call( this, num, gameState ) ; } __inherit( ShockWaveEffectFreeList, ElementFreeList ) ; ShockWaveEffectFreeList.prototype._generateElement = function( ) { return new ShockWaveEffect( this.gameState, this.gameState.getWidth( ), this.gameState.getHeight( ) ) ; } ; function ShockWaveDrawer(elementManager, layer, image) { this.parent = ElementDrawer; this.parent.call(this, elementManager, layer, image); }; __inherit(ShockWaveDrawer, ElementDrawer); ShockWaveDrawer.prototype._doPour = function(e) { return (e._ID === this.elementManager._ID_SHOCKWAVE); }; function ShockWaveView(element) { this.parent = ElementView; this.parent.call(this, element); this.a = 0.1; }; __inherit(ShockWaveView, ElementView); ShockWaveView.prototype.animate = function() { this._initCoordinates(); }; ShockWaveView.prototype.rotate = function() { }; ShockWaveView.prototype.doRotateForViewpoint = function() { return true; }; /** * This class is for small shockwave like the one * it shows when enemy is destroyed. */ function ShockWaveEffect( gameState, maxX, maxY ) { this.parent = Element ; this.parent.call( this, gameState, maxX, maxY ) ; this.element = null ; this.w = null ; this.g = null ; this.a = null ; this.b = null ; this.default = null; this.endCount = null ; this.preCanvas = this._PRE_CANVAS; } __inherit( ShockWaveEffect, Element ) ; // only for reference ShockWaveEffect.prototype.Math = Math; ShockWaveEffect.prototype._WIDTH = 200; ShockWaveEffect.prototype._HEIGHT = 200; ShockWaveEffect.prototype._END_COUNT = 10; ShockWaveEffect.prototype._GRADATION = 20; ShockWaveEffect.prototype._SPEED = 10; ShockWaveEffect.prototype._PRE_CANVAS = []; /* temporal */ ShockWaveEffect.prototype._INNER_COLOR = 'rgba(255, 255, 255, 0.0)'; ShockWaveEffect.prototype._OUTER_COLORS = [ 'rgba(255, 255, 255, 0.0)', 'rgba(255, 255, 255, 0.1)', 'rgba(255, 255, 255, 0.2)', 'rgba(255, 255, 255, 0.3)', 'rgba(255, 255, 255, 0.4)', 'rgba(255, 255, 255, 0.5)', 'rgba(255, 255, 255, 0.6)', 'rgba(255, 255, 255, 0.7)', 'rgba(255, 255, 255, 0.8)', 'rgba(255, 255, 255, 0.9)', 'rgba(255, 255, 255, 1.0)', ]; __copyParentMethod(ShockWaveEffect, Element, 'init'); ShockWaveEffect.prototype.init = function(params, image, element) { this.Element_init(params, image); this.element = element; this.width = this._WIDTH; this.height = this._HEIGHT; this.w = params.w; this.g = params.g; this.a = params.a; this.b = params.b; this.default = params.default; this.endCount = this._calculateEndCount(params.endCount); this._initView(); }; ShockWaveEffect.prototype._generateView = function() { return new ShockWaveView(this); }; ShockWaveEffect.prototype._calculateEndCount = function(count) { if(this.default || count * this.b < this.gameState.getWidth() / 2) return count; var x = this.getX(); var y = this.getY(); if(x < this.gameState.getWidth() / 2) x = this.gameState.getWidth() - x; if(y < this.gameState.getHeight() / 2) y = this.gameState.getHeight() - y; var r = (this.Math.sqrt(x*x + y*y) | 0); var count2 = ((r / this.b) | 0) + this.g; return (count2 < count) ? count2 : count; }; ShockWaveEffect.prototype.display = function(surface) { if(this.default) { this._displayDefault(surface); return; } var x = Math.round(this.getX()); var y = Math.round(this.getY()); surface.save(); this._display(surface, x, y); surface.restore(); // surface.fillText( x + ':' + y, x, y ) ; } ; /** * display with pre-rendering. */ ShockWaveEffect.prototype._displayDefault = function(surface) { var x = Math.round(this.getX()); var y = Math.round(this.getY()); var r = this.count * this.b; if(this.preCanvas[this.count] == undefined) { var cvs = document.createElement('canvas') cvs.width = r*2 + this.w; cvs.height = r*2 + this.w; var ctx = cvs.getContext('2d'); this._display(ctx, r+this.w/2, r+this.w/2); this.preCanvas[this.count] = cvs; } surface.drawImage(this.preCanvas[this.count], x-r-this.w/2, y-r-this.w/2); }; ShockWaveEffect.prototype._display = function(surface, x, y) { var r = this.count * this.b; if(r <= 0) return; var s = 1 - (this.g*this.w)/(this.count*this.b); if(s < 0) s = 0.0; var g = surface.createRadialGradient(x, y, 0, x, y, r); g.addColorStop(s, ShockWaveEffect._INNER_COLOR); g.addColorStop(1.00, ShockWaveEffect._OUTER_COLORS[parseInt(this.a*10)]); surface.beginPath(); surface.fillStyle = g; surface.arc(x, y, r, 0, Math.PI * 2); surface.fill(); }; ShockWaveEffect.prototype.checkLoss = function( ) { return this.count > this.endCount ? true : false ; } ; ShockWaveEffect.prototype.getImageIndexX = function() { return 0; }; ShockWaveEffect.prototype.getImageIndexY = function() { return this.count; }; /** * TODO: temporal */ ShockWaveEffect.prototype.getImageWidth = function() { return 256; }; /** * TODO: temporal */ ShockWaveEffect.prototype.getImageHeight = function() { return 2048; }; function BigShockWaveEffectFreeList(num, gameState) { this.parent = ElementFreeList; this.parent.call(this, num, gameState); } __inherit(BigShockWaveEffectFreeList, ElementFreeList); BigShockWaveEffectFreeList.prototype._generateElement = function() { return new BigShockWaveEffect(this.gameState, this.gameState.getWidth(), this.gameState.getHeight()); }; function BigShockWaveDrawer(elementManager, layer, image) { this.parent = ElementDrawer; this.parent.call(this, elementManager, layer, image); }; __inherit(BigShockWaveDrawer, ElementDrawer); BigShockWaveDrawer.prototype._doPour = function(e) { return (e._ID === this.elementManager._ID_BIG_SHOCKWAVE); }; function BigShockWaveView(element) { this.parent = ElementView; this.parent.call(this, element); }; __inherit(BigShockWaveView, ElementView); BigShockWaveView.prototype.animate = function() { this.a = this.element.a; var w = this.element.b * this.element.count; var h = this.element.b * this.element.count; this.vertices[0] = -w; this.vertices[1] = -h; this.vertices[2] = -1.0; this.vertices[3] = w; this.vertices[4] = -h; this.vertices[5] = -1.0; this.vertices[6] = w; this.vertices[7] = h; this.vertices[8] = -1.0; this.vertices[9] = -w; this.vertices[10] = h; this.vertices[11] = -1.0; }; BigShockWaveView.prototype.rotate = function() { }; function BigShockWaveEffect(gameState, maxX, maxY) { this.parent = Element; this.parent.call(this, gameState, maxX, maxY); this.element = null; this.w = null; this.g = null; this.a = null; this.b = null; this.default = null; this.endCount = null; } __inherit(BigShockWaveEffect, Element); // only for reference BigShockWaveEffect.prototype.Math = Math; BigShockWaveEffect.prototype._WIDTH = 512; BigShockWaveEffect.prototype._HEIGHT = 512; __copyParentMethod(BigShockWaveEffect, Element, 'init'); BigShockWaveEffect.prototype.init = function(params, image, element) { this.Element_init(params, image); this.element = element; this.width = 512; this.height = 512; this.w = params.w; this.g = params.g; this.a = params.a; this.b = params.b; this.default = params.default; this.endCount = this._calculateEndCount(params.endCount); this._initView(); }; BigShockWaveEffect.prototype._generateView = function() { return new BigShockWaveView(this); }; BigShockWaveEffect.prototype._calculateEndCount = function(count) { if(this.default || count * this.b < this.gameState.getWidth() / 2) return count; var x = this.getX(); var y = this.getY(); if(x < this.gameState.getWidth() / 2) x = this.gameState.getWidth() - x; if(y < this.gameState.getHeight() / 2) y = this.gameState.getHeight() - y; var r = (this.Math.sqrt(x*x + y*y) | 0); var count2 = ((r / this.b) | 0) + this.g; return (count2 < count) ? count2 : count; }; BigShockWaveEffect.prototype.checkLoss = function( ) { return this.count > this.endCount ? true : false ; } ; /** * TODO: temporal */ BigShockWaveEffect.prototype.getImageWidth = function() { return 512; }; /** * TODO: temporal */ BigShockWaveEffect.prototype.getImageHeight = function() { return 512; }; function ExplosionEffectFreeList(num, gameState) { this.parent = ElementFreeList; this.parent.call(this, num, gameState); }; __inherit(ExplosionEffectFreeList, ElementFreeList); ExplosionEffectFreeList.prototype._generateElement = function() { return new ExplosionEffect(this.gameState, this.gameState.getWidth(), this.gameState.getHeight()); }; function ExplosionDrawer(elementManager, layer, image) { this.parent = ElementDrawer; this.parent.call(this, elementManager, layer, image); }; __inherit(ExplosionDrawer, ElementDrawer); ExplosionDrawer.prototype._doPour = function(e) { return (e._ID === this.elementManager._ID_EXPLOSION); }; function ExplosionView(element) { this.parent = ElementView; this.parent.call(this, element); }; __inherit(ExplosionView, ElementView); ExplosionView.prototype.animate = function() { this._initCoordinates(); this.a = (this.element._END_COUNT - this.element.count + 1)/ this.element._END_COUNT; }; ExplosionView.prototype.rotate = function() { }; ExplosionView.prototype.doRotateForViewpoint = function() { return true; }; function ExplosionEffect(gameState, maxX, maxY) { this.parent = Element; this.parent.call(this, gameState, maxX, maxY); this.preCanvas = this._PRE_CANVAS; } __inherit(ExplosionEffect, Element); ExplosionEffect.prototype._WIDTH = 64 ; ExplosionEffect.prototype._HEIGHT = 64 ; ExplosionEffect.prototype._END_COUNT = 10; ExplosionEffect.prototype._PRE_CANVAS = []; /* TODO: temporal */ __copyParentMethod(ExplosionEffect, Element, 'init'); ExplosionEffect.prototype.init = function(params, image, enemy) { this.Element_init(params, image); this.setX(enemy.getX()); this.setY(enemy.getY()); this.width = this._WIDTH; this.height = this._HEIGHT; this.collisionWidth = this.width; this.collisionHeight = this.height; this.indexX = 0; this.indexY = 1; this._initView(); }; ExplosionEffect.prototype._generateView = function() { return new ExplosionView(this); }; /** * TODO: temporal */ ExplosionEffect.prototype.display = function(surface) { var x = Math.round(this.getX()); var y = Math.round(this.getY()); var r = Math.round(this.width * this.count * 0.1); if(this.preCanvas[this.count] == undefined) { var cvs = document.createElement('canvas') cvs.width = r*2 + 4; cvs.height = r*2 + 4; var ctx = cvs.getContext('2d'); ctx.beginPath(); ctx.fillStyle = 'rgb(255, 255, 255)'; ctx.globalAlpha = (ExplosionEffect._END_COUNT - this.count + 1) * 0.05; ctx.arc(r+2, r+2, r, 0, Math.PI * 2); ctx.fill(); ctx.beginPath(); ctx.strokeStyle = 'rgb(255, 255, 255)'; ctx.globalAlpha = (ExplosionEffect._END_COUNT - this.count + 1) * 0.1; ctx.lineWidth = 3; ctx.arc(r+2, r+2, r, 0, Math.PI * 2); ctx.stroke(); this.preCanvas[this.count] = cvs; } surface.drawImage(this.preCanvas[this.count], x-r-2, y-r-2); // surface.fillText( x + ':' + y, x, y ) ; }; ExplosionEffect.prototype.checkLoss = function() { return this.count > this._END_COUNT ? true : false; }; ExplosionEffect.prototype.getImageIndexX = function() { return 0; }; ExplosionEffect.prototype.getImageIndexY = function() { return this.count; }; /** * TODO: temporal */ ExplosionEffect.prototype.getImageWidth = function() { return 64; }; /** * TODO: temporal */ ExplosionEffect.prototype.getImageHeight = function() { return 1024; }; function GrazeDrawer(elementManager, layer, image) { this.parent = ElementDrawer; this.parent.call(this, elementManager, layer, image); }; __inherit(GrazeDrawer, ElementDrawer); GrazeDrawer.prototype._doPour = function(e) { return (e._ID === this.elementManager._ID_GRAZE); }; function GrazeView(element) { this.parent = ElementView; this.parent.call(this, element); this.a = 0.1; }; __inherit(GrazeView, ElementView); GrazeView.prototype.animate = function() { this.a = 1.0 - this.element.count/this.element._END_COUNT; }; GrazeView.prototype.rotate = function() { }; function GrazeEffectFreeList(num, gameState) { this.parent = ElementFreeList ; this.parent.call(this, num, gameState); } __inherit(GrazeEffectFreeList, ElementFreeList); GrazeEffectFreeList.prototype._generateElement = function() { return new GrazeEffect(this.gameState, this.gameState.getWidth(), this.gameState.getHeight()); }; function GrazeEffect(gameState, maxX, maxY) { this.parent = Element; this.parent.call(this, gameState, maxX, maxY); this.element = null; this.theta = 0; } __inherit(GrazeEffect, Element); // only for reference GrazeEffect.prototype.Math = Math; GrazeEffect.prototype._END_COUNT = 20; GrazeEffect.prototype._SPAN = 4; GrazeEffect.prototype._SIZE = 4; GrazeEffect.prototype._FLUCTUATION = 30; GrazeEffect.prototype._GAP = 5; GrazeEffect.prototype._generateView = function() { return new GrazeView(this); }; __copyParentMethod(GrazeEffect, Element, 'init'); GrazeEffect.prototype.init = function(params, image, element, bullet) { this.Element_init(params, image); this.element = element; this.width = this._SIZE; this.height = this._SIZE; if(bullet.getVelocity()) { this.theta = bullet.getTheta(); } else { var ax = this.element.getCenterX() - bullet.getCenterX(); var ay = this.element.getCenterY() - bullet.getCenterY(); this.theta = this._calculateTheta(this.Math.atan2(ay, ax)); } // TODO: temporal this.theta += this.gameState.count % this._FLUCTUATION - this._FLUCTUATION/2; // TODO: temporal for(var i = 0; i < this._GAP; i++) this.move(); this._initView(); }; /** * TODO: use MoveVector? */ GrazeEffect.prototype.move = function() { var x = this.getX(); var y = this.getY(); x = x + this.Math.cos(this._calculateRadian(this.theta)) * this._SPAN; y = y + this.Math.sin(this._calculateRadian(this.theta)) * this._SPAN; this.setX(x); this.setY(y); }; GrazeEffect.prototype.display = function(surface) { var x = Math.round(this.getX()); var y = Math.round(this.getY()); surface.save(); surface.globalAlpha = 1.0 - this.count/GrazeEffect._END_COUNT; surface.fillRect(x-GrazeEffect._SIZE/2, y-GrazeEffect._SIZE/2, GrazeEffect._SIZE, GrazeEffect._SIZE); surface.restore(); // surface.fillText( x + ':' + y, x, y ) ; } ; GrazeEffect.prototype.checkLoss = function() { return this.count > this._END_COUNT ? true : false; }; /** * TODO: temporal */ GrazeEffect.prototype.getImageWidth = function() { return this._SIZE; }; /** * TODO: temporal */ GrazeEffect.prototype.getImageHeight = function() { return this._SIZE; }; function DamageEffectFreeList( num, gameState ) { this.parent = ElementFreeList ; this.parent.call( this, num, gameState ) ; } ; __inherit( DamageEffectFreeList, ElementFreeList ) ; DamageEffectFreeList.prototype._generateElement = function( ) { return new DamageEffect( this.gameState, this.gameState.getWidth( ), this.gameState.getHeight( ) ) ; } ; function DamageDrawer(elementManager, layer, image) { this.parent = ElementDrawer; this.parent.call(this, elementManager, layer, image); }; __inherit(DamageDrawer, ElementDrawer); DamageDrawer.prototype._doPour = function(e) { return (e._ID === this.elementManager._ID_DAMAGE); }; function DamageView(element) { this.parent = ElementView; this.parent.call(this, element); }; __inherit(DamageView, ElementView); DamageView.prototype.animate = function() { this.a = (this.element._END_COUNT - this.element.count + 1) * 0.02; }; DamageView.prototype.rotate = function() { }; DamageView.prototype.doRotateForViewpoint = function() { return true; }; function DamageEffect( gameState, maxX, maxY ) { this.parent = Element ; this.parent.call( this, gameState, maxX, maxY ) ; this.enemy = null ; this.dx = 0 ; this.dy = 0 ; } __inherit( DamageEffect, Element ) ; // only for reference DamageEffect.prototype.Math = Math; DamageEffect.prototype.Randomizer = __randomizer; DamageEffect.prototype._WIDTH = 64 ; DamageEffect.prototype._HEIGHT = 64 ; DamageEffect.prototype._END_COUNT = 2; __copyParentMethod(DamageEffect, Element, 'init'); DamageEffect.prototype.init = function(params, image, enemy) { this.Element_init(params, image); this.enemy = enemy; this.setX(enemy.getX()); this.setY(enemy.getY()); this.width = this._WIDTH; this.height = this._HEIGHT; this.collisionWidth = this.width; this.collisionHeight = this.height; this.indexX = 0; this.indexY = 0; // TODO: temporal var tmp = 32; this.dx = -tmp/2 + (this.Math.pow(this.gameState.count, 2)%32); this.dy = -tmp/2 + (this.Math.pow(this.gameState.count, 2)%32); this._initView(); }; DamageEffect.prototype._generateView = function() { return new DamageView(this); }; /** * TODO: temporal */ __copyParentMethod(DamageEffect, Element, 'runStep'); DamageEffect.prototype.runStep = function() { var tmp = 32; this.dx = -tmp / 2 + ((this.Randomizer.random() * tmp) | 0); this.dy = -tmp / 2 + ((this.Randomizer.random() * tmp) | 0); this.Element_runStep(); }; __copyParentMethod(DamageEffect, Element, 'getX'); DamageEffect.prototype.getX = function() { return this.Element_getX() + this.dx; }; __copyParentMethod(DamageEffect, Element, 'getY'); DamageEffect.prototype.getY = function() { return this.Element_getY() + this.dy; }; /** * TODO: temporal */ DamageEffect.prototype.display = function( surface ) { surface.save( ) ; var x = Math.round( this.getLeftX( ) + this.dx ) ; var y = Math.round( this.getUpY( ) + this.dy ) ; var width = this.getWidth( ) ; var height = this.getHeight( ) ; surface.globalAlpha = ( 3 - this.count ) * 0.1 ; surface.drawImage( this.image, this.width * this.indexX, this.height * this.indexY + 32 * 13, this.width, this.height, x, y, width, height ) ; surface.restore( ) ; // surface.fillText( x + ':' + y, x, y ) ; } ; DamageEffect.prototype.checkLoss = function( ) { return this.count > 2 ? true : false ; } ; /** * TODO: temporal */ DamageEffect.prototype.getImageWidth = function() { return this._WIDTH; }; /** * TODO: temporal */ DamageEffect.prototype.getImageHeight = function() { return this._HEIGHT; }; function BigExplosionEffectFreeList(num, gameState) { this.parent = ElementFreeList; this.parent.call(this, num, gameState); }; __inherit(BigExplosionEffectFreeList, ElementFreeList); BigExplosionEffectFreeList.prototype._generateElement = function() { return new BigExplosionEffect(this.gameState, this.gameState.getWidth(), this.gameState.getHeight()); }; function BigExplosionDrawer(elementManager, layer, image) { this.parent = ElementDrawer; this.parent.call(this, elementManager, layer, image); }; __inherit(BigExplosionDrawer, ElementDrawer); BigExplosionDrawer.prototype._doPour = function(e) { return (e._ID === this.elementManager._ID_BIG_EXPLOSION); }; function BigExplosionView(element) { this.parent = ElementView; this.parent.call(this, element); }; __inherit(BigExplosionView, ElementView); BigExplosionView.prototype.animate = function() { this.a = (this.element._END_COUNT - this.element.count + 1) / this.element._END_COUNT; var w = 32 * this.element.count * 0.1; var h = 32 * this.element.count * 0.1; this.vertices[0] = -w; this.vertices[1] = -h; this.vertices[2] = -1.0; this.vertices[3] = w; this.vertices[4] = -h; this.vertices[5] = -1.0; this.vertices[6] = w; this.vertices[7] = h; this.vertices[8] = -1.0; this.vertices[9] = -w; this.vertices[10] = h; this.vertices[11] = -1.0; }; BigExplosionView.prototype.rotate = function() { }; function BigExplosionEffect(gameState, maxX, maxY) { this.parent = Element; this.parent.call(this, gameState, maxX, maxY); this.boss = null; }; __inherit(BigExplosionEffect, Element); BigExplosionEffect.prototype._WIDTH = 320; BigExplosionEffect.prototype._HEIGHT = 320; BigExplosionEffect.prototype._END_COUNT = 100; __copyParentMethod(BigExplosionEffect, Element, 'init'); BigExplosionEffect.prototype.init = function(params, image, boss) { this.Element_init(params, image); this.width = this._WIDTH; this.height = this._HEIGHT; this.collisionWidth = this.width; this.collisionHeight = this.height; this.boss = boss; this.indexX = 0; this.indexY = 0; this._initView(); }; BigExplosionEffect.prototype._generateView = function() { return new BigExplosionView(this); }; /** * TODO: temporal */ BigExplosionEffect.prototype.display = function(surface) { var x = Math.round(this.getX()); var y = Math.round(this.getY()); var r = this.width * this.count * 0.1; surface.save(); surface.fillStyle = 'rgb(255, 255, 255)'; surface.globalAlpha = (BigExplosionEffect._END_COUNT - this.count + 1) * 0.005; surface.beginPath(); surface.arc(x, y, r, 0, Math.PI * 2); surface.fill(); surface.strokeStyle = 'rgb(255, 255, 255)'; surface.globalAlpha = (BigExplosionEffect._END_COUNT - this.count + 1 ) * 0.01; surface.beginPath(); surface.arc(x, y, r, 0, Math.PI * 2); surface.lineWidth = 3; surface.stroke(); surface.restore(); // surface.fillText( x + ':' + y, x, y ) ; }; BigExplosionEffect.prototype.checkLoss = function() { return this.count > this._END_COUNT ? true : false; }; /** * TODO: temporal */ BigExplosionEffect.prototype.getImageWidth = function() { return 512; }; /** * TODO: temporal */ BigExplosionEffect.prototype.getImageHeight = function() { return 512; }; // TODO: remove the followings because they complicate the design. // TODO: temporal // only for reference EffectManager.prototype.ShockWaveEffect = ShockWaveEffect.prototype; EffectManager.prototype.BigShockWaveEffect = BigShockWaveEffect.prototype; EffectManager.prototype.ExplosionEffect = ExplosionEffect.prototype; EffectManager.prototype.GrazeEffect = GrazeEffect.prototype; EffectManager.prototype.DamageEffect = DamageEffect.prototype; EffectManager.prototype.BigExplosionEffect = BigExplosionEffect.prototype; // TODO: temporal // for _doPour() and free() EffectManager.prototype._ID_SHOCKWAVE = 0; EffectManager.prototype._ID_BIG_SHOCKWAVE = 1; EffectManager.prototype._ID_EXPLOSION = 2; EffectManager.prototype._ID_GRAZE = 3; EffectManager.prototype._ID_DAMAGE = 4; EffectManager.prototype._ID_BIG_EXPLOSION = 5; EffectFactory.prototype.EffectManager = EffectManager.prototype; ShockWaveEffect.prototype._ID = EffectManager.prototype._ID_SHOCKWAVE; BigShockWaveEffect.prototype._ID = EffectManager.prototype._ID_BIG_SHOCKWAVE; ExplosionEffect.prototype._ID = EffectManager.prototype._ID_EXPLOSION; GrazeEffect.prototype._ID = EffectManager.prototype._ID_GRAZE; DamageEffect.prototype._ID = EffectManager.prototype._ID_DAMAGE; BigExplosionEffect.prototype._ID = EffectManager.prototype._ID_BIG_EXPLOSION; ================================================ FILE: source/Element.js ================================================ /** * TODO: should rename Element to Entity? */ function ElementManager(gameState) { this.gameState = gameState; this.elements = []; this.count = 0; this.factory = null; this.drawer = null; this.maxNum = this._initMaxNum(); this._initFactory(); }; /** * maximum number for WebGL Buffer. * TODO: bad design? * TODO: rename to _getMaxNum. */ ElementManager.prototype._initMaxNum = function() { return 1; }; ElementManager.prototype._initFactory = function( ) { this.factory = new ElementFactory( this.gameStage, this.gameState.maxX, this.gameState.maxY ) ; } ; /** * TODO: be private? */ ElementManager.prototype.initDrawer = function(layer, image) { this.drawer = new ElementDrawer(this, layer, image); }; ElementManager.prototype.reset = function( ) { for( var i = 0; i < this.elements.length; i++ ) { this.elements[ i ].die( ) ; this.elements[ i ].free( ) ; this.factory.free( this.elements[ i ] ) ; } this.elements.length = 0 ; this.count = 0 ; } ; ElementManager.prototype.runStep = function() { for(var i = 0, len = this.elements.length; i < len; i++) this.elements[i].runStep(); this.count++; }; /** * displays on 2D Canvas */ ElementManager.prototype.display = function( surface ) { for( var i = 0; i < this.elements.length; i++ ) this.elements[ i ].display( surface ) ; } ; /** * draws on WebGL layer * TODO: rename */ ElementManager.prototype.draw = function(layer) { this.drawer.draw(layer); }; ElementManager.prototype.create = function( params ) { this.addElement( this.factory.create( params ) ) ; } ; /** * TODO: rename to add() */ ElementManager.prototype.addElement = function(element) { this.elements[this.elements.length] = element; }; ElementManager.prototype.add = function(element) { this.addElement(element); }; ElementManager.prototype.get = function(index) { return this.elements[index]; }; ElementManager.prototype.checkCollisionWith = function( id, element, caller, flag ) { for(var i = 0, len = this.elements.length; i < len; i++) { if(this.elements[i].checkCollision(element)) { caller.notifyCollision(id, element, this.elements[i]); if(flag === true) return ; } } }; /** * TODO: temporal */ ElementManager.prototype.checkCollisionWith2 = function( id, element, caller, flag) { for(var i = 0, len = this.elements.length; i < len; i++) { if(element.checkCollision(this.elements[i])) { caller.notifyCollision2(id, element, this.elements[i]); if(flag === true) return; } } }; ElementManager.prototype.checkGrazeWith = function(id, element, caller) { for(var i = 0, len = this.elements.length; i < len; i++) { if(this.elements[i].checkGraze(element)) { caller.notifyGraze(id, element, this.elements[i]); } } }; /** * TODO: temporal. How deletes unnecessary entries? */ ElementManager.prototype.checkLoss = function(caller) { var j = 0 ; for(var i = 0, len = this.elements.length; i < len; i++ ) { if( ! this.elements[ i ].checkLoss( ) ) { this.elements[ i - j ] = this.elements[ i ] ; } else { this.elements[ i ].die( ) ; // TODO: temporal if(caller !== void 0) caller.notifyCheckLoss(this.elements[i]); this.elements[ i ].free( ) ; this.factory.free( this.elements[ i ] ) ; j++ ; } } this.elements.length -= j ; } ElementManager.prototype.getNum = function() { return this.elements.length; }; ElementManager.prototype.getMaxNum = function() { return this.maxNum; }; function ElementFactory( gameState, maxX, maxY ) { this.gameState = gameState ; this.maxX = maxX ; this.maxY = maxY ; this.freelist = null ; this._initFreelist( ) ; } ; ElementFactory.prototype._NUM = 100 ; ElementFactory.prototype._initFreelist = function() { this.freelist = new ElementFreeList(this._NUM, this.gameState); }; ElementFactory.prototype.create = function( params ) { var element = this.freelist.get( ) ; element.init( params, this._getImage( params ) ) ; return element ; } ; ElementFactory.prototype.free = function( element ) { this.freelist.free( element ) ; } ; /** * Child process must override this method. */ ElementFactory.prototype._getImage = function( params ) { return new Image( ) ; } ; /** * TODO: list may should be Linked list if num is large. */ function ElementFreeList( num, gameState ) { this.gameState = gameState ; FreeList.call( this, num ) ; } __inherit( ElementFreeList, FreeList ) ; /** * Child class must override this method. */ ElementFreeList.prototype._generateElement = function( ) { return new Element( this.gameState, this.gameState.maxX, this.gameState.maxY ) ; } ; /** * This class has position and parameters of Element for WebGL. * They're used by ElementDrawer. * Note that this class doesn't have image and texture. * ElementDrawer has them. */ function ElementView(element) { this.element = element; this.a = 1.0; this.d = 1.0; this.vertices = []; this.coordinates = []; this.indices = []; this.colors = []; this.sVertices = []; this.vertices.length = this._V_SIZE; this.coordinates.length = this._C_SIZE; this.indices.length = this._I_SIZE; this.colors.length = this._A_SIZE; this.sVertices.length = this._V_SIZE; }; // only for reference ElementView.prototype.Math = Math; ElementView.prototype._V_ITEM_SIZE = 3; ElementView.prototype._V_ITEM_NUM = 4; ElementView.prototype._V_SIZE = ElementView.prototype._V_ITEM_SIZE * ElementView.prototype._V_ITEM_NUM; ElementView.prototype._C_ITEM_SIZE = 2; ElementView.prototype._C_ITEM_NUM = 4; ElementView.prototype._C_SIZE = ElementView.prototype._C_ITEM_SIZE * ElementView.prototype._C_ITEM_NUM; ElementView.prototype._I_ITEM_SIZE = 1; ElementView.prototype._I_ITEM_NUM = 6; ElementView.prototype._I_SIZE = ElementView.prototype._I_ITEM_SIZE * ElementView.prototype._I_ITEM_NUM; ElementView.prototype._A_ITEM_SIZE = 4; ElementView.prototype._A_ITEM_NUM = 4; ElementView.prototype._A_SIZE = ElementView.prototype._A_ITEM_SIZE * ElementView.prototype._A_ITEM_NUM; // TODO: temporal ElementView._V_ITEM_SIZE = 3; ElementView._V_ITEM_NUM = 4; ElementView._V_SIZE = ElementView._V_ITEM_SIZE * ElementView._V_ITEM_NUM; ElementView._C_ITEM_SIZE = 2; ElementView._C_ITEM_NUM = 4; ElementView._C_SIZE = ElementView._C_ITEM_SIZE * ElementView._C_ITEM_NUM; ElementView._I_ITEM_SIZE = 1; ElementView._I_ITEM_NUM = 6; ElementView._I_SIZE = ElementView._I_ITEM_SIZE * ElementView._I_ITEM_NUM; ElementView._A_ITEM_SIZE = 4; ElementView._A_ITEM_NUM = 4; ElementView._A_SIZE = ElementView._A_ITEM_SIZE * ElementView._A_ITEM_NUM; ElementView.prototype.init = function() { this._initVertices(); this._initCoordinates(); this._initIndices(); this._initColors(); }; ElementView.prototype._initVertices = function() { var w = this.element.getWidth()/2; var h = this.element.getHeight()/2; this.vertices[0] = -w; this.vertices[1] = -h; this.vertices[2] = -1.0; this.vertices[3] = w; this.vertices[4] = -h; this.vertices[5] = -1.0; this.vertices[6] = w; this.vertices[7] = h; this.vertices[8] = -1.0; this.vertices[9] = -w; this.vertices[10] = h; this.vertices[11] = -1.0; }; ElementView.prototype._initCoordinates = function() { var w = this.element.getWidth()/this.element.getImageWidth(); var h = this.element.getHeight()/this.element.getImageHeight(); var x1 = w * this.element.getImageIndexX(); var y1 = h * this.element.getImageIndexY(); var x2 = x1 + w; var y2 = y1 + h; this.coordinates[0] = x1; this.coordinates[1] = y2; this.coordinates[2] = x2; this.coordinates[3] = y2; this.coordinates[4] = x2; this.coordinates[5] = y1; this.coordinates[6] = x1; this.coordinates[7] = y1; }; ElementView.prototype._initIndices = function() { this.indices[0] = 0; this.indices[1] = 1; this.indices[2] = 2; this.indices[3] = 0; this.indices[4] = 2; this.indices[5] = 3; }; ElementView.prototype._initColors = function() { this.colors[0] = 1.0; this.colors[1] = 1.0; this.colors[2] = 1.0; this.colors[3] = 1.0; this.colors[4] = 1.0; this.colors[5] = 1.0; this.colors[6] = 1.0; this.colors[7] = 1.0; this.colors[8] = 1.0; this.colors[9] = 1.0; this.colors[10] = 1.0; this.colors[11] = 1.0; this.colors[12] = 1.0; this.colors[13] = 1.0; this.colors[14] = 1.0; this.colors[15] = 1.0; }; ElementView.prototype.getNum = function() { return 1; }; ElementView.prototype.saveVertices = function() { for(var i = 0, len = this._V_SIZE * this.getNum(); i < len; i++) { this.sVertices[i] = this.vertices[i]; } }; ElementView.prototype.restoreVertices = function() { for(var i = 0, len = this._V_SIZE * this.getNum(); i < len; i++) { this.vertices[i] = this.sVertices[i]; } }; ElementView.prototype.translate = function() { for(var j = 0, len = this.getNum(); j < len; j++) { var o = this._V_SIZE * j; for(var i = 0; i < this._V_ITEM_NUM; i++) { this.vertices[o+i*this._V_ITEM_SIZE+0] += this._getElementX(); // this is the trick to correspond 2D canvas coordinates. this.vertices[o+i*this._V_ITEM_SIZE+1] -= this._getElementY(); this.vertices[o+i*this._V_ITEM_SIZE+2] += this._getElementZ();; } } }; ElementView.prototype._getElementX = function() { return this.element.getX(); }; ElementView.prototype._getElementY = function() { return this.element.getY(); }; ElementView.prototype._getElementZ = function() { return this.element.getZ(); }; ElementView.prototype.rotate = function() { var theta = 270 - this.element.getDirectionTheta(); var radian = theta * this.Math.PI / 180; for(var j = 0, len = this.getNum(); j < len; j++) { var o = this._V_SIZE * j; for(var i = 0; i < this._V_ITEM_NUM; i++) { var x = this.vertices[o+i*this._V_ITEM_SIZE+0]; var y = this.vertices[o+i*this._V_ITEM_SIZE+1]; this.vertices[o+i*this._V_ITEM_SIZE+0] = x * this.Math.cos(radian) - y * this.Math.sin(radian); this.vertices[o+i*this._V_ITEM_SIZE+1] = x * this.Math.sin(radian) + y * this.Math.cos(radian); } } }; /** * TODO: optimize. and remove magic numbers; */ ElementView.prototype.rotateForViewpoint = function() { var r = this.Math.sqrt(40*40 + 120*120); var r2 = this.element.getHeight()/2; var ay = 40 * r2 / r; var az = 120 * r2 / r; for(var j = 0, len = this.getNum(); j < len; j++) { var o = this._V_SIZE * j; for(var i = 0; i < this._V_ITEM_NUM; i++) { var y = this.vertices[o+i*this._V_ITEM_SIZE+1]; var z = this.vertices[o+i*this._V_ITEM_SIZE+2]; if(i > 1) { this.vertices[o+i*this._V_ITEM_SIZE+1] = ay; this.vertices[o+i*this._V_ITEM_SIZE+2] = z+az; } else { this.vertices[o+i*this._V_ITEM_SIZE+1] = ay; this.vertices[o+i*this._V_ITEM_SIZE+2] = z-az; } } } }; ElementView.prototype.doRotateForViewpoint = function() { return false; }; /** * assume that update coordinates here in each frame. */ ElementView.prototype.animate = function() { }; function ElementDrawer(e, layer, image) { this.gameState = e.gameState; if(e instanceof ElementManager) { this.elementManager = e; this.element = null; this.maxLength = e.getMaxNum(); } else { this.element = e; this.elementManager = null; this.maxLength = 1; } this.vArray = layer.createFloatArray(this.maxLength*this.ElementView._V_SIZE); this.cArray = layer.createFloatArray(this.maxLength*this.ElementView._C_SIZE); this.iArray = layer.createUintArray(this.maxLength*this.ElementView._I_SIZE); this.aArray = layer.createFloatArray(this.maxLength*this.ElementView._A_SIZE); this.vBuffer = layer.createBuffer(); this.cBuffer = layer.createBuffer(); this.iBuffer = layer.createBuffer(); this.aBuffer = layer.createBuffer(); this.texture = null; this._initTexture(layer, image); }; // only for reference ElementDrawer.prototype.ElementView = ElementView.prototype; ElementDrawer.prototype.Layer = Layer.prototype; ElementDrawer.prototype._initTexture = function(layer, image) { this.texture = layer.generateTexture(image); }; ElementDrawer.prototype._pourVertices = function(i, v) { v.saveVertices(); if(this.gameState.doLookAtFromViewpointTarget() && v.doRotateForViewpoint()) v.rotateForViewpoint(); v.rotate(); v.translate(); var num = v.getNum(); var vLength = v._V_SIZE; for(var k = 0; k < num; k++) { for(var j = 0; j < vLength; j++) { this.vArray[(i+k)*vLength+j] = v.vertices[k*vLength+j]; } } v.restoreVertices(); }; ElementDrawer.prototype._pourCoordinates = function(i, v) { var cLength = v._C_SIZE; for(var k = 0, len = v.getNum(); k < len; k++) { for(var j = 0; j < cLength; j++) { this.cArray[(i+k)*cLength+j] = v.coordinates[k*cLength+j]; } } }; ElementDrawer.prototype._pourIndices = function(i, v) { // TODO: 4 is a magic number var iLength = v._I_SIZE; var indices = v.indices; for(var k = 0, len = v.getNum(); k < len; k++) { for(var j = 0; j < iLength; j++) { this.iArray[(i+k)*iLength+j] = (i+k)*4 + indices[k*iLength+j]; } } }; ElementDrawer.prototype._pourColors = function(i, v) { var aLength = v._A_SIZE; var colors = v.colors; var a = v.a; var d = v.d; for(var k = 0, len = v.getNum(); k < len; k++) { for(var j = 0; j < aLength; j++) { if(j % 4 == 3) this.aArray[(i+k)*aLength+j] = colors[k*aLength+j] * a; else this.aArray[(i+k)*aLength+j] = colors[k*aLength+j] * d; } } }; ElementDrawer.prototype._pourArray = function(e, n) { var v = e.getView(); v.animate(); this._pourVertices(n, v); this._pourCoordinates(n, v); this._pourIndices(n, v); this._pourColors(n, v); return v.getNum(); }; ElementDrawer.prototype._pourArrays = function() { var n = 0; for(var i = 0, len = this.elementManager.getNum(); i < len; i++) { // TODO: bad design var e = this.elementManager.get(i); if(this._doPour(e)) { n += this._pourArray(e, n); } } return n; }; ElementDrawer.prototype._doPour = function(e) { return true; }; /** * This method can be performance critical function. * TODO: iBuffer generally doesn't need to update in each frame. * It's good enough to update only its size if it's initialized. * It could be improve CPU-GPU transfer performance. * TODO: attempt to redoce CPU-GPU transfer. */ ElementDrawer.prototype._pourBuffer = function(layer, n) { layer.pourArrayBuffer(this.vBuffer, this.vArray, this.ElementView._V_ITEM_SIZE, n * this.ElementView._V_ITEM_NUM); layer.pourArrayBuffer(this.cBuffer, this.cArray, this.ElementView._C_ITEM_SIZE, n * this.ElementView._C_ITEM_NUM); layer.pourArrayBuffer(this.aBuffer, this.aArray, this.ElementView._A_ITEM_SIZE, n * this.ElementView._A_ITEM_NUM); layer.pourElementArrayBuffer(this.iBuffer, this.iArray, this.ElementView._I_ITEM_SIZE, n * this.ElementView._I_ITEM_NUM); }; ElementDrawer.prototype._draw = function(layer) { layer.draw(this.texture, this.vBuffer, this.cBuffer, this.iBuffer, this.aBuffer, this._getBlend()); }; ElementDrawer.prototype._getBlend = function() { return this.Layer._BLEND_ALPHA; }; ElementDrawer.prototype._initDraw = function(layer) { layer.viewport(); }; /** * TODO: remove magic numbers. */ ElementDrawer.prototype._project = function(layer) { if(this.gameState.doLookAtFromViewpointTarget()) layer.perspective(60, 0.1, 1000.0); else layer.ortho(0.1, 10.0); }; /** * Note: layer.lookAt or something should be here. */ ElementDrawer.prototype._prepareDraw = function(layer) { }; ElementDrawer.prototype._VIEWPOINTS_CONTAINERS = [ [0, 0, 1], // eye [0, 0, 0], // center [0, 1, 0] // up ]; /** * TODO: remove magic numbers. */ ElementDrawer.prototype.lookAtFromViewpointTarget = function(layer) { var f = this.gameState.getViewpointTarget(); var eye = this._VIEWPOINTS_CONTAINERS[0]; var center = this._VIEWPOINTS_CONTAINERS[1]; var up = this._VIEWPOINTS_CONTAINERS[2]; eye[0] = f.getX(); eye[1] = -f.getY()+8; eye[2] = 20; center[0] = f.getX(); center[1] = -f.getY() + 128; center[2] = -20; layer.lookAt(eye, center, up); }; ElementDrawer.prototype.draw = function(layer) { var n = this.element ? this._pourArray(this.element, 0) : this._pourArrays(); this._pourBuffer(layer, n); this._initDraw(layer); this._project(layer); layer.identity(); this._prepareDraw(layer); if(this.gameState.doLookAtFromViewpointTarget()) this.lookAtFromViewpointTarget(layer); this._draw(layer); }; /** * TODO: parameters should be object? */ var __moveVectorManager = new MoveVectorManager( ) ; function Element( gameState, maxX, maxY ) { this.moveVectorManager = __moveVectorManager ; // TODO: temporal this.listId = null ; this.listForw = null ; this.image = null ; this.gameState = gameState ; this.maxX = maxX ; this.maxY = maxY ; this.x = 0 ; this.y = 0 ; this.z = 0 ; this.r = 0 ; this.keepAlive = 0 ; this.baseTheta = 0 ; this.indexX = 0 ; this.indexY = 0 ; this.width = 0 ; this.height = 0 ; this.collisionWidth = 0 ; this.collisionHeight = 0 ; this.grazeWidth = 0; this.grazeHeight = 0; this.state = 0 ; this.flags = 0 ; this.count = 0 ; this.graze = 0; this.vectorIndex = 0 ; this.vector = null ; this.baseVectorCount = 0 ; this.vectors = [ ] ; this.gravity = null ; this.view = this._generateView(); }; // only for reference Element.prototype.Math = Math; Element.prototype.Randomizer = __randomizer; Element.prototype._STATE_ALIVE = 1 ; Element.prototype._STATE_DEAD = 2 ; Element.prototype._FLAG_MOVE_STOP = 0x1 ; Element.prototype._FLAG_MOVE_LEFT = 0x2 ; Element.prototype._FLAG_MOVE_UP = 0x4 ; Element.prototype._FLAG_MOVE_RIGHT = 0x8 ; Element.prototype._FLAG_MOVE_DOWN = 0x10 ; Element.prototype._FLAG_SHOT = 0x20 ; Element.prototype._FLAG_HIT = 0x40 ; Element.prototype._FLAG_UNHITTABLE = 0x80 ; Element.prototype.init = function(params, image) { this.image = image ; this.x = this._getValueOrDefaultValue(params.x, 0); this.y = this._getValueOrDefaultValue(params.y, 0); this.z = this._getValueOrDefaultValue(params.z, 0); this.r = this._getValueOrDefaultValue(params.r, 0); this.keepAlive = this._getValueOrDefaultValue(params.keepAlive, 0); this.baseTheta = this._getValueOrDefaultValue(params.baseTheta, 0); this.indexX = this._getValueOrDefaultValue(params.indexX, 0); this.indexY = this._getValueOrDefaultValue(params.indexY, 0); this.width = this._getValueOrDefaultValue(params.width, 0); this.height = this._getValueOrDefaultValue(params.height, 0); this.collisionWidth = this._getValueOrDefaultValue(params.collisionWidth, 0); this.collisionHeight = this._getValueOrDefaultValue(params.collisionHeight, 0); this.grazeWidth = this._getValueOrDefaultValue(params.grazeWidth, 0); this.grazeHeight = this._getValueOrDefaultValue(params.grazeHeight, 0); this.graze = this._getValueOrDefaultValue(params.graze, 1); this.state = 0 ; this.flags = 0 ; this.count = 0 ; this.vectorIndex = 0 ; this.baseVectorCount = 0 ; // TODO: temporal this.vectors.length = 0 ; if(params.v === void 0) { } else if( params.v instanceof Array ) { for( var i = 0; i < params.v.length; i++ ) this.vectors.push( params.v[ i ] ) ; } else { params.v = [ { 'v': params.v } ] ; this.vectors.push( params.v[ 0 ] ) ; // this.vectors.push( { 'v': params.v } ) ; } if( this.vectors.length > 0 ) this.vectors[ 0 ].count = 0 ; this.vector = null ; this.gravity = null ; if( this.vectors.length > 0 ) this._initVector( ) ; this._supplyPosition( ) ; } ; Element.prototype._initView = function() { this.view.init(); }; Element.prototype.getView = function() { return this.view; }; Element.prototype._generateView = function() { return new ElementView(this); }; Element.prototype._getValueOrDefaultValue = function(value, defaultValue) { return value !== void 0 ? value : defaultValue; }; Element.prototype.free = function( ) { if(this.vector !== null) this.moveVectorManager.free( this.vector ) ; if(this.gravity !== null) this.moveVectorManager.free( this.gravity ) ; } ; Element.prototype._checkVectorChange = function( ) { if( this.vectorIndex >= this.vectors.length - 1 ) return false ; if( this.count >= this.vectors[ this.vectorIndex + 1 ].count + this.baseVectorCount ) { return true ; } return false ; } ; Element.prototype._changeVector = function( ) { this.vectorIndex++ ; if( typeof( this.vectors[ this.vectorIndex ].v ) == 'number' ) { this.vectorIndex = this.vectors[ this.vectorIndex ].v ; this.baseVectorCount = this.count ; } } ; /** * TODO: to make the logic straightforward. */ Element.prototype._initVector = function( ) { // save previous data var preTheta = null; if(this.vector !== null) preTheta = this.vector.theta ; var tmpTheta = this.vectors[ this.vectorIndex ].v.theta ; var tmpR = this.vectors[ this.vectorIndex ].v.r ; // for special propose // these functions will updates this.vectors[ this.vectorIndex ], // so previous data needs to be saved. if(this.vectors[ this.vectorIndex ].v.aimed !== void 0) this._calculateAimedVector( ) ; if(this.vectors[ this.vectorIndex ].v.target !== void 0) this._calculateTargetVector( ) ; // set normal vector if(this.vector !== null) this.moveVectorManager.free( this.vector ) ; this.vector = this.moveVectorManager.create( this.vectors[ this.vectorIndex ].v ) ; if(this.baseTheta !== null) this.vector.theta += this.baseTheta ; if(preTheta !== null && this.vectors[ this.vectorIndex ].v.theta === void 0) this.vector.theta = preTheta ; // restore previous data this.vectors[ this.vectorIndex ].v.theta = tmpTheta ; this.vectors[ this.vectorIndex ].v.r = tmpR ; // set gravity vector if(this.gravity !== null) this.moveVectorManager.free( this.gravity ) ; if(this.vectors[ this.vectorIndex ].v.g !== void 0) this.gravity = this.moveVectorManager.create( this.vectors[ this.vectorIndex ].v.g ) ; else this.gravity = null ; } ; /** * TODO: temporal */ Element.prototype._supplyPosition = function( ) { if(this.r === 0 || this.vector === null) return ; var ax = 0 ; var ay = 0 ; if(this.gravity === null) { ax = this.r * this.Math.cos( this._calculateRadian( this.vector.theta ) ) ; ay = this.r * this.Math.sin( this._calculateRadian( this.vector.theta ) ) ; } else { var dx = this.vector.moveX( ) + this.gravity.moveX( ) ; var dy = this.vector.moveY( ) + this.gravity.moveY( ) ; var t = this.Math.atan2( dy, dx ) ; ax = this.r * this.Math.cos( t ) ; ay = this.r * this.Math.sin( t ) ; } this.setX( this.getX( ) + ax ) ; this.setY( this.getY( ) + ay ) ; } ; /** * TODO: temporal */ Element.prototype._calculateAimedVector = function() { var fighter = this.gameState.fighterManager.getClosestFighter(this); var ax = fighter.getCenterX() - this.getCenterX(); var ay = fighter.getCenterY() - this.getCenterY(); this.vectors[this.vectorIndex].v.theta += this._calculateTheta(this.Math.atan2(ay, ax)); }; /** * TODO: temporal */ Element.prototype._calculateTargetVector = function( ) { var x = typeof( this.vectors[ this.vectorIndex ].v.target.x ) == 'object' ? this._getRandomValue( this.vectors[ this.vectorIndex ].v.target.x ) : this.vectors[ this.vectorIndex ].v.target.x ; var y = typeof( this.vectors[ this.vectorIndex ].v.target.y ) == 'object' ? this._getRandomValue( this.vectors[ this.vectorIndex ].v.target.y ) : this.vectors[ this.vectorIndex ].v.target.y ; var ax = x - this.getX( ) ; var ay = y - this.getY( ) ; this.vectors[ this.vectorIndex ].v.theta = this._calculateTheta( this.Math.atan2( ay, ax ) ) ; this.vectors[ this.vectorIndex ].v.r = this.Math.sqrt( ax * ax + ay * ay ) / this.vectors[ this.vectorIndex ].v.target.count ; } ; /** * TODO: temporal * duplicated code */ Element.prototype._getRandomValue = function(range) { var differ = range.max - range.min; return ((this.Randomizer.random() * differ) | 0) + range.min; }; Element.prototype._calculateRadian = function( theta ) { return theta * this.Math.PI / 180 ; } ; Element.prototype._calculateTheta = function(radian) { return (radian * 180 / this.Math.PI) | 0; }; Element.prototype.display = function( surface, rotate, angle ) { var x = this.Math.round( this.getLeftX( ) ) ; var y = this.Math.round( this.getUpY( ) ) ; if( rotate ) { var rx = this.Math.round( this.getCenterX( ) ) ; var ry = this.Math.round( this.getCenterY( ) ) ; if(angle === null || angle === void 0) angle = this._calculateRadian( this.getDirectionTheta( ) + 90 ) ; else angle = this._calculateRadian( angle ) ; surface.save( ) ; surface.translate( rx, ry ) ; surface.rotate( angle ) ; surface.translate( -rx, -ry ) ; } surface.drawImage( this.image, this.width * this.indexX, this.height * this.indexY, this.width, this.height, x, y, this.width, this.height ) ; if( rotate ) { surface.restore( ) ; } } ; Element.prototype.getX = function( ) { return this.x ; } ; Element.prototype.getY = function( ) { return this.y ; } ; Element.prototype.getZ = function() { return this.z; }; Element.prototype.getWidth = function( ) { return this.width ; } ; Element.prototype.getHeight = function( ) { return this.height ; } ; Element.prototype.getImageIndexX = function() { return this.indexX; }; Element.prototype.getImageIndexY = function() { return this.indexY; }; Element.prototype.getImageWidth = function() { return this.image.width; }; Element.prototype.getImageHeight = function() { return this.image.height; }; Element.prototype.setX = function( x ) { this.x = x ; } ; Element.prototype.setY = function( y ) { this.y = y ; } ; Element.prototype.getCenterX = function( ) { return this.getX( ) ; } ; Element.prototype.getCenterY = function( ) { return this.getY( ) ; } ; Element.prototype.getLeftX = function( ) { return this.getCenterX( ) - this.getWidth( ) / 2 ; } ; Element.prototype.getRightX = function( ) { return this.getCenterX( ) + this.getWidth( ) / 2 ; } ; /** * TODO: rename. Up -> Top */ Element.prototype.getUpY = function( ) { return this.getCenterY( ) - this.getHeight( ) / 2 ; } ; Element.prototype.getBottomY = function( ) { return this.getCenterY( ) + this.getHeight( ) / 2 ; } ; Element.prototype.getCollisionLeftX = function( ) { return this.getCenterX( ) - this.collisionWidth / 2 ; } ; Element.prototype.getCollisionRightX = function( ) { return this.getCenterX( ) + this.collisionWidth / 2 ; } ; Element.prototype.getCollisionUpY = function( ) { return this.getCenterY( ) - this.collisionHeight / 2 ; } ; Element.prototype.getCollisionBottomY = function( ) { return this.getCenterY( ) + this.collisionHeight / 2 ; } ; Element.prototype.inCollisionArea = function( x, y ) { if( x >= this.getCollisionLeftX( ) && x <= this.getCollisionRightX( ) && y >= this.getCollisionUpY( ) && y <= this.getCollisionBottomY( ) ) return true ; return false ; } ; /** * TODO: temporal */ Element.prototype.checkCollision = function( e ) { if( this.isDead( ) ) return false ; if( this.inCollisionArea( e.getCollisionLeftX( ), e.getCollisionUpY( ) ) || this.inCollisionArea( e.getCollisionLeftX( ), e.getCollisionBottomY( ) ) || this.inCollisionArea( e.getCollisionRightX( ), e.getCollisionUpY( ) ) || this.inCollisionArea( e.getCollisionRightX( ), e.getCollisionBottomY( ) ) || this.inCollisionArea( e.getCenterX( ), e.getCenterY( ) ) ) { return true ; } return false ; } ; Element.prototype.getGrazeLeftX = function() { return this.getCenterX() - this.grazeWidth/2; }; Element.prototype.getGrazeRightX = function() { return this.getCenterX() + this.grazeWidth/2; }; Element.prototype.getGrazeUpY = function() { return this.getCenterY() - this.grazeHeight/2; }; Element.prototype.getGrazeBottomY = function() { return this.getCenterY() + this.grazeHeight/2; }; Element.prototype.inGrazeArea = function(x, y) { if(x >= this.getGrazeLeftX() && x <= this.getGrazeRightX() && y >= this.getGrazeUpY() && y <= this.getGrazeBottomY()) return true; return false; }; /** * TODO: temporal */ Element.prototype.checkGraze = function(e) { if(!this.graze) return false; if(this.isDead()) return false; if(this.inGrazeArea(e.getGrazeLeftX(), e.getGrazeUpY()) || this.inGrazeArea(e.getGrazeLeftX(), e.getGrazeBottomY()) || this.inGrazeArea(e.getGrazeRightX(), e.getGrazeUpY()) || this.inGrazeArea(e.getGrazeRightX(), e.getGrazeBottomY()) || this.inGrazeArea(e.getCenterX(), e.getCenterY())) { return true; } return false; }; Element.prototype.inViewArea = function( x, y ) { if( x > this.getLeftX( ) && x < this.getRightX( ) && y > this.getUpY( ) && y < this.getBottomY( ) ) return true ; return false ; } ; Element.prototype.checkViewCollision = function( e ) { if( this.isDead( ) ) return false ; if( this.inViewArea( e.getLeftX( ), e.getUpY( ) ) || this.inViewArea( e.getLeftX( ), e.getBottomY( ) ) || this.inViewArea( e.getRightX( ), e.getUpY( ) ) || this.inViewArea( e.getRightX( ), e.getBottomY( ) ) ) { return true ; } return false ; } ; Element.prototype._beInTheField = function( ) { if( this.getX( ) < 0 ) this.setX( 0 ) ; if( this.getX( ) > this.maxX ) this.setX( this.maxX ) ; if( this.getY( ) < 0 ) this.setY( 0 ) ; if( this.getY( ) > this.maxY ) this.setY( this.maxY ) ; } ; /** * TODO: separate the check loss logic and reflect logic? */ Element.prototype.checkLoss = function( ) { if( this.isDead( ) ) return true ; if( this._outOfKeepAlive( ) ) return true ; if( this._checkReflect( ) ) return true ; if( this._outOfTheField( ) ) return true ; return false ; } ; Element.prototype._outOfKeepAlive = function( ) { if( this.keepAlive && this.count >= this.keepAlive ) return true ; } ; Element.prototype._outOfTheField = function( ) { if( this.getX( ) < 0 || this.getX( ) > this.maxX || this.getY( ) < 0 || this.getY( ) > this.maxY ) return true ; return false ; } ; Element.prototype._checkReflect = function( ) { if( this.vectors.length <= 0 ) return false ; if( this.vectors[ this.vectorIndex ].v.reflectX ) { if( this.getX( ) < 0 || this.getX( ) > this.maxX ) { this.vector.reflectX( ) ; this._beInTheField( ) ; if( this.vectors[ this.vectorIndex ].v.reflectCount && this.vector.getReflectCount( ) > this.vectors[ this.vectorIndex ].v.reflectCount ) return true ; } } if( this.vectors[ this.vectorIndex ].v.reflectY ) { if( this.getY( ) < 0 || this.getY( ) > this.maxY ) { this.vector.reflectY( ) ; this._beInTheField( ) ; if( this.vectors[ this.vectorIndex ].v.reflectCount && this.vector.getReflectCount( ) > this.vectors[ this.vectorIndex ].v.reflectCount ) return true ; } } if( this.vectors[ this.vectorIndex ].v.reflect ) { if( this.getX( ) < 0 || this.getX( ) > this.maxX || this.getY( ) < 0 || this.getY( ) > this.maxY ) { this.vector.reflect( ) ; this._beInTheField( ) ; if( this.vectors[ this.vectorIndex ].v.reflectCount && this.vector.getReflectCount( ) > this.vectors[ this.vectorIndex ].v.reflectCount ) return true ; } } return false ; } ; Element.prototype.move = function( ) { if( this.vector ) { this.setX( this.getX( ) + this._moveX( ) ) ; this.setY( this.getY( ) + this._moveY( ) ) ; } if( this.gravity ) { this.setX( this.getX( ) + this._moveGravityX( ) ) ; this.setY( this.getY( ) + this._moveGravityY( ) ) ; } } ; Element.prototype._moveX = function( ) { return this.vector.moveX( ) ; } ; Element.prototype._moveY = function( ) { return this.vector.moveY( ) ; } ; Element.prototype._moveGravityX = function( ) { return this.gravity.moveX( ) ; } ; Element.prototype._moveGravityY = function( ) { return this.gravity.moveY( ) ; } ; /** * TODO: temporal */ Element.prototype.getDirectionTheta = function( ) { if( ! this.vector ) return 90 ; if( this.vector && ! this.gravity ) return this.vector.theta ; // TODO: is there any simpler logics? var ax = this.vector.moveX( ) + this.gravity.moveX( ) ; var ay = this.vector.moveY( ) + this.gravity.moveY( ) ; return this._calculateTheta( this.Math.atan2( ay, ax ) ) ; } ; Element.prototype.getXDirection = function( ) { if( ! this.vector ) return 0 ; var cos = this.Math.cos( this._calculateRadian( this.getDirectionTheta( ) ) ) ; if( cos > 1.00e-10 ) return 1 ; else if( cos < -1.00e-10 ) return -1 ; return 0 ; } ; Element.prototype.getTheta = function() { if(this.getVelocity() >= 0) return this.vector.theta; return -this.vector.theta; }; Element.prototype.getVelocity = function() { return this.vector.r; }; /** * TODO: divide count up and runstep? */ Element.prototype.runStep = function( ) { this.move( ) ; if( this.gravity ) { this.gravity.runStep( ) ; } if( this.vector ) { this.vector.runStep( ) ; if( this._checkVectorChange( ) ) { this._changeVector( ) ; this._initVector( ) ; } } this.count++ ; } ; Element.prototype.die = function( ) { this.state = this._STATE_DEAD ; } ; Element.prototype.isDead = function( ) { return this.state == this._STATE_DEAD ; } ; Element.prototype.isFlagSet = function( type ) { return ( this.flags & type ) ? true : false ; } ; /** * Returns true if previous value is false. Otherwise returns false. */ Element.prototype.setFlag = function( type ) { var pre = this.isFlagSet( type ) ; this.flags |= type ; return ! pre ; } ; /** * Returns true if previous value is true. Otherwise returns false. */ Element.prototype.clearFlag = function( type ) { var pre = this.isFlagSet( type ) ; this.flags &= ~type ; return pre ; } ; ================================================ FILE: source/EndingState.js ================================================ function EndingState( game ) { this.parent = GameState ; this.parent.call( this, game ) ; this.count = 0 ; } __inherit( EndingState, GameState ) ; EndingState.prototype.init = function( ) { this._soundBGM( Game._BGM_ENDING ) ; } ; EndingState.prototype.runStep = function( ) { this.count++ ; } ; EndingState.prototype.updateDisplay = function( surface ) { this.game.clear( surface ) ; this._displayBG( surface ) ; this._displayMessage( surface ) ; } ; EndingState.prototype._displayBG = function( surface ) { surface.save( ) ; surface.fillStyle = 'rgb( 0, 0, 0 )' ; surface.fillRect( 0, 0, this.getWidth( ), this.getHeight( ) ) ; surface.restore( ) ; } ; EndingState.prototype._displayMessage = function( surface ) { surface.save( ) ; surface.font = '30pt Calibri' ; surface.textAlign = 'center' ; surface.fillStyle = 'rgb( 255, 255, 255 )' ; if( this.count >= 0 ) { surface.fillText( 'You\'ve done.', this.getWidth( ) / 2, 50 ) ; } if( this.count >= 100 ) { surface.fillText( 'And all was over.', this.getWidth( ) / 2, 100 ) ; } if( this.count >= 200 ) { surface.fillText( 'Thank you for the playing.', this.getWidth( ) / 2, 150 ) ; } surface.restore( ) ; } ; EndingState.prototype.handleKeyDown = function( e ) { } ; EndingState.prototype.handleKeyUp = function( e ) { } ; ================================================ FILE: source/Enemy.js ================================================ function EnemyManager( gameState, params ) { this.parent = ElementManager ; this.parent.call( this, gameState ) ; for( var i = 0; i < params.length; i++ ) { params[ i ].sort( function( a, b ) { return a.count - b.count ; } ) ; } this.params = params ; this.index = 0 ; this.stageIndex = 0 ; // TODO: temporal } ; __inherit( EnemyManager, ElementManager ) ; EnemyManager.prototype._MAX_NUM = 200; EnemyManager.prototype._initMaxNum = function() { return this._MAX_NUM; }; EnemyManager.prototype._initFactory = function( ) { this.factory = new EnemyFactory( this.gameState, this.gameState.getWidth( ), this.gameState.getHeight( ) ) ; } ; EnemyManager.prototype.initDrawer = function(layer, image) { this.drawer = new EnemyDrawer(this, layer, this.gameState.getImage(Game._IMG_ENEMY)); }; __copyParentMethod(EnemyManager, ElementManager, 'reset'); EnemyManager.prototype.reset = function() { this.ElementManager_reset(); this.index = 0; this.stageIndex = 0; }; EnemyManager.prototype.goNextStage = function() { this.ElementManager_reset(); this.index = 0; this.stageIndex++; }; __copyParentMethod(EnemyManager, ElementManager, 'runStep'); EnemyManager.prototype.runStep = function() { this._generateEnemy(); this.ElementManager_runStep(); }; EnemyManager.prototype._generateEnemy = function( ) { if(this.gameState.isBossExist()) return; while( this.index < this.params[ this.stageIndex ].length && this.params[ this.stageIndex ][ this.index ].count + this.gameState.pending <= this.gameState.count ) { if(! this.gameState.isBombExist()) this.addElement( this.factory.create( this.params[ this.stageIndex ][ this.index ] ) ) ; this.index++ ; } } ; __copyParentMethod(EnemyManager, ElementManager, 'checkCollisionWith'); EnemyManager.prototype.checkCollisionWith = function(fighter) { if(fighter.isFlagSet(fighter._FLAG_UNHITTABLE)) return; this.ElementManager_checkCollisionWith(null, fighter, this) }; EnemyManager.prototype.checkCollisionWithFighters = function(fighters) { for(var i = 0; i < fighters.length; i++) { this.checkCollisionWith(fighters[i]); } }; EnemyManager.prototype.notifyCollision = function(id, fighter, enemy) { fighter.die(); this.gameState.notifyFighterDead(fighter, enemy); }; /** * TODO: temporal */ EnemyManager.prototype.bomb = function( fighter ) { for( var i = 0; i < this.elements.length; i++ ) { this.elements[ i ].die( ) ; this.gameState.notifyEnemyVanished( null, this.elements[ i ] ) ; // TODO: null is ok? } } ; function EnemyFactory( gameState, maxX, maxY ) { this.parent = ElementFactory ; this.parent.call( this, gameState, maxX, maxY ) ; this.image = null; // TODO: temporal } ; __inherit( EnemyFactory, ElementFactory ) ; EnemyFactory.prototype._NUM = 200 ; EnemyFactory.prototype._initFreelist = function() { this.freelist = new EnemyFreeList(this._NUM, this.gameState); }; /** * */ EnemyFactory.prototype.create = function( params ) { var enemy = this.freelist.get( ) ; enemy.init( params, this._getImage( params ) ) ; return enemy ; } ; /** * TODO: temporal */ EnemyFactory.prototype._getImage = function(params) { if(this.image === null) this.image = this.gameState.getImage(Game._IMG_ENEMY); return this.image; }; function EnemyFreeList( num, gameState ) { this.parent = ElementFreeList ; this.parent.call( this, num, gameState ) ; } __inherit( EnemyFreeList, ElementFreeList ) ; EnemyFreeList.prototype._generateElement = function( ) { return new Enemy( this.gameState, this.gameState.getWidth( ), this.gameState.getHeight( ) ) ; } ; function EnemyDrawer(elementManager, layer, image) { this.parent = ElementDrawer; this.parent.call(this, elementManager, layer, image); }; __inherit(EnemyDrawer, ElementDrawer); function EnemyView(element) { this.parent = ElementView; this.parent.call(this, element); }; __inherit(EnemyView, ElementView); /** * no rotate. * TODO: no rotate impl should be in parent class? */ EnemyView.prototype.rotate = function() { }; EnemyView.prototype.doRotateForViewpoint = function() { return true; }; EnemyView.prototype.animate = function() { this._initCoordinates(); }; function Enemy( gameState, maxX, maxY ) { this.parent = Element ; this.parent.call( this, gameState, maxX, maxY ) ; this.shots = [ ] ; // TODO: temporal this.shotIndices = [ ] ; this.baseShotCounts = [ ] ; this.endShotCounts = [ ] ; this.vital = null ; this.powerItem = null ; this.lpowerItem = null ; this.scoreItem = null ; } __inherit( Enemy, Element ) ; Enemy.prototype._WIDTH = 32 ; Enemy.prototype._HEIGHT = 32 ; __copyParentMethod(Enemy, Element, 'init'); Enemy.prototype.init = function(params, image) { this.Element_init(params, image); // TODO: temporal this.shots.length = 0; if(params.s === void 0) { // } else if(params.s instanceof Array) { } else if(params.s.length !== void 0) { for(var i = 0; i < params.s.length; i++) this.shots[this.shots.length] = params.s[i]; } else { this.shots[this.shots.length] = params.s; } // TODO: temporal this.shotIndices.length = 0; this.baseShotCounts.length = 0; this.endShotCounts.length = 0; for(var i = 0; i < this.shots.length; i++) { this.shotIndices[this.shotIndices.length] = 0; if(this.shots[i].baseCount !== void 0) this.baseShotCounts[this.baseShotCounts.length] = this.shots[i].baseCount; else this.baseShotCounts[this.baseShotCounts.length] = 0; if(this.shots[i].endCount !== void 0) this.endShotCounts[this.endShotCounts.length] = this.shots[i].endCount; else this.endShotCounts[this.endShotCounts.length] = 0; } this.width = this._WIDTH; this.height = this._HEIGHT; this.collisionWidth = this.width; this.collisionHeight = this.height; this.vital = params.vital !== void 0 ? params.vital : 4; // TODO: temporal this.powerItem = params.powerItem !== void 0 ? params.powerItem : 0; this.lpowerItem = params.lpowerItem !== void 0 ? params.lpowerItem : 0; this.scoreItem = params.scoreItem !== void 0 ? params.scoreItem : 0; this._initView(); }; Enemy.prototype._generateView = function() { return new EnemyView(this); }; Enemy.prototype._shot = function( ) { if( this.shots.length == 0 ) return ; for( var i = 0; i < this.shots.length; i++ ) { if( this.shotIndices[ i ] >= this.shots[ i ].shotCount.length ) continue ; if( this.endShotCounts[ i ] && this.count >= this.endShotCounts[ i ] ) continue ; if( this.count >= this.shots[ i ].shotCount[ this.shotIndices[ i ] ] + this.baseShotCounts[ i ] ) { // TODO: temporal this.gameState.notifyEnemyDoShot( this, this.shots[ i ] ) ; this.shotIndices[ i ]++ ; if( this.shots[ i ].loop && this.shotIndices[ i ] >= this.shots[ i ].shotCount.length ) { this.shotIndices[ i ] = 0 ; this.baseShotCounts[ i ] = this.count ; } } } } ; // TODO: temporal __copyParentMethod(Enemy, Element, 'runStep'); Enemy.prototype.runStep = function() { this._shot(); this.Element_runStep(); // for animation if(this.count % 5 == 0) { this.indexX++; if(this.indexX > 2) this.indexX = 0; } }; // TODO: temporal Enemy.prototype.isVanishingOrEscaping = function() { return false; }; ================================================ FILE: source/EnemyBullet.js ================================================ function EnemyBulletManager( gameState, params ) { this.parent = ElementManager ; this.parent.call( this, gameState ) ; this.params = params ; this.index = 0 ; this.reservedLength = 0 ; // TODO: temporal this.reserved = [ ] ; // TODO: temporal this._initReserved( ) ; this.beamDrawer = null; // TODO: temporal } ; __inherit( EnemyBulletManager, ElementManager ) ; EnemyBulletManager.prototype._RESERVED_NUM = 50 ; // TODO: temporal EnemyBulletManager.prototype._MAX_NUM = 1000 ; // TODO: temporal EnemyBulletManager.prototype._initMaxNum = function() { return this._MAX_NUM; }; EnemyBulletManager.prototype._initFactory = function( ) { this.factory = new EnemyBulletFactory( this.gameState, this.gameState.getWidth( ), this.gameState.getHeight( ) ) ; } ; EnemyBulletManager.prototype.initDrawer = function(layer, image) { this.drawer = new EnemyBulletDrawer( this, layer, this.gameState.getImage(Game._IMG_ENEMY_SHOT)); this.beamDrawer = new EnemyBeamDrawer( this, layer, this.gameState.getImage(Game._IMG_BEAM)); }; /** * TODO: temporal. should implement reserved freelist? */ EnemyBulletManager.prototype._initReserved = function( ) { for( var i = 0; i < this._RESERVED_NUM; i++ ) { this.reserved.push( { 'enemy': null, 'index': 0, 'count': 0, 'shot' : null, 'array': null } ) ; } } ; __copyParentMethod(EnemyBulletManager, ElementManager, 'reset'); EnemyBulletManager.prototype.reset = function() { this.ElementManager_reset(); this.reservedLength = 0; this.index = 0; }; __copyParentMethod(EnemyBulletManager, ElementManager, 'runStep'); EnemyBulletManager.prototype.runStep = function() { this._shotReserved(); for(var i = 0; i < this.reservedLength; i++) this.reserved[ i ].count++; this.ElementManager_runStep(); }; /** * TODO: temporal. to make the logic straightforward. */ EnemyBulletManager.prototype._shotReserved = function( ) { for( var i = 0; i < this.reservedLength; i++ ) { if( this.reserved[ i ].enemy.isDead( ) ) continue ; while( this.reserved[ i ].index < this.reserved[ i ].array.length && this.reserved[ i ].count >= this.reserved[ i ].array[ this.reserved[ i ].index ].count ) { // TODO: temporal if(! this.gameState.isBombExist()) { this.addElement( this.factory.create( this.reserved[ i ].enemy, this.reserved[ i ].array[ this.reserved[ i ].index ], this.reserved[ i ].shot ) ) ; this.gameState.notifyEnemyDidShot( this.reserved[ i ].enemy, this.reserved[ i ].shot ) ; } this.reserved[ i ].index++ ; } } } ; EnemyBulletManager.prototype.create = function( enemy, shot ) { // TODO: temporal. to make reserved manager? if(this.params[shot.bullet][0].count !== void 0) { var r = this.reserved[ this.reservedLength ] ; r.enemy = enemy ; r.index = 0 ; r.count = 0 ; r.shot = shot ; r.array = this.params[ shot.bullet ] ; this.reservedLength++ ; return ; } for( var i = 0; i < this.params[ shot.bullet ].length; i++ ) { if(! this.gameState.isBombExist()) { this.addElement( this.factory.create( enemy, this.params[ shot.bullet ][ i ], shot ) ) ; this.gameState.notifyEnemyDidShot( enemy, shot ) ; } } } ; __copyParentMethod(EnemyBulletManager, ElementManager, 'checkLoss'); EnemyBulletManager.prototype.checkLoss = function( ) { this.ElementManager_checkLoss(); // TODO: temporal. to use freelist? var j = 0 ; for( var i = 0; i < this.reservedLength; i++ ) { if( ! this.reserved[ i ].enemy.isDead( ) && this.reserved[ i ].index < this.reserved[ i ].array.length ) { var tmp = this.reserved[ i - j ] ; this.reserved[ i - j ] = this.reserved[ i ] ; this.reserved[ i ] = tmp ; } else { j++ ; } } this.reservedLength -= j ; }; /** * TODO: temporal */ EnemyBulletManager.prototype.clearReserved = function( enemy ) { this.reservedLength = 0 ; } ; __copyParentMethod(EnemyBulletManager, ElementManager, 'checkCollisionWith'); EnemyBulletManager.prototype.checkCollisionWith = function(fighter) { if(fighter.isFlagSet(fighter._FLAG_UNHITTABLE)) return; this.ElementManager_checkCollisionWith(null, fighter, this, true); }; EnemyBulletManager.prototype.checkCollisionWithFighters = function(fighters) { for(var i = 0; i < fighters.length; i++) { this.checkCollisionWith(fighters[i]); } }; EnemyBulletManager.prototype.notifyCollision = function(id, fighter, bullet) { fighter.die(); this.gameState.notifyFighterDead(fighter, bullet); }; __copyParentMethod(EnemyBulletManager, ElementManager, 'checkGrazeWith'); EnemyBulletManager.prototype.checkGrazeWith = function(fighter) { this.ElementManager_checkGrazeWith(null, fighter, this); }; EnemyBulletManager.prototype.checkGrazeWithFighters = function(fighters) { for(var i = 0; i < fighters.length; i++) { this.checkGrazeWith(fighters[i]); } }; EnemyBulletManager.prototype.notifyGraze = function(id, fighter, bullet) { this.gameState.notifyGraze(fighter, bullet); }; /** * TODO: temporal */ EnemyBulletManager.prototype.bomb = function( fighter ) { for( var i = 0; i < this.elements.length; i++ ) { this.elements[ i ].die( ) ; this.gameState.notifyBeScoreItem(fighter, this.elements[i]); } } ; EnemyBulletManager.prototype.removeBulletsOfEnemy = function( enemy ) { for( var i = 0; i < this.elements.length; i++ ) { if( this.elements[ i ].enemy == enemy ) this.elements[ i ].die( ) ; } } ; EnemyBulletManager.prototype.beItem = function(fighter) { for( var i = 0; i < this.elements.length; i++ ) { this.elements[ i ].die( ) ; this.gameState.notifyBeScoreItem(fighter, this.elements[i]); } // TODO: temporal this.clearReserved( ) ; } ; EnemyBulletManager.prototype.draw = function(layer) { this.drawer.draw(layer); this.beamDrawer.draw(layer); }; function EnemyBulletFactory( gameState, maxX, maxY ) { this.parent = ElementFactory ; this.beamFreelist = null ; this.laserFreelist = null ; this.parent.call( this, gameState, maxX, maxY ) ; this.types = __enemyBulletTypes ; // TODO: temporal // TODO: temporal this.image = null; this.beamImage = null; } __inherit( EnemyBulletFactory, ElementFactory ) ; EnemyBulletFactory.prototype._NUM = 1000 ; EnemyBulletFactory.prototype._BEAM_NUM = 100 ; EnemyBulletFactory.prototype._LASER_NUM = 50 ; EnemyBulletFactory.prototype._initFreelist = function() { this.freelist = new EnemyBulletFreeList(this._NUM, this.gameState); this.beamFreelist = new EnemyBeamFreeList(this._BEAM_NUM, this.gameState); this.laserFreelist = new EnemyLaserFreeList(this._LASER_NUM, this.gameState); }; // TODO: temporal EnemyBulletFactory.prototype.create = function( enemy, params, shot ) { // TODO: temporal. How can I remove this save and restore. var preX = params.x ; var preY = params.y ; var preR = params.r ; var preBaseTheta = params.baseTheta ; params.r = shot.r ; params.baseTheta = shot.baseTheta ; params.x = ( params.x ? params.x : 0 ) + enemy.getX( ) + ( shot.x ? shot.x : 0 ) ; params.y = ( params.y ? params.y : 0 ) + enemy.getY( ) + ( shot.y ? shot.y : 0 ) ; var bullet ; if( params.beam ) { bullet = this.beamFreelist.get( ) ; bullet.init( params, this._getImage( params ), enemy ) ; } else if( params.laser ) { bullet = this.laserFreelist.get( ) ; bullet.init( params, this._getImage( params ), enemy ) ; } else { var key = shot.type ? shot.type : 0 ; bullet = this.freelist.get( ) ; bullet.init( params, this._getImage( params ), enemy, this.types[ key ] ) ; } params.x = preX ; params.y = preY ; params.r = preR ; params.baseTheta = preBaseTheta ; return bullet ; } ; EnemyBulletFactory.prototype.free = function(bullet) { switch(bullet._ID) { case this.EnemyBulletManager._ID_BULLET: this.freelist.free(bullet); return; case this.EnemyBulletManager._ID_LASER: this.laserFreelist.free(bullet); return; case this.EnemyBulletManager._ID_BEAM: this.beamFreelist.free(bullet); return; default: // throw exception? } }; /** * TODO: temporal */ EnemyBulletFactory.prototype._getImage = function(params) { if(params.beam) { if(this.beamImage === null) this.beamImage = this.gameState.getImage(Game._IMG_BEAM); return this.beamImage; } else { if(this.image === null) this.image = this.gameState.getImage(Game._IMG_ENEMY_SHOT); return this.image; } }; function EnemyBulletFreeList( num, gameState ) { this.parent = ElementFreeList ; this.parent.call( this, num, gameState ) ; } ; __inherit( EnemyBulletFreeList, ElementFreeList ) ; EnemyBulletFreeList.prototype._generateElement = function( ) { return new EnemyBullet( this.gameState, this.gameState.getWidth( ), this.gameState.getHeight( ) ) ; } ; function EnemyBulletDrawer(elementManager, layer, image) { this.parent = ElementDrawer; this.parent.call(this, elementManager, layer, image); }; __inherit(EnemyBulletDrawer, ElementDrawer); EnemyBulletDrawer.prototype._doPour = function(e) { return (e._ID === this.elementManager._ID_BEAM) ? false : true; }; function EnemyBulletView(element) { this.parent = ElementView; this.parent.call(this, element); }; __inherit(EnemyBulletView, ElementView); function EnemyBullet( gameState, maxX, maxY ) { this.parent = Element ; this.parent.call( this, gameState, maxX, maxY ) ; this.enemy = null ; this.rotate = false ; } __inherit( EnemyBullet, Element ) ; __copyParentMethod(EnemyBullet, Element, 'init'); EnemyBullet.prototype.init = function(params, image, enemy, params2) { this.Element_init(params, image); this.enemy = enemy; this.width = params2.width; this.height = params2.height; this.collisionWidth = params2.collisionWidth; this.collisionHeight = params2.collisionHeight; this.indexX = params2.indexX; this.indexY = params2.indexY; this.rotate = params2.rotate; this.grazeWidth = this.width; this.grazeHeight = this.height; this._initView(); }; EnemyBullet.prototype._generateView = function() { return new EnemyBulletView(this); }; EnemyBullet.prototype.display = function( surface ) { this.parent.prototype.display.call( this, surface, this.rotate ) ; } ; function EnemyLaserFreeList( num, gameState ) { this.parent = ElementFreeList ; this.parent.call( this, num, gameState ) ; } ; __inherit( EnemyLaserFreeList, ElementFreeList ) ; EnemyLaserFreeList.prototype._generateElement = function( ) { return new EnemyLaser( this.gameState, this.gameState.getWidth( ), this.gameState.getHeight( ) ) ; } ; function EnemyLaserView(element) { this.parent = ElementView; this.parent.call(this, element); }; __inherit(EnemyLaserView, ElementView); __copyParentMethod(EnemyLaserView, ElementView, '_initVertices'); EnemyLaserView.prototype._initVertices = function() { this.ElementView_initVertices(); this.vertices[1] = 0; this.vertices[4] = 0; this.vertices[7] *= 2; this.vertices[10] *= 2; }; __copyParentMethod(EnemyLaserView, ElementView, '_initCoordinates'); EnemyLaserView.prototype._initCoordinates = function() { this.ElementView_initCoordinates(); // TODO: temporal. var s = 0.01; var h = this.element.getWidth()/this.element.getImageHeight(); var y1 = h * this.element.getImageIndexY(); var y2 = y1 + h - s; this.coordinates[1] = y2; this.coordinates[3] = y2; this.coordinates[5] = y1; this.coordinates[7] = y1; }; /** * TODO: should be in EnemyLaser? */ EnemyLaserView.prototype.animate = function() { var w = this.element.getWidth()/2; if(this.element.count < this.element.waitCount) { w = w * this.element.count / this.element.waitCount ; this.a = 0.2; } else if (this.element.inExtendTime()) { w = w * (this.element.keepAlive + this.element._EXTEND_COUNT - this.element.count) / this.element._EXTEND_COUNT; this.a = 0.2; } else { this.a = 0.8; } this.vertices[0] = -w; this.vertices[3] = w; this.vertices[6] = w; this.vertices[9] = -w; }; /** * TODO: temporal */ function EnemyLaser( gameState, maxX, maxY ) { this.parent = Element ; this.parent.call( this, gameState, maxX, maxY ) ; this.baseX = 0 ; this.baseY = 0 ; } __inherit( EnemyLaser, Element ) ; // only for reference EnemyLaser.prototype.Math = Math; // TODO: temporal EnemyLaser.prototype._WIDTH = 16; EnemyLaser.prototype._HEIGHT = 400 * 2; EnemyLaser.prototype._EXTEND_COUNT = 20; __copyParentMethod(EnemyLaser, Element, 'init'); EnemyLaser.prototype.init = function(params, image, enemy) { this.Element_init(params, image); this.enemy = enemy; this.width = this._WIDTH; this.height = this._HEIGHT; this.collisionWidth = this.width; this.collisionHeight = this.height; this.waitCount = this._getValueOrDefaultValue(params.waitCount, 0); this.keepAlive = this._getValueOrDefaultValue(params.keep, 0); this.baseX = this.Math.round(enemy.getX()); this.baseY = this.Math.round(enemy.getY()); this.indexX = 15; this.indexY = 0; this._initView(); }; EnemyLaser.prototype._generateView = function() { return new EnemyLaserView(this); }; /** * TODO: temporal */ EnemyLaser.prototype.display = function( surface ) { surface.save( ) ; var width = this.getWidth( ) ; if( this.count < this.waitCount ) { width = width * this.count / this.waitCount ; surface.globalAlpha = 0.2 ; } else if ( this.count + 10 > this.keepAlive ) { width = width * ( 10 - this.count + this.keepAlive ) / 10 ; surface.globalAlpha = 0.2 ; } else { surface.globalAlpha = 0.8 ; } var x = Math.round( this.getCenterX( ) ) ; var y = Math.round( this.getCenterY( ) - width / 2 ) ; surface.translate( this.baseX, this.baseY ) ; surface.rotate( this._calculateRadian( this.vector.theta ) ) ; surface.translate( -this.baseX, -this.baseY ) ; surface.drawImage( this.image, this.getWidth( ) * this.indexX, this.height * this.indexY, this.getWidth( ), this.getWidth( ), x, y, this.height, width ) ; surface.restore( ) ; // surface.fillText( x + ':' + y, x, y ) ; } ; EnemyLaser.prototype._getTheta = function( ) { return this._calculateRadian( this.vector.theta ) ; } ; EnemyLaser.prototype.getUpLeftX = function( ) { return this.getCenterX( ) - ( this.getWidth( ) / 2 ) * this.Math.cos( this._getTheta( ) ) ; } ; EnemyLaser.prototype.getUpLeftY = function( ) { return this.getCenterY( ) - ( this.getWidth( ) / 2 ) * this.Math.sin( this._getTheta( ) ) ; } ; EnemyLaser.prototype.getUpRightX = function( ) { return this.getCenterX( ) + ( this.getWidth( ) / 2 ) * this.Math.cos( this._getTheta( ) ) ; } ; EnemyLaser.prototype.getUpRightY = function( ) { return this.getCenterY( ) + ( this.getWidth( ) / 2 ) * this.Math.sin( this._getTheta( ) ) ; } ; EnemyLaser.prototype.getBottomLeftX = function( ) { return this.getUpLeftX( ) + this.getHeight( ) * this.Math.cos( this._getTheta( ) ) ; } ; EnemyLaser.prototype.getBottomLeftY = function( ) { return this.getUpLeftY( ) + this.getHeight( ) * this.Math.sin( this._getTheta( ) ) ; } ; EnemyLaser.prototype.getBottomRightX = function( ) { return this.getUpRightX( ) + this.getHeight( ) * this.Math.cos( this._getTheta( ) ) ; } ; EnemyLaser.prototype.getBottomRightY = function( ) { return this.getUpRightY( ) + this.getHeight( ) * this.Math.sin( this._getTheta( ) ) ; } ; EnemyLaser.prototype.getCollisionUpLeftX = function( ) { return this.getCenterX( ) - ( this.collisionWidth / 2 ) * this.Math.sin( this._getTheta( ) ) ; } ; EnemyLaser.prototype.getCollisionUpLeftY = function( ) { return this.getCenterY( ) + ( this.collisionWidth / 2 ) * this.Math.cos( this._getTheta( ) ) ; } ; EnemyLaser.prototype.getCollisionUpRightX = function( ) { return this.getCenterX( ) + ( this.collisionWidth / 2 ) * this.Math.sin( this._getTheta( ) ) ; } ; EnemyLaser.prototype.getCollisionUpRightY = function( ) { return this.getCenterY( ) - ( this.collisionWidth / 2 ) * this.Math.cos( this._getTheta( ) ) ; } ; EnemyLaser.prototype.getCollisionBottomLeftX = function( ) { return this.getCollisionUpLeftX( ) + this.collisionHeight * this.Math.cos( this._getTheta( ) ) ; } ; EnemyLaser.prototype.getCollisionBottomLeftY = function( ) { return this.getCollisionUpLeftY( ) + this.collisionHeight * this.Math.sin( this._getTheta( ) ) ; } ; EnemyLaser.prototype.getCollisionBottomRightX = function( ) { return this.getCollisionUpRightX( ) + this.collisionHeight * this.Math.cos( this._getTheta( ) ) ; } ; EnemyLaser.prototype.getCollisionBottomRightY = function( ) { return this.getCollisionUpRightY( ) + this.collisionHeight * this.Math.sin( this._getTheta( ) ) ; } ; EnemyLaser.prototype.inCollisionArea = function( x, y ) { if(this.inExtendTime() || this.overExtendTime()) return false; if(! this._inCollisionTheta( this.getCollisionUpRightX(), this.getCollisionUpRightY(), x, y, this.getCollisionUpLeftX(), this.getCollisionUpLeftY() )) return false; if(! this._inCollisionTheta( this.getCollisionBottomLeftX(), this.getCollisionBottomLeftY(), x, y, this.getCollisionBottomRightX(), this.getCollisionBottomRightY() )) return false; return true; }; EnemyLaser.prototype._inCollisionTheta = function( x1, y1, x2, y2, baseX, baseY ) { var ax1 = x1 - baseX ; var ax2 = x2 - baseX ; var ay1 = y1 - baseY ; var ay2 = y2 - baseY ; var t = this._calculateTheta( this.Math.atan2( ax1 * ay2 - ax2 * ay1, ax1 * ax2 + ay1 * ay2 ) ) ; if( t >= 0 && t <= 90 ) return true ; return false ; } ; EnemyLaser.prototype.inViewArea = function( x, y ) { return false ; } ; EnemyLaser.prototype.checkViewCollision = function( e ) { return false ; } ; /** * TODO: temporal */ EnemyLaser.prototype.checkLoss = function() { if(this.isDead()) return true; if(this.overExtendTime()) return true; return false; }; EnemyLaser.prototype.inExtendTime = function() { if(this.keepAlive && this.count >= this.keepAlive && this.count < this.keepAlive + this._EXTEND_COUNT) return true; return false; }; EnemyLaser.prototype.overExtendTime = function() { if(this.keepAlive && this.count >= this.keepAlive + this._EXTEND_COUNT) return true; return false; }; function EnemyBeamFreeList(num, gameState) { this.parent = ElementFreeList; this.hFreelist = new EnemyBeamHistoryFreeList(this._HISTORY_NUM); this.pFreelist = new EnemyBeamPositionFreeList(this._HISTORY_NUM); this.parent.call(this, num, gameState); }; __inherit(EnemyBeamFreeList, ElementFreeList); EnemyBeamFreeList.prototype._HISTORY_NUM = 1000; EnemyBeamFreeList.prototype._generateElement = function( ) { return new EnemyBeam( this.gameState, this.gameState.getWidth( ), this.gameState.getHeight( ), this.hFreelist, this.pFreelist ) ; } ; function EnemyBeamDrawer(elementManager, layer, image) { this.parent = ElementDrawer; this.parent.call(this, elementManager, layer, image); }; __inherit(EnemyBeamDrawer, ElementDrawer); EnemyBeamDrawer.prototype._doPour = function(e) { return (e._ID === this.elementManager._ID_BEAM) ? true : false; }; function EnemyBeamView(element) { this.parent = ElementView; this.parent.call(this, element); // TODO: temporal this.vertices.length = this._V_SIZE * element.historyMax; this.coordinates.length = this._C_SIZE * element.historyMax; this.indices.length = this._I_SIZE * element.historyMax; this.colors.length = this._A_SIZE * element.historyMax; this.sVertices.length = this._V_SIZE * element.historyMax; }; __inherit(EnemyBeamView, ElementView); /** * TODO: temporal. */ EnemyBeamView.prototype.getNum = function() { return this.element.p.length; }; EnemyBeamView.prototype._initVertices = function() { for(var i = 0; i < this.element.p.length; i++) { var p = this.element.p[i]; var o = this._V_SIZE * i; this.vertices[o+0] = p.x0; this.vertices[o+1] = -p.y0; this.vertices[o+2] = -1.0; this.vertices[o+3] = p.x1; this.vertices[o+4] = -p.y1; this.vertices[o+5] = -1.0; this.vertices[o+6] = p.x3; this.vertices[o+7] = -p.y3; this.vertices[o+8] = -1.0; this.vertices[o+9] = p.x2; this.vertices[o+10] = -p.y2; this.vertices[o+11] = -1.0; } }; EnemyBeamView.prototype._initCoordinates = function() { // TODO: temporal var w = this.element.imageWidth/this.element.getImageWidth(); var h = this.element.imageHeight/this.element.getImageHeight(); var x1 = w * this.element.getImageIndexX(); var x2 = x1 + w; var y = h * this.element.getImageIndexY(); var dy = h / this.element.p.length; for(var i = 0; i < this.element.p.length; i++) { var o = this._C_SIZE * i; var y1 = y + dy * i; var y2 = y + dy * (i+1); // y order is reversed from the normal one. this.coordinates[o+0] = x1; this.coordinates[o+1] = y1; this.coordinates[o+2] = x2; this.coordinates[o+3] = y1; this.coordinates[o+4] = x2; this.coordinates[o+5] = y2; this.coordinates[o+6] = x1; this.coordinates[o+7] = y2; } }; EnemyBeamView.prototype._initIndices = function() { for(var i = 0; i < this.element.p.length; i++) { var o = this._I_SIZE * i; this.indices[o+0] = 0; this.indices[o+1] = 1; this.indices[o+2] = 2; this.indices[o+3] = 0; this.indices[o+4] = 2; this.indices[o+5] = 3; } }; EnemyBeamView.prototype._initColors = function() { for(var i = 0; i < this.element.p.length; i++) { var o = this._A_SIZE * i; this.colors[o+0] = 1.0; this.colors[o+1] = 1.0; this.colors[o+2] = 1.0; this.colors[o+3] = 1.0; this.colors[o+4] = 1.0; this.colors[o+5] = 1.0; this.colors[o+6] = 1.0; this.colors[o+7] = 1.0; this.colors[o+8] = 1.0; this.colors[o+9] = 1.0; this.colors[o+10] = 1.0; this.colors[o+11] = 1.0; this.colors[o+12] = 1.0; this.colors[o+13] = 1.0; this.colors[o+14] = 1.0; this.colors[o+15] = 1.0; } }; /** * unnecessary to translate cuz it's already done in EnemyBeam. */ EnemyBeamView.prototype.translate = function() { }; /** * unnecessary to rotate cuz it's already done in EnemyBeam. */ EnemyBeamView.prototype.rotate = function() { }; /** * unnecessary to save vertices cuz translate() and rotate() do nothing. */ EnemyBeamView.prototype.saveVertices = function() { }; /** * unnecessary to restore vertices cuz translate() and rotate() do nothing. */ EnemyBeamView.prototype.restoreVertices = function() { }; EnemyBeamView.prototype.animate = function() { this._initVertices(); this._initCoordinates(); this._initIndices(); this._initColors(); this.a = 0.9; }; /** * TODO: temporal * TODO: add histories, p, hFreelist and pFreelist descriptions. * TODO: implement checkColision(). */ function EnemyBeam(gameState, maxX, maxY, hFreelist, pFreelist) { this.histories = []; this.p = []; this.hFreelist = hFreelist; this.pFreelist = pFreelist; this.historyMax = this._HISTORY_MAX; this.parent = Element; this.parent.call(this, gameState, maxX, maxY); this.imageWidth = this._IMAGE_WIDTH; this.imageHeight = this._IMAGE_HEIGHT; } __inherit(EnemyBeam, Element); // only for reference EnemyBeam.prototype.Math = Math; EnemyBeam.prototype._WIDTH = 16; EnemyBeam.prototype._HEIGHT = 16; EnemyBeam.prototype._IMAGE_WIDTH = 20; EnemyBeam.prototype._IMAGE_HEIGHT = 256; EnemyBeam.prototype._HISTORY_MAX = 16; EnemyBeam.prototype._SPAN = 1; EnemyBeam.prototype._generateView = function() { return new EnemyBeamView(this); }; __copyParentMethod(EnemyBeam, Element, 'free'); EnemyBeam.prototype.free = function() { this._freeHistoriesUntil(0); this._freePositionsUntil(0); this.Element_free(); }; EnemyBeam.prototype._freeHistoriesUntil = function(num) { while(this.histories.length > num) { this.hFreelist.free(this.histories[this.histories.length-1]) ; this.histories.length--; } }; EnemyBeam.prototype._freePositionsUntil = function(num) { while(this.p.length > num){ this.pFreelist.free(this.p[this.p.length-1]); this.p.length--; } }; __copyParentMethod(EnemyBeam, Element, 'init'); EnemyBeam.prototype.init = function(params, image, enemy) { this.Element_init(params, image); this.enemy = enemy; // TODO: temporal this.width = this._WIDTH; this.height = this._HEIGHT; this.collisionWidth = this.width; this.collisionHeight = this.height; this.indexX = 1; this.indexY = 0; this.histories.length = 0; this.p.length = 0; this._initView(); }; __copyParentMethod(EnemyBeam, Element, 'runStep'); EnemyBeam.prototype.runStep = function() { this.Element_runStep(); if((this.count % this._SPAN) == 0) { this._addHistory(); this._freeHistoriesUntil(this.historyMax); this._freePositionsUntil(this.historyMax); } }; EnemyBeam.prototype._addHistory = function() { var h = this.hFreelist.get(); h.x = this.getX(); h.y = this.getY(); if(this.histories.length > 0) { var x1 = h.x; var y1 = h.y; var x2 = this.histories[0].x; var y2 = this.histories[0].y; var dx = x1 - x2; var dy = y1 - y2; var rad = this.Math.atan2(dy, dx); var p = this.pFreelist.get(); p.x0 = x1 - this.width/2 * this.Math.sin(rad); p.y0 = y1 + this.width/2 * this.Math.cos(rad); p.x1 = x1 + this.width/2 * this.Math.sin(rad); p.y1 = y1 - this.width/2 * this.Math.cos(rad); p.x2 = x2 - this.width/2 * this.Math.sin(rad); p.y2 = y2 + this.width/2 * this.Math.cos(rad); p.x3 = x2 + this.width/2 * this.Math.sin(rad); p.y3 = y2 - this.width/2 * this.Math.cos(rad); if(this.p.length > 0) { this.p[0].x0 = p.x2; this.p[0].y0 = p.y2; this.p[0].x1 = p.x3; this.p[0].y1 = p.y3; } this.p.unshift(p); } this.histories.unshift(h); }; /** * TODO: temporal, make this function fast. */ EnemyBeam.prototype.display = function( surface ) { var height = this.imageHeight / this.histories.length ; var width = this.imageWidth ; var p = this.p ; for( var i = 0; i < this.histories.length - 1; i++ ) { var by = height * i ; surface.save( ) ; /* surface.beginPath( ) ; surface.strokeStyle = 'white' ; surface.moveTo( p[ i ].x0, p[ i ].y0 ) ; surface.lineTo( p[ i ].x1, p[ i ].y1 ) ; surface.lineTo( p[ i ].x3, p[ i ].y3 ) ; surface.lineTo( p[ i ].x2, p[ i ].y2 ) ; surface.closePath( ) ; surface.clip( ) ; // surface.stroke( ) ; */ var t1 = ( p[ i ].x1 - p[ i ].x0 ) / width ; var t2 = ( p[ i ].y1 - p[ i ].y0 ) / width ; var t3 = ( p[ i ].x2 - p[ i ].x0 ) / height ; var t4 = ( p[ i ].y2 - p[ i ].y0 ) / height ; var t5 = p[ i ].x0 ; var t6 = p[ i ].y0 ; surface.setTransform( t1, t2, t3, t4, t5, t6 ) ; surface.globalAlpha = 0.5 ; surface.drawImage( this.image, width, by, width, height, 0, 0, width, height ) ; surface.restore( ) ; surface.save( ) ; /* surface.beginPath( ) ; surface.strokeStyle = 'white' ; surface.moveTo( p[ i ].x1, p[ i ].y1 ) ; surface.lineTo( p[ i ].x2, p[ i ].y2 ) ; surface.lineTo( p[ i ].x3, p[ i ].y3 ) ; surface.closePath( ) ; surface.clip( ) ; // surface.stroke( ) ; */ var t1 = ( p[ i ].x3 - p[ i ].x2 ) / width ; var t2 = ( p[ i ].y3 - p[ i ].y2 ) / width ; var t3 = ( p[ i ].x3 - p[ i ].x1 ) / height ; var t4 = ( p[ i ].y3 - p[ i ].y1 ) / height; var t5 = p[ i ].x2 ; var t6 = p[ i ].y2 ; surface.setTransform( t1, t2, t3, t4, t5, t6 ) ; surface.globalAlpha = 0.5 ; surface.drawImage( this.image, width, by, width, height, 0, 0, width, -height ) ; surface.restore( ) ; } } ; /** * TODO: temporal */ EnemyBeam.prototype._outOfTheField = function( ) { var x = this.histories[ this.histories.length - 1 ].x ; var y = this.histories[ this.histories.length - 1 ].y ; if( x < 0 || x > this.maxX || y < 0 || y > this.maxY ) return true ; return false ; } ; function EnemyBeamHistoryFreeList( num ) { FreeList.call( this, num ) ; } __inherit( EnemyBeamHistoryFreeList, FreeList ) ; EnemyBeamHistoryFreeList.prototype._generateElement = function( ) { return { 'x0': 0.0, 'y0': 0.0, 'x1': 0.0, 'y1': 0.0, 'x2': 0.0, 'y2': 0.0, 'x3': 0.0, 'y3': 0.0 } ; } ; function EnemyBeamPositionFreeList( num ) { FreeList.call( this, num ) ; } __inherit( EnemyBeamPositionFreeList, FreeList ) ; EnemyBeamPositionFreeList.prototype._generateElement = function( ) { return { 'x': 0.0, 'y': 0.0 } ; } ; // TODO: remove the followings because they complicate the design. EnemyBulletManager.prototype._ID_BULLET = 0; EnemyBulletManager.prototype._ID_LASER = 1; EnemyBulletManager.prototype._ID_BEAM = 2; EnemyBulletFactory.prototype.EnemyBulletManager = EnemyBulletManager.prototype; EnemyBullet.prototype._ID = EnemyBulletManager.prototype._ID_BULLET; EnemyLaser.prototype._ID = EnemyBulletManager.prototype._ID_LASER; EnemyBeam.prototype._ID = EnemyBulletManager.prototype._ID_BEAM; ================================================ FILE: source/Fighter.js ================================================ /** * care for two players in the future. */ function FighterManager(gameState) { this.parent = ElementManager; this.parent.call(this, gameState); this.id = 0; this._init(); }; __inherit(FighterManager, ElementManager); FighterManager.prototype._MAX_NUM = 2; FighterManager.prototype.Randomizer = __randomizer; FighterManager.prototype.Math = Math; FighterManager.prototype._initMaxNum = function() { return this._MAX_NUM; }; /** * Note: not return the resouces to freelist. */ FighterManager.prototype.reset = function() { for(var i = 0; i < this.elements.length; i++) { this.elements[i].reset(); this.elements[i].beDefaultPosition(); } this.count = 0; }; FighterManager.prototype.recoverWhenContinue = function() { for(var i = 0; i < this.elements.length; i++) { this.elements[i].recoverWhenContinue(); } }; FighterManager.prototype.beNeutral = function() { for(var i = 0; i < this.elements.length; i++) { this.elements[i].beNeutral(); } }; FighterManager.prototype.getFighter = function() { return this.get(0); }; FighterManager.prototype.getRandom = function() { return this.get((this.Randomizer.random() * this.elements.length) | 0); }; FighterManager.prototype.getMe = function(isMaster) { return this.get(isMaster ? 0 : 1); }; FighterManager.prototype.getOther = function(isMaster) { return this.get(isMaster ? 1 : 0); }; FighterManager.prototype._init = function() { this.add(this._createFighter()); this.get(0).beDefaultPosition(); if(this.gameState.isMultiPlay()) { this.add(this._createFighter()); this.get(1).beDefaultPosition(); } }; FighterManager.prototype._createFighter = function() { return new Fighter(this.gameState, this.gameState.getWidth(), this.gameState.getHeight(), this._getImage(), this.id++); }; /** * unnecessary. */ FighterManager.prototype._initFactory = function() { }; FighterManager.prototype.initDrawer = function(layer, image) { this.drawer = new FighterDrawer(this, layer, this._getImage()); }; FighterManager.prototype._getImage = function() { return this.gameState.getImage(Game._IMG_FIGHTER); }; // TODO: duplicated code. // TODO: check Active numbers FighterManager.prototype.getClosestFighter = function(e) { var target = this.get(0); if(this.elements.length <= 1) return target; var min = 1024 * 1024; // TODO: temporal for(var i = 0; i < this.elements.length; i++) { var f = this.get(i); var d = this.Math.pow(f.getX() - e.getX(), 2) + this.Math.pow(f.getY() - e.getY(), 2); if(d < min) { min = d; target = f; } } return target; }; function FighterDrawer(elementManager, layer, image) { this.parent = ElementDrawer; this.parent.call(this, elementManager, layer, image); }; __inherit(FighterDrawer, ElementDrawer); /** * TODO: consider if should make Reimu/Marisa View. */ function FighterView(element) { this.parent = ElementView; this.parent.call(this, element); }; __inherit(FighterView, ElementView); /** * no rotate. * TODO: no rotate impl should be in parent class? */ FighterView.prototype.rotate = function() { }; FighterView.prototype.animate = function() { this._initCoordinates(); // TODO: temporal this.a = this.element.isFlagSet(this.element._FLAG_UNHITTABLE) || this.element.gameState.doLookAtFromViewpointTarget() ? 0.7 : 1.0; }; FighterView.prototype.doRotateForViewpoint = function() { return true; }; function Fighter(gameState, maxX, maxY, image, id) { this.id = id; this.characterIndex = 0; // TODO: temporal this.parent = Element; this.parent.call(this, gameState, maxX, maxY); this.image = image; this.width = this._WIDTH; this.height = this._HEIGHT; this.collisionWidth = this._COLLISION_WIDTH[this.characterIndex]; this.collisionHeight = this._COLLISION_HEIGHT[this.characterIndex]; this.grazeWidth = this.width; this.grazeHeight = this.height; this.power = 0; this.powerLevel = 0; this.deadCount = 0; this.spellCard = 'Special Spell'; // TODO: temporary this.setFlag(this._FLAG_UNHITTABLE); this.options = []; this._initView(); }; __inherit(Fighter, Element); // TODO: temporal Fighter.prototype._REIMU = 0 ; Fighter.prototype._MARISA = 1 ; // TODO: prameters should be in parameter .js file. Fighter.prototype._SHIP_IMAGE = [ Game._IMG_REIMU_SHIP, Game._IMG_MARISA_SHIP ] ; Fighter.prototype._SPAN_FAST = [ 4, 5 ] ; Fighter.prototype._SPAN_SLOW = [ 3, 4 ] ; Fighter.prototype._COLLISION_WIDTH = [ 4, 6 ] ; Fighter.prototype._COLLISION_HEIGHT = [ 4, 6 ] ; Fighter.prototype._FLAG_SLOW = 0x1000 ; Fighter.prototype._UNHITABLE_COUNT = 100 ; Fighter.prototype._WIDTH = 32 ; Fighter.prototype._HEIGHT = 48 ; Fighter.prototype._ANIMATION_SPAN = 2 ; Fighter.prototype.reset = function( ) { this.state = this._STATE_ALIVE ; this.flags = 0 ; this.setFlag( this._FLAG_UNHITTABLE ) ; this.power = 0 ; this.powerLevel = 0 ; this.deadCount = 0 ; this.count = 0 ; this.indexX = 0 ; this.indexY = 0 ; } ; Fighter.prototype._generateView = function() { return new FighterView(this); }; Fighter.prototype.beDefaultPosition = function( ) { this.setX( parseInt( this.maxX / 2 ) ) ; this.setY( this.maxY - 100 ) ; } ; Fighter.prototype.display = function( surface ) { if( this.isFlagSet( this._FLAG_UNHITTABLE ) ) surface.globalAlpha = 0.7 ; // surface.save( ) ; this.parent.prototype.display.call( this, surface ) ; if( this.isFlagSet( this._FLAG_UNHITTABLE ) ) surface.globalAlpha = 1.0 ; // surface.restore( ) ; } ; /** * TODO: temporal */ Fighter.prototype._setDirection = function( ) { if( ( ! this.isFlagSet( this._FLAG_MOVE_LEFT ) && ! this.isFlagSet( this._FLAG_MOVE_RIGHT ) ) || ( this.isFlagSet( this._FLAG_MOVE_LEFT ) && this.isFlagSet( this._FLAG_MOVE_RIGHT ) ) ) { this.indexY = 0 ; } else if( this.isFlagSet( this._FLAG_MOVE_LEFT ) ) { this.indexY = 1 ; this.indexX = 7 ; } else if( this.isFlagSet( this._FLAG_MOVE_RIGHT ) ) { this.indexY = 2 ; this.indexX = 7 ; } } ; Fighter.prototype.move = function( ) { this._setDirection( ) ; var d = this.isFlagSet( this._FLAG_SLOW ) ? this._SPAN_SLOW[ this.characterIndex ] : this._SPAN_FAST[ this.characterIndex ] ; // TODO: temporal if( this.isFlagSet( this._FLAG_MOVE_LEFT ) ) { this.x -= d ; } if( this.isFlagSet( this._FLAG_MOVE_DOWN ) ) { this.y += d ; } if( this.isFlagSet( this._FLAG_MOVE_RIGHT ) ) { this.x += d ; } if( this.isFlagSet( this._FLAG_MOVE_UP ) ) { this.y -= d ; } this._beInTheField( ) ; } ; Fighter.prototype.Element_runStep = Element.prototype.runStep; Fighter.prototype.runStep = function( ) { if( this.isFlagSet( this._FLAG_UNHITTABLE ) && this.count > this._UNHITABLE_COUNT + this.deadCount ) { this.clearFlag( this._FLAG_UNHITTABLE ) ; } this._shot( ) ; this.Element_runStep(); if( this.count % this._ANIMATION_SPAN == 0 ) { this.indexX++ ; if( ! this.indexY && this.indexX > 7 ) this.indexX = 0 ; else if( this.indexY && this.indexX > 7 ) this.indexX = 4 ; } } ; Fighter.prototype._shot = function( ) { if( this.isFlagSet( this._FLAG_SHOT ) ) this.gameState.notifyFighterDoShot( this ) ; } ; Fighter.prototype.getBulletIndex = function( ) { return this.isFlagSet( this._FLAG_SLOW ) ? 1 : 0 ; } ; Fighter.prototype.setCharacterIndex = function(index) { this.characterIndex = index; this._updateFighterInfoDependingCharacterIndex(); }; /** * TODO: temporal */ Fighter.prototype.changeCharacter = function( ) { this.characterIndex++ ; if( this.characterIndex > 1 ) this.characterIndex = 0 ; this._updateFighterInfoDependingCharacterIndex( ) ; } ; Fighter.prototype._updateFighterInfoDependingCharacterIndex = function() { this.collisionWidth = this._COLLISION_WIDTH[ this.characterIndex ]; this.collisionHeight = this._COLLISION_HEIGHT[ this.characterIndex ]; }; Fighter.prototype._initVector = function( ) { } ; /** * TODO: temporal */ Fighter.prototype.getPower = function( ) { return this.power ; } ; /** * TODO: temporal */ Fighter.prototype.getPowerLevel = function( ) { return this.powerLevel > 3 ? 3 : this.powerLevel; } ; Fighter.prototype._calculatePowerLevel = function( power ) { if( this.power < 8 ) return 0 ; if( this.power < 16 ) return 1 ; if( this.power < 32 ) return 2 ; if( this.power < 48 ) return 3 ; if( this.power < 64 ) return 4 ; if( this.power < 80 ) return 5 ; if( this.power < 96 ) return 6 ; if( this.power < 128 ) return 7 ; return 8 ; } ; /** * TODO: temporal */ Fighter.prototype.hasOption = function( ) { return this.getPowerLevel( ) > 0 ? true : false ; } ; Fighter.prototype.addOption = function(option) { this.options.push(option); }; Fighter.prototype.getOption = function(index) { return this.options[index]; }; /** * TODO: temporal */ Fighter.prototype.incrementPower = function( num ) { var prePowerLevel = this._calculatePowerLevel( this.power ) ; this.power += num ; if( this.power > 128 ) { this.power = 128 ; return false ; } this.powerLevel = this._calculatePowerLevel( this.power ) ; if( this.powerLevel > prePowerLevel ) this.gameState.notifyFighterPowerUp( ) ; } ; Fighter.prototype.beNeutral = function( ) { this.clearFlag( this._FLAG_SLOW ) ; this.clearFlag( this._FLAG_MOVE_LEFT ) ; this.clearFlag( this._FLAG_MOVE_UP ) ; this.clearFlag( this._FLAG_MOVE_RIGHT ) ; this.clearFlag( this._FLAG_MOVE_DOWN ) ; this.clearFlag( this._FLAG_SHOT ) ; } ; /** * TODO: temporal. bad design. */ Fighter.prototype.Element_getImageIndexY = Element.prototype.getImageIndexY; Fighter.prototype.getImageIndexY = function() { return this.Element_getImageIndexY() + this.characterIndex * 3; }; Fighter.prototype.recoverWhenContinue = function() { this.state = this._STATE_ALIVE; this.setX((this.gameState.getWidth() / 2) | 0); this.setY(this.gameState.getHeight() - 100); }; Fighter.prototype.getID = function() { return this.id; }; ================================================ FILE: source/FighterOption.js ================================================ function FighterOptionManager(gameState, fighters) { this.parent = ElementManager; this.parent.call(this, gameState); this.fighters = fighters; this._init(); }; __inherit(FighterOptionManager, ElementManager); FighterOptionManager.prototype._MAX_NUM = 4; FighterOptionManager.prototype._PARAMS = []; FighterOptionManager.prototype._PARAMS[0] = { 'r': 32, 'angle': 180, 'theta': 180, 'd': 1, 'trange': {'min': 180, 'max': 250} }; FighterOptionManager.prototype._PARAMS[1] = { 'r': 32, 'angle': 0, 'theta': 360, 'd': -1, 'trange': {'min': 290, 'max': 360} }; FighterOptionManager.prototype._initMaxNum = function() { return this._MAX_NUM; }; FighterOptionManager.prototype._init = function() { // TODO: move these parameters to outside. for(var i = 0; i < this.fighters.length; i++) { var fighter = this.fighters[i]; this.create(fighter, this._PARAMS[0]); this.create(fighter, this._PARAMS[1]); } }; /** * keeps the elements even it resets. * TODO: unstraightforward. */ FighterOptionManager.prototype.reset = function() { for(var i = 0; i < this.elements.length; i++) { this.elements[i].reset(this._PARAMS[i%2]); } this.count = 0 ; }; FighterOptionManager.prototype._initFactory = function( ) { this.factory = new FighterOptionFactory( this.gameState, this.gameState.getWidth( ), this.gameState.getHeight( ) ) ; } ; FighterOptionManager.prototype.initDrawer = function(layer, image) { this.drawer = new FighterOptionDrawer(this, layer, this._getImage()); }; /** * TODO: consider who should manage image. */ FighterOptionManager.prototype._getImage = function() { return this.gameState.getImage(Game._IMG_FIGHTER_OPTION); }; FighterOptionManager.prototype.create = function(fighter, params) { var o = this.factory.create(fighter, params, this._getImage()); fighter.addOption(o); this.addElement(o); }; function FighterOptionFactory( gameState, maxX, maxY ) { this.parent = ElementFactory ; this.parent.call( this, gameState, maxX, maxY ) ; } ; __inherit( FighterOptionFactory, ElementFactory ) ; FighterOptionFactory.prototype._NUM = 10 ; FighterOptionFactory.prototype._initFreelist = function( ) { this.freelist = new FighterOptionFreeList( this._NUM, this.gameState ) ; } ; /** * */ FighterOptionFactory.prototype.create = function(fighter, params, image) { var option = this.freelist.get(); option.init(params, image, fighter); return option; }; function FighterOptionFreeList( num, gameState ) { this.parent = ElementFreeList ; this.parent.call( this, num, gameState ) ; } ; __inherit( FighterOptionFreeList, ElementFreeList ) ; FighterOptionFreeList.prototype._generateElement = function( ) { return new FighterOption( this.gameState, this.gameState.getWidth( ), this.gameState.getHeight( ) ) ; } ; function FighterOptionDrawer(elementManager, layer, image) { this.parent = ElementDrawer; this.parent.call(this, elementManager, layer, image); }; __inherit(FighterOptionDrawer, ElementDrawer); function FighterOptionView(element) { this.parent = ElementView; this.parent.call(this, element); }; __inherit(FighterOptionView, ElementView); /** * if fighter doesn't have option, return 0 not to draw. * TODO: not straight forward design. */ FighterOptionView.prototype.getNum = function() { return (this.element.fighter.hasOption()) ? 1 : 0; }; __copyParentMethod(FighterOptionView, ElementView, '_getElementX'); FighterOptionView.prototype._getElementX = function() { return this.ElementView_getElementX() + this.element.fighter.getX(); }; __copyParentMethod(FighterOptionView, ElementView, '_getElementY'); FighterOptionView.prototype._getElementY = function() { return this.ElementView_getElementY() + this.element.fighter.getY(); }; __copyParentMethod(FighterOptionView, ElementView, '_getElementZ'); FighterOptionView.prototype._getElementZ = function() { return this.ElementView_getElementZ() + this.element.fighter.getZ(); }; /** * for character change. * TODO: bad design. */ FighterOptionView.prototype.animate = function() { this._initCoordinates(); this.a = this.element.fighter.isFlagSet(this.element._FLAG_UNHITTABLE) ? 0.7 : 1.0; }; function FighterOption(gameState, maxX, maxY) { this.parent = Element; this.parent.call(this, gameState, maxX, maxY); this.fighter = null; this.angle = null; this.theta = null; this.d = null; this.trange = null; } __inherit(FighterOption, Element); // only for reference FighterOption.prototype.Math = Math; FighterOption.prototype._WIDTH = 16 ; FighterOption.prototype._HEIGHT = 16 ; FighterOption.prototype._MOVE_SPEED = 8 ; FighterOption.prototype._ROTATE_SPEED = 4 ; __copyParentMethod(FighterOption, Element, 'init'); FighterOption.prototype._init = function(params, image) { this.Element_init(params, image); this.width = this._WIDTH; this.height = this._HEIGHT; this.collisionWidth = this.width; this.collisionHeight = this.height; this.angle = this._getValueOrDefaultValue(params.angle, 0); this.theta = this._getValueOrDefaultValue(params.theta, 0); this.d = this._getValueOrDefaultValue(params.d, 0); this.trange = this._getValueOrDefaultValue(params.trange, null); }; FighterOption.prototype.init = function(params, image, fighter) { this.fighter = fighter; this._init(params, image); this._initView(); }; FighterOption.prototype.reset = function(params) { this._init(params, this.image); }; FighterOption.prototype._generateView = function() { return new FighterOptionView(this); }; /** * TODO: temporal. Should I use MoveVector? */ __copyParentMethod(FighterOption, Element, 'runStep'); FighterOption.prototype.runStep = function() { if(this.fighter.hasOption()) { this.theta += (this.fighter.isFlagSet(this.fighter._FLAG_SLOW) ? 1 : -1) * this.d * this._MOVE_SPEED; if(this.theta > this.trange.max) this.theta = this.trange.max; if(this.theta < this.trange.min) this.theta = this.trange.min; this.setX(this.r * this.Math.cos(this._calculateRadian(this.theta))); this.setY(this.r * this.Math.sin(this._calculateRadian(this.theta))); } this.Element_runStep(); }; /** * TODO: temporal */ FighterOption.prototype.display = function( surface ) { if( ! this.fighter.hasOption( ) ) return ; this.image = this.fighter.characterIndex == 0 ? this.gameState.getImage( Game._IMG_REIMU_OPTION ) : this.gameState.getImage( Game._IMG_MARISA_OPTION ) ; this.parent.prototype.display.call( this, surface, true, angle ) ; } ; FighterOption.prototype.getDirectionTheta = function() { return (this.angle + this.count * this._ROTATE_SPEED + 90) % 360; }; FighterOption.prototype.checkLoss = function( ) { return false ; } ; FighterOption.prototype.getCenterX = function( ) { return this.getX( ) + this.fighter.getX( ) ; } ; FighterOption.prototype.getCenterY = function( ) { return this.getY( ) + this.fighter.getY( ) ; } ; /** * TODO: temporal. bad design. */ FighterOption.prototype.getImageIndexY = function() { return this.fighter.characterIndex; }; ================================================ FILE: source/Game.js ================================================ function Game(mainCanvas, bgCanvas) { this.gs = new GameSocket(this); this.gs.connect(); this.surface = mainCanvas.getContext('2d'); this.surface.fillStyle = 'white'; this.bgLayer = new Layer(bgCanvas); // this.width = Number(mainCanvas.getAttribute('width')) - Game._SIDE_WIDTH; this.width = Number(mainCanvas.getAttribute('width')); this.height = Number(mainCanvas.getAttribute('height')); this.sounds = [ ] ; this.bgms = [ ] ; this.images = [ ] ; this.interval = null ; this.oldTIme = null ; this.fps = null ; this.count = 0 ; this.someoneState = -1; this.onlineActiveNum = 0; this.messegeReceiveCount = 0; this.state = 0 ; this.flags = 0 ; this.states = [ ] ; // TODO: temporal this.states[ Game._STATE_LOAD ] = new LoadingState( this ) ; this.states[ Game._STATE_OPENING ] = new OpeningState( this ) ; this.states[ Game._STATE_CHARA_SEL ] = new CharacterSelectState( this ) ; this.states[ Game._STATE_REPLAY_SEL ] = new ReplaySelectState( this ) ; this.states[ Game._STATE_IN_STAGE ] = new StageState( this ) ; this.states[ Game._STATE_ENDING ] = new EndingState( this ) ; this.states[ Game._STATE_STAFF_ROLL ] = new StaffRollState( this ) ; this.states[ Game._STATE_POST_REPLAY ] = new PostReplayState( this ) ; this._changeState( Game._STATE_LOAD, { } ) ; var self = this; this.runFunc = function() { self._runStep(); }; this.lag = null; this.room = null; this.peer = null; this.master = false; this.multiPlay = false; this.connected = false; this.waitingOther = false; this.receivedOther = false; this.otherParams = null; this.meParams = null; this.onWsReady = null; this.onConnected = null; this.onSentParams = null; this.onRan = null; this.onRoomUpdate = null; } Game.prototype.Randomizer = __randomizer; //Game.prototype._WS_URL = 'ws://localhost:5000'; Game.prototype._WS_URL = 'wss://boiling-anchorage-5279.herokuapp.com/'; Game.prototype._PEER_ID_START = 0; Game.prototype._PEER_ID_SYNC = 1; Game._SIDE_WIDTH = 160 ; Game._FPS = 60 ; Game._FPS_SPAN = 60 ; Game._SOMEONE_STATE_DISPLAY_COUNT = 60*5; Game._STATE_LOAD = 0x0 ; Game._STATE_OPENING = 0x1 ; Game._STATE_CHARA_SEL = 0x2 ; Game._STATE_REPLAY_SEL = 0x3 ; Game._STATE_IN_STAGE = 0x4 ; Game._STATE_STAGE_CLEAR = 0x5 ; Game._STATE_ENDING = 0x6 ; Game._STATE_STAFF_ROLL = 0x7 ; Game._STATE_POST_REPLAY = 0x8 ; Game._SE_SELECT = 0 ; Game._SE_DEAD = 1 ; Game._SE_SHOT = 2 ; Game._SE_ENEMY_SHOT = 3 ; Game._SE_ENEMY_VANISH = 4 ; Game._SE_ENEMY_DAMAGE = 5 ; Game._SE_GRAZE = 6 ; Game._SE_POWERUP = 7 ; Game._SE_POWER_EFFECT = 8 ; Game._IMG_FIGHTER = 0; Game._IMG_REIMU_SHIP = 1; Game._IMG_MARISA_SHIP = 2; Game._IMG_FIGHTER_OPTION = 3; Game._IMG_REIMU_OPTION = 4; Game._IMG_MARISA_OPTION = 5; Game._IMG_SHOT = 6; Game._IMG_BOMB = 7; Game._IMG_ENEMY_SHOT = 8; Game._IMG_LASER = 9; Game._IMG_BEAM = 10; Game._IMG_ENEMY = 11; Game._IMG_DAMAGE = 12; Game._IMG_VANISHED = 13; Game._IMG_SHOCK_WAVE = 14; Game._IMG_REIMU_FACE_1 = 15; Game._IMG_REIMU_FACE_2 = 16; Game._IMG_REIMU_FACE_3 = 17; Game._IMG_REIMU_FACE_4 = 18; Game._IMG_MARISA_FACE_1 = 19; Game._IMG_MARISA_FACE_2 = 20; Game._IMG_MARISA_FACE_3 = 21; Game._IMG_MARISA_FACE_4 = 22; Game._IMG_ENEMY_MOKOU = 23; Game._IMG_ENEMY_RUMIA = 24; Game._IMG_ENEMY_DAIYOUSEI = 25; Game._IMG_ENEMY_CHILNO = 26; Game._IMG_ITEM = 27; Game._IMG_POWER_ITEM = 28; Game._IMG_SCORE_ITEM = 29; Game._IMG_BG1 = 30; Game._IMG_BG2 = 31; Game._IMG_SCORE_BACK = 32; Game._IMG_STAND_REIMU = 33; Game._IMG_STAND_MARISA = 34; Game._IMG_STAND_MOKOU = 35; Game._IMG_STAND_RUMIA = 36; Game._IMG_STAND_CHILNO = 37; Game._IMG_TITLE_BG = 38; Game._IMGS = { } ; Game._IMGS[Game._IMG_FIGHTER] = 'image/fighter.png'; Game._IMGS[ Game._IMG_REIMU_SHIP ] = 'image/reimu.png' ; Game._IMGS[ Game._IMG_MARISA_SHIP ] = 'image/marisa.png' ; Game._IMGS[ Game._IMG_REIMU_OPTION ] = 'image/reimu_option.png' ; Game._IMGS[ Game._IMG_MARISA_OPTION ] = 'image/marisa_option.png' ; Game._IMGS[Game._IMG_FIGHTER_OPTION] = 'image/fighter_option.png'; Game._IMGS[ Game._IMG_SHOT ] = 'image/pl_shot.png' ; Game._IMGS[ Game._IMG_BOMB ] = 'image/th128_Bullet2HD.png' ; Game._IMGS[ Game._IMG_ENEMY_SHOT ] = 'image/bullet.png' ; Game._IMGS[ Game._IMG_LASER ] = 'image/pl_shot.png' ; Game._IMGS[ Game._IMG_BEAM ] = 'image/beam.png' ; Game._IMGS[ Game._IMG_ENEMY ] = 'image/enemy.png' ; Game._IMGS[ Game._IMG_ENEMY_MOKOU ] = 'image/mokou.png' ; Game._IMGS[ Game._IMG_ENEMY_RUMIA ] = 'image/rumia.png' ; Game._IMGS[ Game._IMG_ENEMY_DAIYOUSEI ] = 'image/daiyousei.png' ; Game._IMGS[ Game._IMG_ENEMY_CHILNO ] = 'image/chilno.png' ; Game._IMGS[ Game._IMG_DAMAGE ] = 'image/th128_BulletHD.png' ; Game._IMGS[ Game._IMG_VANISHED ] = 'image/th128_Bullet2.png' ; Game._IMGS[ Game._IMG_SHOCK_WAVE ] = 'image/shockwave.png' ; Game._IMGS[ Game._IMG_REIMU_FACE_1 ] = 'image/reimu_1.png' ; Game._IMGS[ Game._IMG_REIMU_FACE_2 ] = 'image/reimu_2.png' ; Game._IMGS[ Game._IMG_REIMU_FACE_3 ] = 'image/reimu_3.png' ; Game._IMGS[ Game._IMG_REIMU_FACE_4 ] = 'image/reimu_4.png' ; Game._IMGS[ Game._IMG_MARISA_FACE_1 ] = 'image/marisa_1.png' ; Game._IMGS[ Game._IMG_MARISA_FACE_2 ] = 'image/marisa_2.png' ; Game._IMGS[ Game._IMG_MARISA_FACE_3 ] = 'image/marisa_3.png' ; Game._IMGS[ Game._IMG_MARISA_FACE_4 ] = 'image/marisa_4.png' ; Game._IMGS[ Game._IMG_ITEM ] = 'image/item.png' ; Game._IMGS[ Game._IMG_POWER_ITEM ] = 'image/power_item.png' ; Game._IMGS[ Game._IMG_SCORE_ITEM ] = 'image/score_item.png' ; Game._IMGS[ Game._IMG_BG1 ] = 'image/bg1.png' ; Game._IMGS[ Game._IMG_BG2 ] = 'image/bg2.png' ; Game._IMGS[ Game._IMG_SCORE_BACK ] = 'image/scoreback.png' ; Game._IMGS[ Game._IMG_STAND_REIMU ] = 'image/reimu_stand.png' ; Game._IMGS[ Game._IMG_STAND_MARISA ] = 'image/marisa_stand.png' ; Game._IMGS[ Game._IMG_STAND_MOKOU ] = 'image/mokou_stand.png' ; Game._IMGS[ Game._IMG_STAND_RUMIA ] = 'image/rumia_stand.png' ; Game._IMGS[ Game._IMG_STAND_CHILNO ] = 'image/chilno_stand.png' ; Game._IMGS[ Game._IMG_TITLE_BG ] = 'image/title_bg.png' ; Game._BGM_TITLE = 0 ; Game._BGM_1 = 1 ; Game._BGM_ENDING = 2 ; Game._BGMS = { } ; Game._BGMS[ Game._BGM_TITLE ] = 'BGM/title.mp3' ; Game._BGMS[ Game._BGM_1 ] = 'BGM/bgm.mp3' ; Game._BGMS[ Game._BGM_ENDING ] = 'BGM/ending.mp3' ; Game._SES = { } ; Game._SES[ Game._SE_SELECT ] = 'SE/select.wav' ; Game._SES[ Game._SE_DEAD ] = 'SE/dead.wav' ; Game._SES[ Game._SE_SHOT ] = 'SE/shot.wav' ; Game._SES[ Game._SE_ENEMY_SHOT ] = 'SE/shot.wav' ; Game._SES[ Game._SE_ENEMY_VANISH ] = 'SE/enemy_vanish.wav' ; Game._SES[ Game._SE_ENEMY_DAMAGE ] = 'SE/enemy_damage.wav' ; Game._SES[ Game._SE_GRAZE ] = 'SE/graze.wav' ; Game._SES[ Game._SE_POWERUP ] = 'SE/powerup.wav' ; Game._SES[ Game._SE_POWER_EFFECT ] = 'SE/enemy_powereffect.wav' ; Game._SOMEONE_MESSAGES = []; Game._SOMEONE_MESSAGES[GameSocket._STATE_OPEN] = 'opened'; Game._SOMEONE_MESSAGES[GameSocket._STATE_CLOSE] = 'closed'; Game._SOMEONE_MESSAGES[GameSocket._STATE_BEGIN_GAME] = 'began the game'; Game._SOMEONE_MESSAGES[GameSocket._STATE_DEAD] = 'dead'; Game._SOMEONE_MESSAGES[GameSocket._STATE_DESTROY_STAGE1_MID_BOSS] = 'destroyed Rumia'; Game._SOMEONE_MESSAGES[GameSocket._STATE_DESTROY_STAGE1_BIG_BOSS] = 'destroyed Rumia'; Game._SOMEONE_MESSAGES[GameSocket._STATE_DESTROY_STAGE2_MID_BOSS] = 'destroyed Dai Yousei'; Game._SOMEONE_MESSAGES[GameSocket._STATE_DESTROY_STAGE2_BIG_BOSS] = 'destroyed Chirno'; Game._SOMEONE_MESSAGES[GameSocket._STATE_GAME_CLEAR] = 'completed the game'; Game._SOMEONE_MESSAGES[GameSocket._STATE_GAME_OVER] = 'game over'; Game.prototype.getImage = function( key ) { return this.images[ key ] ; } ; /** * TODO: temporal */ Game.prototype.soundEffect = function(key) { var game = Game; switch(key) { case game._SE_SHOT: this.sounds[key].volume = 0.012; break; case game._SE_SELECT: this.sounds[key].volume = 0.04; break; case game._SE_POWER_EFFECT: this.sounds[key].volume = 0.14; break; case game._SE_ENEMY_SHOT: this.sounds[key].volume = 0.02; break; case game._SE_ENEMY_DAMAGE: this.sounds[key].volume = 0.014; break; case game._SE_ENEMY_VANISH: this.sounds[key].volume = 0.03; break; case game._SE_DEAD: this.sounds[key].volume = 0.05; break; case game._SE_POWERUP: this.sounds[key].volume = 0.04; break; case game._SE_GRAZE: this.sounds[key].volume = 0.05; break; default: this.sounds[key].volume = 0.1; break; } this.sounds[ key ].pause(); this.sounds[ key ].currentTime = 0; this.sounds[ key ].play(); // this.sounds[ key ] = new Audio( this.sounds[ key ].src ) ; } ; Game.prototype.soundBGM = function( key ) { for( var i = 0; i < this.bgms.length; i++ ) { this.bgms[ i ].pause( ) ; this.bgms[ i ].currentTime = 0 ; } this.bgms[ key ].loop = true ; // TODO: temporal if( key == Game._BGM_TITLE ) this.bgms[ key ].volume = 0.08 ; else this.bgms[ key ].volume = 0.2 ; this.bgms[ key ].play( ) ; } ; Game.prototype.run = function( ) { // this.states[ this.state ].init( ) ; // this.interval = setInterval( this._runStep.bind( this ), 1000 / Game._FPS ) ; this._runStep( ) ; } ; Game.prototype.clear = function( surface ) { surface.clearRect( 0, 0, this.width, this.height ) ; } ; Game.prototype.handleKeyDown = function( e ) { // TODO: temporal if(this.isMultiPlay() && this.waitingOther && ! this.receivedOther) return; this.states[ this.state ].handleKeyDown( e ) ; e.preventDefault( ) ; } ; Game.prototype.handleKeyUp = function( e ) { // TODO: temporal if(this.isMultiPlay() && this.waitingOther && ! this.receivedOther) return; this.states[ this.state ].handleKeyUp( e ) ; e.preventDefault( ) ; } ; /** * TODO: temporal */ Game.prototype._runStep = function( ) { this.states[ this.state ].runStep( ) ; this.states[ this.state ].updateDisplay( this.surface ) ; this._displayFps( this.surface ) ; this._displayOnlineState(this.surface); if(this.someoneState >= 0 && this.count > this.messageReceiveCount + Game._SOMEONE_STATE_DISPLAY_COUNT) this.someoneState = -1; this.count++ ; if(this.states[this.state].doRunNextStep()) this.runNextStep(); } ; Game.prototype.runNextStep = function() { requestAnimationFrame(this.runFunc); }; Game.prototype._calculateFps = function( ) { if( ( this.count % Game._FPS_SPAN ) != 0 ) return ; var newTime = Date.now( ) ; if( this.oldTime ) { this.fps = parseInt( 1000 * Game._FPS_SPAN / ( newTime - this.oldTime ) ) ; } this.oldTime = newTime ; } ; Game.prototype._displayFps = function( surface ) { this._calculateFps( ) ; if( ! this.fps ) return ; surface.save( ) ; surface.fillStyle = 'rgb( 255, 255, 255 )' ; surface.font = '16px Arial' ; surface.fillText( this.fps + 'fps', this.getWidth( ) - 50, this.getHeight( ) - 15 ) ; surface.restore( ) ; } ; /** * TODO: temporal. */ Game.prototype._displayOnlineState = function(surface) { if(! this.gs.connected()) return; surface.save(); surface.textAlign = 'right'; surface.fillStyle = 'rgb(255, 255, 255)'; surface.font = '12px Arial'; surface.fillText(this.onlineActiveNum + ' playing now', this.getWidth() - 5, 15); if(this.someoneState >= 0) { var x = (this.count - this.messageReceiveCount)*4 - 100; if(x > 5) x = 5; surface.fillText('someone', this.getWidth() - x - 30, 30); surface.fillText(Game._SOMEONE_MESSAGES[this.someoneState], this.getWidth() - x, 45); } surface.restore(); }; /** * TODO: temporal. */ Game.prototype.sendMessageToServer = function(key) { this.gs.send(key); }; /** * TODO: temporal. */ Game.prototype.notifyMessageReceive = function(activeNum, key) { this.onlineActiveNum = activeNum; this.someoneState = key; this.messageReceiveCount = this.count; }; Game.prototype.notifyLoadingConclusion = function( ) { this._changeState( Game._STATE_OPENING, { } ) ; // this._changeState( Game._STATE_STAFF_ROLL, { } ) ; } ; Game.prototype.notifyOpeningConclusion = function( ) { this._changeState( Game._STATE_CHARA_SEL, { } ) ; } ; Game.prototype.notifyCharacterSelectConclusion = function(index) { var seed = (new Date()).getTime() & 0xffff; if(this.isMultiPlay()) { var p = {}; p.i = index; p.s = seed; if(this.lag) p.l = this.lag; this.meParams = p; this.waitingOther = true; this._startSync(p); if(this.receivedOther) { this._changeState(Game._STATE_IN_STAGE, this._makeStageStateParameterForMultiPlay()); if(this.onRan !== null) this.onRan(); } } else { var params = {}; params.characterIndex = index; // me params.seed = seed; this._changeState(Game._STATE_IN_STAGE, params); } }; Game.prototype.notifyReplaySelectBegin = function( index ) { this._changeState( Game._STATE_REPLAY_SEL, { } ) ; } ; /** * TODO: temporal */ Game.prototype.notifyReplaySelectConclusion = function( params ) { // currently, only Reimu. this._changeState( Game._STATE_IN_STAGE, { 'autoplayParams': params, 'autoplay': true } ) ; } ; /** * TODO: temporal */ Game.prototype.notifyQuitStage = function( flag ) { if(flag && ! this.isMultiPlay()) this._changeState( Game._STATE_POST_REPLAY, { } ) ; else this._changeState( Game._STATE_OPENING, { } ) ; // TODO: temporal if(this.isMultiPlay()) this.resetSyncParams(); } ; Game.prototype.notifyGameClear = function( ) { // this._changeState( Game._STATE_ENDING, { } ) ; this._changeState( Game._STATE_STAFF_ROLL, { } ) ; // TODO: temporal if(this.isMultiPlay()) this.resetSyncParams(); } ; Game.prototype._changeState = function( state, params ) { this.state = state ; this.states[ this.state ].init( params ) ; } ; Game.prototype.getWidth = function( ) { return this.width ; } ; Game.prototype.getHeight = function( ) { return this.height ; } ; Game.prototype.isFlagSet = function( type ) { return ( this.flags & type ) ? true : false ; } ; Game.prototype.setFlag = function( type ) { this.flags |= type ; } ; Game.prototype.clearFlag = function( type ) { this.flags &= ~type ; } ; Game.prototype.setLag = function(lag) { this.lag = lag; }; Game.prototype.setRoom = function(room) { this.room = room; this.peer = new Peer(this.room, this._WS_URL, this); this.peer.createPeerConnection(); this.multiPlay = true; }; Game.prototype.notifyWsReady = function(e) { if(this.onWsReady !== null) this.onWsReady(e); }; Game.prototype.notifyRoomUpdate = function(num) { if(this.onRoomUpdate !== null) this.onRoomUpdate(num); }; Game.prototype.connect = function() { this.peer.offer(); this.master = true; }; Game.prototype.notifyOpenPeer = function(e) { this.connected = true; if(this.onConnected !== null) this.onConnected(e); }; Game.prototype._startSync = function(params) { this.peer.send({id: this._PEER_ID_START, p: params}); if(this.onSentParams !== null) this.onSentParams(); }; Game.prototype.sync = function(params) { // TODO: temporal impl to reduce the amount data transferred. // this.peer.send({id: this._PEER_ID_SYNC, p: params}); this.peer.send(params); }; Game.prototype.receiveFromPeer = function(data) { // TODO: temporal impl to reduce the amount data transferred. /* switch(data.id) { case this._PEER_ID_START: this.receivedOther = true; this.otherParams = data.p; if(this.waitingOther) { this._changeState(Game._STATE_IN_STAGE, this._makeStageStateParameterForMultiPlay()); if(this.onRan !== null) this.onRan(); } break; case this._PEER_ID_SYNC: this.states[this.state].receiveFromPeer(data.p); break; } */ if(data.id !== void 0) { switch(data.id) { case this._PEER_ID_START: this.receivedOther = true; this.otherParams = data.p; if(this.waitingOther) { this._changeState(Game._STATE_IN_STAGE, this._makeStageStateParameterForMultiPlay()); if(this.onRan !== null) this.onRan(); } break; case this._PEER_ID_SYNC: this.states[this.state].receiveFromPeer(data.p); break; } } else { this.states[this.state].receiveFromPeer(data); } }; Game.prototype._makeStageStateParameterForMultiPlay = function() { var p = {}; p.characterIndex = this.meParams.i; p.characterIndex2 = this.otherParams.i; // use greater one. p.seed = this.meParams.s > this.otherParams.s ? this.meParams.s : this.otherParams.s; if(this.meParams.l !== void 0 && this.otherParams.l === void 0) { p.lag = this.meParams.l; } else if(this.meParams.l === void 0 && this.otherParams.l !== void 0) { p.lag = this.otherParams.l; } else if(this.meParams.l !== void 0 && this.otherParams.l !== void 0) { p.lag = this.meParams.l > this.otherParams.l ? this.meParams.l : this.otherParams.l; } return p; }; Game.prototype.isMultiPlay = function() { return this.multiPlay; }; Game.prototype.isMaster = function() { return this.master; }; Game.prototype.isConnected = function() { return this.connected; }; Game.prototype.resetSyncParams = function() { this.waitingOther = false; this.receivedOther = false; this.otherParams = null; this.meParams = null; // TODO: temporal if(this.onConnected !== null) this.onConnected(); }; ================================================ FILE: source/GameSocket.js ================================================ /** * transferred data: state and activeNum. */ function GameSocket(game) { this.game = game; this.ws = null; this.params = {}; // for sent data. this.interval = null; var self = this; this.onMessageFunc = function(event) { self._messageCallback(event); }; this.dummySendFunc = function() { self._keepSendDummy(); }; }; GameSocket._URL = 'wss://safe-retreat-9152.herokuapp.com/'; //GameSocket._URL = 'ws://localhost:5000'; GameSocket._DUMMY_SPAN = 1000 * 20; // Share these parameters with Server. GameSocket._STATE_OPEN = 0; GameSocket._STATE_CLOSE = 1; GameSocket._STATE_BEGIN_GAME = 2; GameSocket._STATE_DEAD = 3; GameSocket._STATE_DESTROY_STAGE1_MID_BOSS = 4; GameSocket._STATE_DESTROY_STAGE1_BIG_BOSS = 5; GameSocket._STATE_DESTROY_STAGE2_MID_BOSS = 6; GameSocket._STATE_DESTROY_STAGE2_BIG_BOSS = 7; GameSocket._STATE_GAME_CLEAR = 8; GameSocket._STATE_GAME_OVER = 9; GameSocket._CONNECTION_STATUS_MAX_NUM = 1; GameSocket._SHOOTING_STATE_MAX_NUM = 9; GameSocket.prototype.connected = function() { return this.ws ? true : false; }; GameSocket.prototype.connect = function() { try { this.ws = new WebSocket(GameSocket._URL); this.ws.onmessage = this.onMessageFunc; } catch(e) { this.ws = null; console.log(e); } this._setIntervalForDummy(); }; GameSocket.prototype._messageCallback = function(event) { try { var message = JSON.parse(event.data); } catch(e) { return; } var activeNum = this.convertToValidActiveNum(message.activeNum); var key = this.convertToValidState(message.state); if(this.isValidState(key) && this.isValidActiveNum(activeNum)) this.game.notifyMessageReceive(activeNum, key); }; /** * Prolly JSON.stringify allocates new memory in it and * this could lead GC. */ GameSocket.prototype.send = function(key) { if(! this.ws) return; this.params.state = key; var data = JSON.stringify(this.params); this.ws.send(data); }; GameSocket.prototype._keepSendDummy = function() { this.send(-1); this._setIntervalForDummy(); }; GameSocket.prototype._setIntervalForDummy = function() { if(! this.ws) return; this.interval = setTimeout(this.dummySendFunc, GameSocket._DUMMY_SPAN); }; GameSocket.prototype.convertToValidState = function(key) { return parseInt(key); }; GameSocket.prototype.isValidShootingState = function(key) { if(key > GameSocket._CONNECTION_STATUS_MAX_NUM && key <= GameSocket._SHOOTING_STATE_MAX_NUM) return true; return false; }; GameSocket.prototype.isValidState = function(key) { if(key >= 0 && key <= GameSocket._SHOOTING_STATE_MAX_NUM) return true; return false; }; GameSocket.prototype.convertToValidActiveNum = function(num) { return parseInt(num); }; GameSocket.prototype.isValidActiveNum = function(num) { if(num >= 0) return true; return false; }; ================================================ FILE: source/GameState.js ================================================ function GameState( game ) { this.game = game ; this.flags = 0 ; this.state = 0 ; } GameState.prototype.init = function( params ) { } ; GameState.prototype.runStep = function( ) { } ; GameState.prototype.doRunNextStep = function() { return true; }; GameState.prototype.updateDisplay = function( surface ) { } ; GameState.prototype.handleKeyDown = function( e ) { } ; GameState.prototype.handleKeyUp = function( e ) { } ; GameState.prototype.getImage = function( key ) { return this.game.getImage( key ) ; } ; GameState.prototype.getWidth = function( ) { return this.game.width ; } ; GameState.prototype.getHeight = function( ) { return this.game.height ; } ; GameState.prototype._soundBGM = function( key ) { this.game.soundBGM( key ) ; } ; GameState.prototype._soundEffect = function( key ) { this.game.soundEffect( key ) ; } ; GameState.prototype.isFlagSet = function( type ) { return ( this.flags & type ) ? true : false ; } ; GameState.prototype.setFlag = function( type ) { this.flags |= type ; } ; GameState.prototype.clearFlag = function( type ) { this.flags &= ~type ; } ; GameState.prototype.isMultiPlay = function() { return this.game.isMultiPlay(); }; GameState.prototype.isMaster = function() { return this.game.isMaster(); }; GameState.prototype.isConnected = function() { return this.game.isConnected(); }; GameState.prototype.receiveFromPeer = function(data) { }; ================================================ FILE: source/Item.js ================================================ function ItemManager( gameState ) { this.parent = ElementManager ; this.parent.call( this, gameState ) ; } ; __inherit( ItemManager, ElementManager ) ; ItemManager.prototype._MAX_NUM = 1000; ItemManager.prototype._initMaxNum = function() { return this._MAX_NUM; }; ItemManager.prototype._initFactory = function( ) { this.factory = new ItemFactory( this.gameState, this.gameState.getWidth( ), this.gameState.getHeight( ) ) ; } ; ItemManager.prototype.initDrawer = function(layer, image) { this.drawer = new ItemDrawer(this, layer, this.gameState.getImage(Game._IMG_ITEM)); }; /** * TODO: temporary */ ItemManager.prototype.create = function( enemy, type ) { this.addElement( this.factory.create( enemy, type ) ) ; } ; ItemManager.prototype.createPowerItem = function(enemy) { this.create(enemy, this.Item._TYPE_POWER); }; ItemManager.prototype.createScoreItem = function(enemy) { this.create(enemy, this.Item._TYPE_SCORE); }; /** * TODO: temporary */ ItemManager.prototype.createHoming = function(fighter, enemy) { var item = this.factory.create(enemy, this.Item._TYPE_SCORE); item.setTarget(fighter); this.addElement(item); }; __copyParentMethod(ItemManager, ElementManager, 'checkCollisionWith'); ItemManager.prototype.checkCollisionWith = function( fighter ) { this.ElementManager_checkCollisionWith(null, fighter, this); }; ItemManager.prototype.checkCollisionWithFighters = function(fighters) { for(var i = 0; i < fighters.length; i++) { this.checkCollisionWith(fighters[i]); } }; ItemManager.prototype.notifyCollision = function(id, fighter, item) { item.die(); if(item.isPower()) this.gameState.notifyFighterGotPowerItem(fighter, item); else this.gameState.notifyFighterGotScoreItem(fighter, item); }; ItemManager.prototype.beHomingAll = function( fighter ) { for( var i = 0; i < this.elements.length; i++ ) { this.elements[ i ].setTarget( fighter ) ; } } ; function ItemFactory( gameState, maxX, maxY ) { this.parent = ElementFactory ; this.parent.call( this, gameState, maxX, maxY ) ; this.image = null; // TODO: temporal } ; __inherit( ItemFactory, ElementFactory ) ; ItemFactory.prototype._NUM = 1000 ; ItemFactory.prototype._PARAMS = { 'x': 0, 'y': 0, 'v': { 'r': 4, 'theta': 270, 'w': 0, 'ra':-0.1, 'wa': 0 } } ; ItemFactory.prototype._initFreelist = function() { this.freelist = new ItemFreeList(this._NUM, this.gameState); }; /** * TODO: temporal */ ItemFactory.prototype.create = function(element, type) { var params = this._PARAMS; params.x = element.getX(); params.y = element.getY(); var item = this.freelist.get(); item.init(params, this._getImage(type), type); return item; }; ItemFactory.prototype._getImage = function(type) { if(this.image === null) this.image = this.gameState.getImage(Game._IMG_ITEM); return this.image; }; function ItemFreeList( num, gameState ) { this.parent = ElementFreeList ; this.parent.call( this, num, gameState ) ; } __inherit( ItemFreeList, ElementFreeList ) ; ItemFreeList.prototype._generateElement = function( ) { return new Item( this.gameState, this.gameState.getWidth( ), this.gameState.getHeight( ) ) ; } ; function ItemDrawer(elementManager, layer, image) { this.parent = ElementDrawer; this.parent.call(this, elementManager, layer, image); }; __inherit(ItemDrawer, ElementDrawer); function ItemView(element) { this.parent = ElementView; this.parent.call(this, element); }; __inherit(ItemView, ElementView); /** * no rotate. * TODO: no rotate impl should be in parent class? */ ItemView.prototype.rotate = function() { }; ItemView.prototype.doRotateForViewpoint = function() { return true; }; function Item( gameState, maxX, maxY ) { this.parent = Element ; this.parent.call( this, gameState, maxX, maxY ) ; this.type = null ; this.target = null ; } __inherit( Item, Element ) ; // only for reference Item.prototype.Math = Math; Item.prototype._WIDTH = 12 ; Item.prototype._HEIGHT = 12 ; Item.prototype._COLLISION_WIDTH = 50 ; Item.prototype._COLLISION_HEIGHT = 50 ; Item.prototype._HOMING_SPAN = 2 ; Item.prototype._HOMING_R = 10 ; Item.prototype._TYPE_POWER = 0 ; Item.prototype._TYPE_SCORE = 1 ; __copyParentMethod(Item, Element, 'init'); Item.prototype.init = function(params, image, type) { this.Element_init(params, image); this.type = type; this.indexX = this.type; // TODO: temporal. this.width = this._WIDTH; this.height = this._HEIGHT; this.collisionWidth = this._COLLISION_WIDTH; this.collisionHeight = this._COLLISION_HEIGHT; this.target = null; this._initView(); }; Item.prototype._generateView = function() { return new ItemView(this); }; /** * TODO: temporal */ __copyParentMethod(Item, Element, 'runStep'); Item.prototype.runStep = function() { if(this.target && this.count % this._HOMING_SPAN == 0) this._calculateHomingPoint(); this.Element_runStep(); }; Item.prototype.setTarget = function( element ) { this.target = element ; } ; Item.prototype.isPower = function() { return this.type == this._TYPE_POWER; }; Item.prototype.isScore = function() { return this.type == this._TYPE_SCORE; }; /** * TODO: temporal */ Item.prototype.checkLoss = function( ) { if( this.isDead( ) ) return true ; if( this.x < 0 || this.x >= this.maxX || this.y >= this.maxY ) return true ; return false ; } ; /** * TODO: temporal */ Item.prototype._calculateHomingPoint = function( ) { var ax = this.target.getX( ) - this.getX( ) ; var ay = this.target.getY( ) - this.getY( ) ; var t = this._calculateTheta( this.Math.atan2( ay, ax ) ) ; this.vector.theta = t ; this.vector.r = this._HOMING_R ; return ; } ; // TODO: remove the followings because they complicate the design. ItemManager.prototype.Item = Item.prototype; ================================================ FILE: source/LoadingState.js ================================================ function LoadingState( game ) { this.parent = GameState ; this.parent.call( this, game ) ; this.loadImageNum = 0 ; this.loadSoundNum = 0 ; this.loadBgmNum = 0 ; } __inherit( LoadingState, GameState ) ; LoadingState.prototype.init = function( params ) { this._loadImages( ) ; this._loadSEs( ) ; this._loadBGMs( ) ; } ; LoadingState.prototype.runStep = function( ) { this._checkLoadCompletion( ) ; } ; LoadingState.prototype._checkLoadCompletion = function( ) { if( this.loadImageNum < this.game.images.length ) return ; if( this.loadSoundNum < this.game.sounds.length ) return ; if( this.loadBgmNum < this.game.bgms.length ) return ; this.game.notifyLoadingConclusion( ) ; } ; LoadingState.prototype._loadImages = function( ) { var self = this ; for( var key in Game._IMGS ) { this.game.images[ key ] = new Image( ) ; this.game.images[ key ].src = Game._IMGS[ key ] ; this.game.images[ key ].onload = function( ) { self.loadImageNum++ ; } ; } } ; LoadingState.prototype._loadSEs = function( ) { var self = this ; for( var key in Game._SES ) { this.game.sounds[ key ] = new Audio( Game._SES[ key ] ) ; this.game.sounds[ key ].addEventListener( 'canplay', function( e ) { self.loadSoundNum++ ; } ) ; this.game.sounds[ key ].load( ) ; } } ; LoadingState.prototype._loadBGMs = function( ) { var self = this ; for( var key in Game._BGMS ) { this.game.bgms[ key ] = new Audio( Game._BGMS[ key ] ) ; this.game.bgms[ key ].addEventListener( 'loadstart', function( e ) { self.loadBgmNum++ ; } ) ; this.game.bgms[ key ].load( ) ; } } ; LoadingState.prototype.updateDisplay = function( surface ) { surface.save( ) ; this.game.clear( surface ) ; // TODO: temporal surface.fillStyle = 'rgb( 0, 0, 0 )' ; surface.textAlign = 'right' ; surface.fillText( 'loading...', 180, 200 ) ; surface.fillText( ( this.loadImageNum + this.loadSoundNum + this.loadBgmNum ) + '/' + ( this.game.images.length + this.game.sounds.length + this.game.bgms.length ), 200, 240 ) ; surface.restore( ) ; } ; ================================================ FILE: source/MoveVector.js ================================================ function MoveVectorManager( ) { this.elements = [ ] ; this.factory = null ; this._initFactory( ) ; } MoveVectorManager.prototype._NUM = 2000; MoveVectorManager.prototype._initFactory = function() { this.factory = new MoveVectorFactory(this._NUM); }; MoveVectorManager.prototype.reset = function( ) { for(var i = 0, len = this.elements.length; i < len; i++) { this.factory.free(this.elements[i]); } this.elements.length = 0; }; MoveVectorManager.prototype.create = function( params ) { return this.factory.create( params ) ; } ; MoveVectorManager.prototype.free = function( element ) { this.factory.free( element ) ; } ; function MoveVectorFactory( num ) { this.num = num ; this.freelist = null ; this._initFreelist( ) ; } MoveVectorFactory.prototype._initFreelist = function( ) { this.freelist = new MoveVectorFreeList( this.num ) ; } ; MoveVectorFactory.prototype.create = function( params ) { var vector = this.freelist.get( ) ; vector.init( params ) ; return vector ; } ; MoveVectorFactory.prototype.free = function( vector ) { this.freelist.free( vector ) ; } ; /** * TODO: list may should be Linked list if num is large. */ function MoveVectorFreeList( num ) { FreeList.call( this, num ) ; } __inherit( MoveVectorFreeList, FreeList ) ; /** * Child class must override this method. */ MoveVectorFreeList.prototype._generateElement = function( ) { return new MoveVector( ) ; } ; /** * */ function MoveVector( ) { this.r = 0 ; // TODO: should be "v"elocity? this.theta = 90 ; this.w = 0 ; this.ra = 0 ; this.wa = 0 ; this.raa = 0 ; this.waa = 0 ; this.trange = null ; this.rrange = null ; this.wrange = null ; this.rarange = null ; this.warange = null ; this.element = null ; this.reflectCount = 0 ; } // only for reference MoveVector.prototype.Math = Math; MoveVector.prototype.Randomizer = __randomizer; MoveVector.prototype.init = function( params ) { this.r = params.r !== void 0 ? params.r : 0 ; this.theta = params.theta !== void 0 ? params.theta : 90 ; this.w = params.w !== void 0 ? params.w : 0 ; this.ra = params.ra !== void 0 ? params.ra : 0 ; this.wa = params.wa !== void 0 ? params.wa : 0 ; this.raa = params.raa !== void 0 ? params.raa : 0 ; this.waa = params.waa !== void 0 ? params.waa : 0 ; this.trange = params.trange !== void 0 ? params.trange : null ; this.rrange = params.rrange !== void 0 ? params.rrange : null ; this.wrange = params.wrange !== void 0 ? params.wrange : null ; this.rarange = params.rarange !== void 0 ? params.rarange : null ; this.warange = params.warange !== void 0 ? params.warange : null ; this.element = null ; this.reflectCount = 0 ; if(params.rrandom !== void 0) this.r = this._getRandomValue( params.rrandom ) ; if(params.trandom !== void 0) this.theta = this._getRandomValue( params.trandom ) ; if(params.wrandom !== void 0) this.w = this._getRandomValue( params.wrandom ) ; } ; /** * TODO: temporal * How to handle floating point...? */ MoveVector.prototype._getRandomValue = function( range ) { var differ = range.max - range.min ; return ((this.Randomizer.random() * differ) | 0) + range.min ; } ; MoveVector.prototype.setHomingElement = function( e ) { this.element = e ; } ; MoveVector.prototype.runStep = function( ) { this.theta += this.w ; this.r += this.ra ; this.w += this.wa ; this.ra += this.raa ; this.wa += this.waa ; this.theta = this._beInRange( this.theta, this.trange ) ; this.r = this._beInRange( this.r, this.rrange ) ; this.w = this._beInRange( this.w, this.wrange ) ; this.ra = this._beInRange( this.ra, this.rarange ) ; this.wa = this._beInRange( this.wa, this.warange ) ; } ; MoveVector.prototype._beInRange = function( value, range ) { if(range === null) return value; if(range.max !== void 0 && value > range.max) value = range.max ; if(range.min !== void 0 && value < range.min) value = range.min return value; }; MoveVector.prototype._getRadian = function( ) { return this.theta / 180 * this.Math.PI ; } ; MoveVector.prototype.moveX = function( ) { return this.r * this.Math.cos( this._getRadian( ) ) ; } ; MoveVector.prototype.moveY = function( ) { return this.r * this.Math.sin( this._getRadian( ) ) ; } ; MoveVector.prototype.reflect = function( ) { this.theta += 180 ; this.reflectCount++ ; } ; MoveVector.prototype.reflectX = function( ) { this.theta = 180 - this.theta ; this.reflectCount++ ; } ; MoveVector.prototype.reflectY = function( ) { this.theta = 360 - this.theta ; this.reflectCount++ ; } ; MoveVector.prototype.getReflectCount = function( ) { return this.reflectCount ; } ; ================================================ FILE: source/OpeningState.js ================================================ function OpeningState( game ) { this.parent = GameState ; this.parent.call( this, game ) ; this.initialized = false ; this.state = OpeningState._STATE_LOGO ; this.states = [ ] ; this.states[ OpeningState._STATE_LOGO ] = new LogoState( this ) ; this.states[ OpeningState._STATE_TITLE ] = new TitleState( this ) ; } __inherit( OpeningState, GameState ) ; OpeningState._STATE_LOGO = 0x0 ; OpeningState._STATE_TITLE = 0x1 ; OpeningState.prototype.init = function( ) { if( this.initialized ) this.notifyLogoConclusion( ) ; this.initialized = true ; } ; OpeningState.prototype.runStep = function( ) { this.states[ this.state ].runStep( ) ; } ; OpeningState.prototype.updateDisplay = function( surface ) { this.game.clear( surface ) ; this.states[ this.state ].updateDisplay( surface ) ; } ; OpeningState.prototype.handleKeyDown = function( e ) { this.states[ this.state ].handleKeyDown( e ) ; } ; OpeningState.prototype.handleKeyUp = function( e ) { } ; OpeningState.prototype.notifyLogoConclusion = function( ) { this.state = OpeningState._STATE_TITLE ; this.states[ this.state ].init( ) ; } ; OpeningState.prototype.notifyTitleConclusion = function() { if(! this.isMultiPlay() || this.isConnected()) { this.game.notifyOpeningConclusion(); } else { // TODO: temporal window.alert('connect to begin the game.'); } }; OpeningState.prototype.notifyReplaySelectBegin = function() { if(this.isMultiPlay()) { // TODO: temporal window.alert('cannot choose replay for multi play.'); } else { this.game.notifyReplaySelectBegin(); } }; OpeningState.prototype.getImage = function( key ) { return this.game.getImage( key ) ; } ; OpeningState.prototype.soundEffect = function( key ) { this.game.soundEffect( key ) ; } ; OpeningState.prototype.soundBGM = function( key ) { this.game.soundBGM( key ) ; } ; OpeningAbstractState = function( opening ) { this.opening = opening ; } OpeningAbstractState.prototype.init = function( ) { } ; OpeningAbstractState.prototype.runStep = function( ) { } ; OpeningAbstractState.prototype.handleKeyDown = function( e ) { } ; OpeningAbstractState.prototype.updateDisplay = function( surface ) { } ; OpeningAbstractState.prototype.getImage = function( key ) { return this.opening.getImage( key ) ; } ; OpeningAbstractState.prototype.soundEffect = function( key ) { this.opening.soundEffect( key ) ; } ; OpeningAbstractState.prototype.soundBGM = function( key ) { this.opening.soundBGM( key ) ; } ; LogoState = function( opening ) { this.parent = OpeningAbstractState ; this.parent.call( this, opening ) ; this.count = 0 ; } __inherit( LogoState, OpeningAbstractState ) ; LogoState._GLOBALALPHA_SPAN = 100 ; LogoState._DISPLAY_SPAN = 300 ; LogoState.prototype.init = function( ) { this.count = 0 ; } ; LogoState.prototype.runStep = function( ) { this.count++ ; if( this.count > LogoState._DISPLAY_SPAN ) this.opening.notifyLogoConclusion( ) ; } ; LogoState.prototype.handleKeyDown = function( e ) { switch( e.keyCode ) { case 90: // z this.opening.notifyLogoConclusion( ) ; break ; } ; } ; LogoState.prototype.updateDisplay = function( surface ) { this._displayBG( surface ) ; this._displayMessage( surface ) ; } ; LogoState.prototype._displayBG = function( surface ) { surface.save( ) ; surface.fillStyle = 'rgb( 0, 0, 0 )' ; surface.fillRect( 0, 0, this.opening.getWidth( ), this.opening.getHeight( ) ) ; surface.restore( ) ; } ; LogoState.prototype._displayMessage = function( surface ) { surface.save( ) ; if( this.count < LogoState._GLOBALALPHA_SPAN ) surface.globalAlpha = this.count / LogoState._GLOBALALPHA_SPAN ; else if( this.count > LogoState._DISPLAY_SPAN - LogoState._GLOBALALPHA_SPAN ) surface.globalAlpha = ( LogoState._DISPLAY_SPAN - this.count ) / LogoState._GLOBALALPHA_SPAN ; else surface.globalAlpha = 1.0 ; surface.font = "30px 'Comic Sans MS'" ; surface.textAlign = 'center' ; surface.textBaseAlign = 'middle' ; surface.fillStyle = 'rgb( 255, 255, 255 )' ; surface.fillText( 'This is a fan STG of Toho-Project', this.opening.getWidth( ) / 2, 200 ) ; surface.fillText( 'Presented by @superhoge', this.opening.getWidth( ) / 2, 300 ) ; surface.restore( ) ; } ; TitleState = function( opening ) { this.parent = OpeningAbstractState ; this.parent.call( this, opening ) ; this.count = 0 ; this.state = 0 ; this.index = 0 ; } __inherit( TitleState, OpeningAbstractState ) ; TitleState._WIDTH = 1280 ; TitleState._HEIGHT = 960 ; TitleState._GLOBALALPHA_SPAN = 100 ; TitleState._STATE_DISPLAYING = 0x0 ; TitleState._STATE_DISPLAYED = 0x1 ; TitleState.prototype.init = function( ) { this.count = 0 ; this.index = 0 ; this.state = TitleState._STATE_DISPLAYING ; this.soundBGM( Game._BGM_TITLE ) ; } ; TitleState.prototype.runStep = function( ) { if( this.state == TitleState._STATE_DISPLAYING && this.count >= TitleState._GLOBALALPHA_SPAN * 2 ) this.state = TitleState._STATE_DISPLAYED ; this.count++ ; } ; TitleState.prototype.updateDisplay = function( surface ) { this._displayBG( surface ) ; this._displayImage( surface ) ; this._displayMessage( surface ) ; this._displayPressKey( surface ) ; } ; TitleState.prototype._displayBG = function( surface ) { surface.save( ) ; surface.fillStyle = 'rgb( 0, 0, 0 )' ; surface.fillRect( 0, 0, this.opening.getWidth( ), this.opening.getHeight( ) ) ; surface.fillStyle = 'rgb( 255, 255, 255 )' ; surface.fillRect( 0, 50, this.opening.getWidth( ), this.opening.getHeight( ) - 100 ) ; surface.restore( ) ; } ; TitleState.prototype._displayImage = function( surface ) { surface.save( ) ; if( this.count < TitleState._GLOBALALPHA_SPAN ) surface.globalAlpha = this.count / TitleState._GLOBALALPHA_SPAN ; else surface.globalAlpha = 1.0 ; surface.drawImage( this.getImage( Game._IMG_TITLE_BG ), 0, 0, TitleState._WIDTH, TitleState._HEIGHT, 0, 0, this.opening.getWidth( ), this.opening.getHeight( ) ) ; surface.restore( ) ; } ; TitleState.prototype._displayMessage = function( surface ) { if( this.count < TitleState._GLOBALALPHA_SPAN ) return ; surface.save( ) ; surface.font = "24px 'Comic Sans MS'" ; surface.textAlign = 'center' ; surface.textBaseAlign = 'middle' ; surface.fillStyle = 'rgb( 0, 0, 0 )' ; if( this.count - TitleState._GLOBALALPHA_SPAN < TitleState._GLOBALALPHA_SPAN ) surface.globalAlpha = ( this.count - TitleState._GLOBALALPHA_SPAN ) / TitleState._GLOBALALPHA_SPAN ; else surface.globalAlpha = 1.0 ; surface.fillText( 'Toho like STG JS', 120, 200 ) ; surface.restore( ) ; } ; TitleState.prototype._displayPressKey = function( surface ) { if( this.count < TitleState._GLOBALALPHA_SPAN * 2 ) return ; surface.save( ) ; surface.font = "24px 'Comic Sans MS'" ; surface.textAlign = 'center' ; surface.textBaseAlign = 'middle' ; surface.fillStyle = 'rgb( 0, 0, 0 )' ; if( this.index == 0 ) surface.globalAlpha = 1.0 ; else surface.globalAlpha = 0.2 ; surface.fillText( 'Start', 120, 300 ) ; if( this.index == 1 ) surface.globalAlpha = 1.0 ; else surface.globalAlpha = 0.2 ; surface.fillText( 'Replay', 120, 340 ) ; surface.restore( ) ; } ; TitleState.prototype.handleKeyDown = function( e ) { switch( e.keyCode ) { case 90: // z this.soundEffect( Game._SE_SELECT ) ; if( this.state == TitleState._STATE_DISPLAYED ) { if( this.index == 0 ) this.opening.notifyTitleConclusion( ) ; else this.opening.notifyReplaySelectBegin( ) ; } else { this.state = TitleState._STATE_DISPLAYED ; this.count = TitleState._GLOBALALPHA_SPAN * 2 ; // TODO: temporal } break ; case 38: // up case 40: // down if( this.state == TitleState._STATE_DISPLAYED ) { this.soundEffect( Game._SE_SELECT ) ; if( this.index == 0 ) this.index = 1 ; else this.index = 0 ; } break ; case 32: // space break ; } ; } ; ================================================ FILE: source/PostReplayState.js ================================================ function PostReplayState( game ) { this.parent = GameState ; this.parent.call( this, game ) ; this.count = 0 ; this.index = 0 ; } __inherit( PostReplayState, GameState ) ; PostReplayState._STATE_SELECT = 0x0 ; PostReplayState._STATE_REPLAY_POSTING = 0x1 ; PostReplayState._STATE_REPLAY_POSTING_ERROR = 0x2 ; PostReplayState._DIR = 'http://gachapin.jp/stg/' ; PostReplayState.prototype.init = function( ) { this.count = 0 ; this.index = 0 ; this.state = PostReplayState._STATE_SELECT ; } ; /** * TODO: temporal. implement error handling */ PostReplayState.prototype._postReplay = function( ) { var user = window.prompt( 'your name?' ) ; if( ! user ) return ; var xhr = new XMLHttpRequest( ) ; xhr.open( 'POST', PostReplayState._DIR + 'post.cgi', true ) ; var self = this ; xhr.onload = function( ) { self.game.notifyQuitStage( ) ; // TODO: temporal } ; xhr.onerror = function( e ) { window.alert( e ) ; } ; // TODO: temporal params = this.game.states[ Game._STATE_IN_STAGE ].exportPlayRecord( ) ; params.user = user ; xhr.setRequestHeader( 'Content-Type', 'application/x-www-form-urlencoded' ) ; xhr.send( this._encode( params ) ) ; this.state = PostReplayState._STATE_REPLAY_POSTING ; } ; PostReplayState.prototype._encode = function( data ) { var params = []; for( var name in data ) { var value = data[ name ]; var param = encodeURIComponent( name ).replace( /%20/g, '+' ) + '=' + encodeURIComponent( value ).replace( /%20/g, '+' ); params.push( param ); } return params.join( '&' ); } ; PostReplayState.prototype.runStep = function( ) { this.count++ ; } ; PostReplayState.prototype.updateDisplay = function( surface ) { this.game.clear( surface ) ; this._displayBG( surface ) ; this._displayMessage( surface ) ; if( this.state == PostReplayState._STATE_SELECT ) this._displayQuestion( surface ) ; } ; /** * TODO: temporal */ PostReplayState.prototype._displayBG = function( surface ) { surface.save( ) ; surface.fillStyle = 'rgb( 0, 0, 0 )' ; surface.fillRect( 0, 0, this.getWidth( ), this.getHeight( ) ) ; surface.fillStyle = 'rgb( 255, 255, 255 )' ; surface.fillRect( 0, 50, this.getWidth( ), this.getHeight( ) - 100 ) ; surface.globalAlpha = 0.05 ; surface.drawImage( this.game.getImage( Game._IMG_TITLE_BG ), 0, 0, TitleState._WIDTH, TitleState._HEIGHT, 0, 0, this.getWidth( ), this.getHeight( ) ) ; surface.globalAlpha = 0.5 ; surface.fillStyle = 'rgb( 0, 0, 0 )' ; surface.fillRect( 0, 0, this.getWidth( ), this.getHeight( ) ) ; surface.restore( ) ; } ; PostReplayState.prototype._displayMessage = function( surface ) { surface.save( ) ; surface.font = "30px 'Comic Sans MS'" ; surface.textAlign = 'center' ; surface.textBaseAlign = 'middle' ; surface.fillStyle = 'rgb( 255, 255, 255 )' ; surface.fillText( 'Replay Select', this.getWidth( ) / 2, 35 ) ; // TODO: temporal if( this.state == PostReplayState._STATE_REPLAY_POSTING ) { surface.fillText( 'Saving...', this.getWidth( ) / 2, this.getHeight( ) / 2 ) ; } surface.restore( ) ; } ; PostReplayState.prototype._displayQuestion = function( surface ) { surface.save( ) ; surface.font = "30px 'Comic Sans MS'" ; surface.textAlign = 'center' ; surface.textBaseAlign = 'middle' ; surface.fillStyle = 'rgb( 255, 255, 255 )' ; surface.fillText( 'Will you save your replay?', this.getWidth( ) / 2, 100 ) ; if( this.index == 0 ) surface.globalAlpha = 1.0 ; else surface.globalAlpha = 0.4 ; surface.fillText( 'Yes', this.getWidth( ) / 2, 200 ) ; if( this.index == 1 ) surface.globalAlpha = 1.0 ; else surface.globalAlpha = 0.4 ; surface.fillText( 'No', this.getWidth( ) / 2, 250 ) ; surface.restore( ) ; } ; PostReplayState.prototype.handleKeyDown = function( e ) { switch( e.keyCode ) { case 38: // up case 40: // down this._soundEffect( Game._SE_SELECT ) ; if( this.index == 0 ) this.index = 1 ; else this.index = 0 ; break ; case 90: // z this._soundEffect( Game._SE_SELECT ) ; if( this.index == 0 ) this._postReplay( ) ; else this.game.notifyQuitStage( ) ; // TODO: temporal break ; } ; } ; PostReplayState.prototype.handleKeyUp = function( e ) { } ; ================================================ FILE: source/ReplaySelectState.js ================================================ function ReplaySelectState( game ) { this.parent = GameState ; this.parent.call( this, game ) ; this.count = 0 ; this.index = 0 ; this.list = [ ] ; } __inherit( ReplaySelectState, GameState ) ; ReplaySelectState._STATE_PREPARE = 0x0 ; ReplaySelectState._STATE_LIST_LOADING = 0x1 ; ReplaySelectState._STATE_LIST_LOADING_ERROR = 0x2 ; ReplaySelectState._STATE_SELECT = 0x3 ; ReplaySelectState._STATE_REPLAY_LOADING = 0x4 ; ReplaySelectState._STATE_REPLAY_LOADING_ERROR = 0x5 ; ReplaySelectState._DIR = 'http://gachapin.jp/stg/' ; ReplaySelectState.prototype.init = function( ) { this.count = 0 ; this.index = 0 ; this.list = [ ] ; this.state = ReplaySelectState._STATE_PREPARE ; } ; /** * TODO: temporal. implement error handling */ ReplaySelectState.prototype.loadReplayList = function( ) { var xhr = new XMLHttpRequest( ) ; xhr.open( 'GET', ReplaySelectState._DIR + 'getlist.cgi', true ) ; var self = this ; xhr.onload = function( ) { self.list = JSON.parse( xhr.responseText ).list ; self.list.pop( ) ; self.state = ReplaySelectState._STATE_SELECT ; } ; xhr.onerror = function( e ) { window.alert( e ) ; } ; xhr.send( null ) ; this.state = ReplaySelectState._STATE_LIST_LOADING ; } ; /** * TODO: temporal. implement error handling */ ReplaySelectState.prototype.loadReplay = function( index ) { var xhr = new XMLHttpRequest( ) ; xhr.open( 'GET', ReplaySelectState._DIR + 'get.cgi?id=' + this.list[ this.index ].id , true ) ; var self = this ; xhr.onload = function( ) { var params = JSON.parse( xhr.responseText ) ; self.game.notifyReplaySelectConclusion( params ) ; } ; xhr.onerror = function( e ) { window.alert( e ) ; } ; xhr.send( null ) ; this.state = ReplaySelectState._STATE_REPLAY_LOADING ; } ; ReplaySelectState.prototype.runStep = function( ) { if( this.state == ReplaySelectState._STATE_PREPARE ) { this.loadReplayList( ) ; } this.count++ ; } ; ReplaySelectState.prototype.updateDisplay = function( surface ) { this.game.clear( surface ) ; this._displayBG( surface ) ; this._displayMessage( surface ) ; switch( this.state ) { case ReplaySelectState._STATE_PREPARE: break ; case ReplaySelectState._STATE_LIST_LOADING: break ; case ReplaySelectState._STATE_LIST_LOADING_ERROR: break ; case ReplaySelectState._STATE_SELECT: this._displayList( surface ) ; break ; case ReplaySelectState._STATE_REPLAY_LOADING: break ; case ReplaySelectState._STATE_REPLAY_LOADING_ERROR: break ; } } ; /** * TODO: temporal */ ReplaySelectState.prototype._displayBG = function( surface ) { surface.save( ) ; surface.fillStyle = 'rgb( 0, 0, 0 )' ; surface.fillRect( 0, 0, this.getWidth( ), this.getHeight( ) ) ; surface.fillStyle = 'rgb( 255, 255, 255 )' ; surface.fillRect( 0, 50, this.getWidth( ), this.getHeight( ) - 100 ) ; surface.globalAlpha = 0.05 ; surface.drawImage( this.game.getImage( Game._IMG_TITLE_BG ), 0, 0, TitleState._WIDTH, TitleState._HEIGHT, 0, 0, this.getWidth( ), this.getHeight( ) ) ; surface.globalAlpha = 0.5 ; surface.fillStyle = 'rgb( 0, 0, 0 )' ; surface.fillRect( 0, 0, this.getWidth( ), this.getHeight( ) ) ; surface.restore( ) ; } ; ReplaySelectState.prototype._displayMessage = function( surface ) { surface.save( ) ; surface.font = "30px 'Comic Sans MS'" ; surface.textAlign = 'center' ; surface.textBaseAlign = 'middle' ; surface.fillStyle = 'rgb( 255, 255, 255 )' ; surface.fillText( 'Replay Select', this.getWidth( ) / 2, 35 ) ; // TODO: temporal if( this.state == ReplaySelectState._STATE_LIST_LOADING || this.state == ReplaySelectState._STATE_REPLAY_LOADING ) { surface.fillText( 'Loading...', this.getWidth( ) / 2, this.getHeight( ) / 2 ) ; } surface.restore( ) ; } ; ReplaySelectState.prototype._displayList = function( surface ) { var h = 100 ; var w = 50 ; surface.save( ) ; surface.font = "16px 'Comic Sans MS'" ; surface.textAlign = 'left' ; surface.textBaseAlign = 'middle' ; surface.fillStyle = 'rgb( 255, 255, 255 )' ; for( var i = 0; i < this.list.length; i++ ) { if( i == this.index ) surface.globalAlpha = 1.0 ; else surface.globalAlpha = 0.4 ; surface.fillText( this._buildReplayStrings( this.list[ i ] ), w, h + 20 * i ) ; } surface.restore( ) ; } ; ReplaySelectState.prototype._buildReplayStrings = function( params ) { var buffer = '' ; buffer += params.id + ': ' + params.user + ' ' ; if( params.characterIndex == 0 ) { buffer += 'Reimu' ; } else { buffer += 'Marisa' ; } buffer += ' ' + this._toStringsFromDate( params.datetime ) ; return buffer ; } ; ReplaySelectState.prototype._toStringsFromDate = function( s ) { var date = new Date( s ) ; return [ date.getMonth( ) + 1, date.getDate( ), date.getFullYear( ), ].join( '/' ) + ' ' + [ date.getHours( ), date.getMinutes( ), date.getSeconds( ), ].join( ':' ) ; } ; ReplaySelectState.prototype.handleKeyDown = function( e ) { switch( e.keyCode ) { case 38: // up this.index-- ; if( this.index < 0 ) this.index = 0 ; this._soundEffect( Game._SE_SELECT ) ; break ; case 40: // down this.index++ ; if( this.index >= this.list.length ) this.index = this.list.length - 1 ; this._soundEffect( Game._SE_SELECT ) ; break ; case 88: // x this.game.notifyLoadingConclusion( ) ; // TODO: temporal break ; case 90: // z this.loadReplay( ) ; this._soundEffect( Game._SE_SELECT ) ; break ; } ; } ; ReplaySelectState.prototype.handleKeyUp = function( e ) { } ; ================================================ FILE: source/SpellCard.js ================================================ /** * no plan to port this class to WebGL so far cuz * it cannot be performance critical. */ function SpellCardManager( gameState ) { this.parent = ElementManager ; this.parent.call( this, gameState ) ; } ; __inherit( SpellCardManager, ElementManager ) ; SpellCardManager.prototype._initFactory = function( ) { this.factory = new SpellCardFactory( this.gameState, this.gameState.width, this.gameState.height ) ; } ; SpellCardManager.prototype.create = function( boss ) { this.addElement( this.factory.create( boss ) ) ; } ; function SpellCardFactory( gameState, maxX, maxY ) { this.parent = ElementFactory ; this.parent.call( this, gameState, maxX, maxY ) ; } ; __inherit( SpellCardFactory, ElementFactory ) ; SpellCardFactory.prototype._NUM = 10 ; SpellCardFactory.prototype._FIGHTER_IMAGES = [ Game._IMG_STAND_REIMU, Game._IMG_STAND_MARISA ] ; SpellCardFactory.prototype._ENEMY_IMAGES = [ Game._IMG_STAND_MOKOU, Game._IMG_STAND_RUMIA, Game._IMG_STAND_CHILNO ] ; SpellCardFactory.prototype._PARAMS = [ { 'x': 240, 'y': 240, 'v': { 'r': 3, 'theta':150, 'raa': -0.005, 'rrange': { 'min': 1 } } }, { 'x': 240, 'y': 240, 'v': { 'r': 3, 'theta': 30, 'raa': -0.005, 'rrange': { 'min': 1 } } }, ] ; SpellCardFactory.prototype._initFreelist = function() { this.freelist = new SpellCardFreeList(this._NUM, this.gameState); }; /** * */ SpellCardFactory.prototype.create = function( element ) { var params = element instanceof Fighter ? this._PARAMS[0] : this._PARAMS[1]; var card = this.freelist.get(); card.init(params, this._getImage(element), element); return card; }; SpellCardFactory.prototype._getImage = function( element ) { var image ; var vector = null ; if( element instanceof Fighter ) { vector = { 'r': 3, 'theta':150, 'raa': -0.005, 'rrange': { 'min': 1 } } ; image = this.gameState.getImage( this._FIGHTER_IMAGES[ element.characterIndex ] ) ; image.width = 400 ; } else { vector = { 'r': 3, 'theta': 30, 'raa': -0.005, 'rrange': { 'min': 1 } } ; // TODO: temporary if( element.character == 'rumia' ) { image = this.gameState.getImage( this._ENEMY_IMAGES[ 1 ] ) ; image.width = 600 ; } else if( element.character == 'chilno' ) { image = this.gameState.getImage( this._ENEMY_IMAGES[ 2 ] ) ; image.width = 550 ; } else { image = this.gameState.getImage( this._ENEMY_IMAGES[ 0 ] ) ; image.width = 512 ; } } return image ; } ; function SpellCardFreeList( num, gameState ) { this.parent = ElementFreeList ; this.parent.call( this, num, gameState ) ; } __inherit( SpellCardFreeList, ElementFreeList ) ; SpellCardFreeList.prototype._generateElement = function( ) { return new SpellCard( this.gameState, this.gameState.getWidth( ), this.gameState.getHeight( ) ) ; } ; /** * This class shows Spell card background. * That is character image and spellcard name strings. */ function SpellCard( gameState, maxX, maxY ) { this.parent = Element ; this.parent.call( this, gameState, maxX, maxY ) ; this.boss = null ; this.baseX = 0 ; this.baseY = 0 ; } __inherit( SpellCard, Element ) ; SpellCard.prototype._HEIGHT = 600 ; __copyParentMethod(SpellCard, Element, 'init'); SpellCard.prototype.init = function(params, image, boss) { this.Element_init(params, image); this.boss = boss; this.width = image.width; this.height = this._HEIGHT; this.collisionWidth = this.width; this.collisionHeight = this.height; this.indexX = 0; this.indexY = 0; this.baseX = this.getX(); this.baseY = this.getY(); }; /** * still uses display() method. * TODO: temporal */ __copyParentMethod(SpellCard, Element, 'display'); SpellCard.prototype.display = function(surface) { surface.save(); surface.globalAlpha = 0.4; this.Element_display(surface); this.displaySpellCardName(surface); surface.restore(); // surface.fillText( x + ':' + y, x, y ) ; }; SpellCard.prototype.displaySpellCardName = function(surface) { surface.save(); surface.fillStyle = 'rgb(255, 255, 255)'; surface.textAlign = 'center'; surface.font = '16px Arial'; surface.globalAlpha = 0.8; var x = this.baseX + (this.getX() - this.baseX) / 4; var y = this.baseY + (this.getY() - this.baseY) / 4 + 150; surface.fillText('Spell Card: ' + this.boss.spellCard, x, y); surface.restore(); }; /** * TODO: temporal */ SpellCard.prototype.checkLoss = function( ) { return this.count > 100 ? true : false ; } ; ================================================ FILE: source/StaffRollState.js ================================================ function StaffRollState( game ) { this.parent = GameState ; this.parent.call( this, game ) ; this.count = 0 ; this.finished = false ; } __inherit( StaffRollState, GameState ) ; StaffRollState._MESSAGE_SPEED = 1 ; StaffRollState.prototype.init = function( ) { this.finished = false ; this._soundBGM( Game._BGM_ENDING ) ; } ; StaffRollState.prototype.runStep = function( ) { this.count++ ; } ; StaffRollState.prototype.updateDisplay = function( surface ) { this.game.clear( surface ) ; this._displayBG( surface ) ; this._displayMessage( surface ) ; } ; StaffRollState.prototype._displayBG = function( surface ) { surface.save( ) ; surface.fillStyle = 'rgb( 0, 0, 0 )' ; surface.fillRect( 0, 0, this.getWidth( ), this.getHeight( ) ) ; surface.fillStyle = 'rgb( 255, 255, 255 )' ; surface.fillRect( 0, 50, this.getWidth( ), this.getHeight( ) - 100 ) ; surface.globalAlpha = 0.05 ; surface.drawImage( this.game.getImage( Game._IMG_TITLE_BG ), 0, 0, TitleState._WIDTH, TitleState._HEIGHT, 0, 0, this.getWidth( ), this.getHeight( ) ) ; surface.restore( ) ; } ; StaffRollState.prototype._displayMessage = function( surface ) { var messages = [ ] ; messages.push( '' ) ; messages.push( '' ) ; messages.push( '' ) ; messages.push( '' ) ; messages.push( 'Staff' ) ; messages.push( '' ) ; messages.push( '' ) ; messages.push( '' ) ; messages.push( '' ) ; messages.push( 'Game Engine' ) ; messages.push( '@superhoge' ) ; messages.push( '' ) ; messages.push( 'Anything except for' ) ; messages.push( 'Graphics and Sound' ) ; messages.push( '@superhoge' ) ; messages.push( '' ) ; messages.push( '' ) ; messages.push( 'Original is' ) ; messages.push( 'Touhou Project' ) ; messages.push( 'Team Shanghai Alice' ) ; messages.push( '' ) ; messages.push( '' ) ; messages.push( '' ) ; messages.push( '' ) ; messages.push( '' ) ; messages.push( 'Presented by' ) ; messages.push( 'Toho-like JS project' ) ; messages.push( '' ) ; messages.push( '' ) ; messages.push( '' ) ; messages.push( '' ) ; messages.push( '' ) ; messages.push( '' ) ; messages.push( '' ) ; messages.push( '' ) ; messages.push( '' ) ; messages.push( 'And you.' ) ; surface.save( ) ; surface.font = '30pt Calibri' ; surface.textAlign = 'center' ; surface.textBaseline = 'middle' ; surface.fillStyle = 'rgb( 0, 0, 0 )' ; var dh = 50 ; var max = ( this.getHeight( ) / 2 + dh * messages.length ) / StaffRollState._MESSAGE_SPEED ; var count = ( this.count > max ) ? max : this.count ; // TODO: temporal if( count >= max ) this.finished = true ; var h = this.getHeight( ) - count * StaffRollState._MESSAGE_SPEED ; for( var i = 0; i < messages.length; i++ ) { surface.fillText( messages[ i ], this.getWidth( ) / 2, h + dh * i ) ; } surface.restore( ) ; } ; StaffRollState.prototype.handleKeyDown = function( e ) { switch( e.keyCode ) { case 90: // z if( ! this.finished ) return ; this._soundEffect( Game._SE_SELECT ) ; this.game.notifyQuitStage( true ) ; // TODO: temporal break ; } ; } ; StaffRollState.prototype.handleKeyUp = function( e ) { } ; ================================================ FILE: source/StageState.js ================================================ function StageState( game ) { this.parent = GameState ; this.parent.call( this, game ) ; this.fighter = null; // me this.fighter2 = null; // other this.fighterManager = null; this.fighterOptionManager = null ; this.bulletManager = null ; this.bombManager = null ; this.enemyManager = null ; this.enemyBulletManager = null ; this.effectManager = null ; this.bossManager = null ; this.itemManager = null ; this.spellCardManager = null ; this.spellCard = null ; this.backgroundManager = null; this.params = __stageParams ; // TODO: temporal this.stageIndex = 0 ; this.count = 0 ; this.animationCount = 0 ; this.replayCount = 0 ; this.oldTime = 0 ; this.graze = 0; this.score = 0 ; this.viewScore = 0 ; this.players = 3 ; this.bombs = 2 ; this.bombCount = 0 ; this.bossSpellCount = 0 ; this.pending = 0 ; this.bgScale = 1 ; this.didContinue = false ; this.initialized = false ; // TODO: temporal this.playRecords = [ ] ; this.autoplayIndex = 0 ; this.autoplayParams = [ ] ; this.baseCharacterIndex = 0 ; this.baseCharacterIndex2 = 0 ; this.seed = null ; this.viewFromFighter = false; this.state = this._STATE_SHOOTING ; // this.state = this._STATE_TALK ; // this.state = this._STATE_CLEAR ; this.states = [ ] ; this.states[ this._STATE_SHOOTING ] = new ShootingState( this ) ; this.states[ this._STATE_TALK ] = new TalkState( this ) ; this.states[ this._STATE_CLEAR ] = new ClearState( this ) ; this.states[ this._STATE_GAME_OVER ] = new GameOverState( this ) ; this.keyFlag = 0; this.keyFlags = new KeyFlagQueue(); this.keyFlagHistories = new KeyFlagQueue(); this.keyFlag2 = 0; this.keyFlags2 = new KeyFlagQueue(); this.syncCount = 0; this.lag = this._BUTTON_LAG; this.waitingForOther = false; } __inherit( StageState, GameState ) ; // only for reference StageState.prototype.Randomizer = __randomizer; StageState.prototype._BUTTON_LAG = 1; StageState.prototype._BUTTON_HISTORY = 4; StageState.prototype._BUTTON_LEFT = 0x01; StageState.prototype._BUTTON_UP = 0x02; StageState.prototype._BUTTON_RIGHT = 0x04; StageState.prototype._BUTTON_DOWN = 0x08; StageState.prototype._BUTTON_Z = 0x10; StageState.prototype._BUTTON_X = 0x20; StageState.prototype._BUTTON_SHIFT = 0x40; StageState.prototype._BUTTON_SPACE = 0x80; StageState.prototype._FLAG_FIGHTER_DEAD = 0x1 ; StageState.prototype._FLAG_BOSS_EXIST = 0x2 ; StageState.prototype._FLAG_BOSS_SPELLCARD = 0x4 ; StageState.prototype._FLAG_BOMB = 0x8 ; StageState.prototype._FLAG_STAGE_TITLE = 0x10 ; StageState.prototype._FLAG_SE_ENEMY_DAMAGE = 0x20 ; StageState.prototype._FLAG_SE_ENEMY_VANISH = 0x40 ; StageState.prototype._FLAG_SE_SHOT = 0x80 ; StageState.prototype._FLAG_SE_ENEMY_SHOT = 0x100 ; StageState.prototype._FLAG_SE_DEAD = 0x200 ; StageState.prototype._FLAG_SE_GRAZE = 0x400 ; StageState.prototype._FLAG_SE_POWERUP = 0x800 ; StageState.prototype._FLAG_SE_POWER_EFFECT = 0x1000 ; StageState.prototype._FLAG_AUTO_PLAY = 0x2000 ; StageState.prototype._BOMB_SPAN = 100 ; StageState.prototype._BOSS_SPELL_SPAN = 100 ; StageState.prototype._STAGE_TITLE_SPAN = 300 ; StageState.prototype._STATE_SHOOTING = 0x1 ; StageState.prototype._STATE_TALK = 0x2 ; StageState.prototype._STATE_CLEAR = 0x3 ; StageState.prototype._STATE_GAME_OVER = 0x4 ; StageState.prototype.init = function( params ) { this.state = this._STATE_SHOOTING ; if(params.lag !== void 0) this.lag = params.lag; this.keyFlag = 0; this.keyFlag2 = 0; this.keyFlags.free(); this.keyFlags2.free(); this.keyFlagHistories.free(); for(var i = 0; i < this.lag; i++) { this.keyFlags.push(0); this.keyFlags2.push(0); this.keyFlagHistories.push(0); } this.syncCount = 0; this.waitingForOther = false; this.viewFromFighter = false; if( ! this.initialized ) { this._initBackground(); this._initFighter( ) ; this._initEnemies( ) ; this._initBullets( ) ; this._initBomb( ) ; this._initEnemyBullets( ) ; this._initItems( ) ; this._initSpellCards( ) ; this.initialized = true ; } else { this.reset( ) ; } if( params.autoplay ) { this.setFlag( this._FLAG_AUTO_PLAY ) ; this.autoplayParams = params.autoplayParams.params ; this.seed = params.autoplayParams.seed ; this.baseCharacterIndex = params.autoplayParams.characterIndex ; } else { this.clearFlag( this._FLAG_AUTO_PLAY ) ; this.seed = params.seed; this.baseCharacterIndex = params.characterIndex ; this.baseCharacterIndex2 = params.characterIndex2; } this.fighter.setCharacterIndex(this.baseCharacterIndex); if(this.game.isMultiPlay()) { this.fighter2.setCharacterIndex(this.baseCharacterIndex2); } this.Randomizer.seed( this.seed ) ; this._soundBGM( Game._BGM_1 ) ; this.sendMessageToServer(GameSocket._STATE_BEGIN_GAME); } ; StageState.prototype._initBackground = function() { this.backgroundManager = new BackgroundManager(this); this.backgroundManager.initDrawer(this.game.bgLayer, null); }; /** * TODO: temporal */ StageState.prototype._initFighter = function() { this.fighterManager = new FighterManager(this); // TODO: temporal if(this.game.isMultiPlay()) { this.fighter = this.fighterManager.getMe(this.game.isMaster()); this.fighter2 = this.fighterManager.getOther(this.game.isMaster()); } else { this.fighter = this.fighterManager.getFighter(); } this.fighterManager.initDrawer(this.game.bgLayer, null); this.fighterOptionManager = new FighterOptionManager( this, this.fighterManager.elements); this.fighterOptionManager.initDrawer(this.game.bgLayer, null); }; StageState.prototype._initEnemies = function( ) { this.enemyManager = new EnemyManager( this, __enemiesParams ) ; this.bossManager = new BossManager( this, __bossesParams ) ; this.effectManager = new EffectManager( this ) ; this.enemyManager.initDrawer(this.game.bgLayer, null); this.bossManager.initDrawer(this.game.bgLayer, null); this.effectManager.initDrawer(this.game.bgLayer, null); } ; StageState.prototype._initBullets = function() { this.bulletManager = new BulletManager(this, __bulletsParams); this.bulletManager.initDrawer(this.game.bgLayer, null); }; StageState.prototype._initBomb = function() { this.bombManager = new BombManager(this); this.bombManager.initDrawer(this.game.bgLayer, null); }; StageState.prototype._initEnemyBullets = function() { this.enemyBulletManager = new EnemyBulletManager(this, __enemyBulletsParams); this.enemyBulletManager.initDrawer(this.game.bgLayer, null); }; StageState.prototype._initItems = function() { this.itemManager = new ItemManager(this); this.itemManager.initDrawer(this.game.bgLayer, null); }; StageState.prototype._initSpellCards = function( ) { this.spellCardManager = new SpellCardManager( this ) ; } ; StageState.prototype._start = function() { this.peer.send({id: this._PEER_ID_START, seed: this.seed}); }; StageState.prototype.runStep = function( ) { if( this.isFlagSet( this._FLAG_AUTO_PLAY ) && this.autoplayIndex < this.autoplayParams.length ) { this._actAsRecord( ) ; // TODO: temporal } else if(! this.isFlagSet(this._FLAG_AUTO_PLAY)) { this.keyFlags.push(this.keyFlag); this.keyFlagHistories.push(this.keyFlag); this.keyFlagHistories.shiftUntilLengthIs(this._BUTTON_HISTORY); this._deployKeyFlag(this.keyFlags.shift(), this.fighter); if(this.game.isMultiPlay()) { this._deployKeyFlag(this.keyFlags2.shift(), this.fighter2); } } this.replayCount++; this.syncCount++; // TODO: temporal if( this.state == this._STATE_SHOOTING ) { this._updateBGScale( ) ; this.enemyManager.runStep( ) ; this.effectManager.runStep( ) ; this.bossManager.runStep( ) ; this.enemyBulletManager.runStep( ) ; this.itemManager.runStep( ) ; this.fighterManager.runStep( ) ; this.fighterOptionManager.runStep( ) ; this.bulletManager.runStep( ) ; this.bombManager.runStep( ) ; this.spellCardManager.runStep( ) ; this.enemyBulletManager.checkGrazeWithFighters(this.fighterManager.elements); this.bulletManager.checkCollisionWithEnemies(this.enemyManager.elements); this.enemyManager.checkCollisionWithFighters(this.fighterManager.elements); this.enemyBulletManager.checkCollisionWithFighters(this.fighterManager.elements); this.itemManager.checkCollisionWithFighters(this.fighterManager.elements); if( this.bossManager.existBoss()) { this.bulletManager.checkCollisionWithBoss(this.bossManager.getBoss()); this.bossManager.checkCollisionWithFighters(this.fighterManager.elements); } this.enemyManager.checkLoss( ) ; this.effectManager.checkLoss( ) ; this.bulletManager.checkLoss( ) ; this.bombManager.checkLoss( ) ; this.enemyBulletManager.checkLoss( ) ; this.itemManager.checkLoss( ) ; this.bossManager.checkLoss( ) ; this.spellCardManager.checkLoss( ) ; this._soundEffectDependsOnFlag( ) ; // TODO: temporal if( this.isFlagSet( this._FLAG_FIGHTER_DEAD ) && ! this.fighter.isFlagSet( this.fighter._FLAG_UNHITTABLE ) ) this.clearFlag( this._FLAG_FIGHTER_DEAD ) ; if( this.isFlagSet( this._FLAG_BOMB ) && this.count > this.bombCount + this._BOMB_SPAN ) this.clearFlag( this._FLAG_BOMB ) ; // TODO: temporal if( this.isFlagSet( this._FLAG_BOSS_SPELLCARD ) && this.count > this.bossSpellCount + this._BOSS_SPELL_SPAN ) this.clearFlag( this._FLAG_BOSS_SPELLCARD ) ; if( this.isFlagSet( this._FLAG_BOSS_EXIST ) ) this.pending++ ; if( this.count < this._STAGE_TITLE_SPAN ) { this.setFlag( this._FLAG_STAGE_TITLE ) ; } else { this.clearFlag( this._FLAG_STAGE_TITLE ) ; } } if(this.score > this.viewScore) { this.viewScore += 1000; if(this.viewScore > this.score) this.viewScore = this.score; } this.states[ this.state ].runStep( ) ; this.backgroundManager.runStep(); this.animationCount++ ; // TODO: temporal // this member should be moved to ShootingState? if( this.state == this._STATE_SHOOTING ) { this.count++ ; } // TODO: temporal if(this.game.isMultiPlay()) this._sync(); // TODO: temporal this.keyFlag = this.states[this.state].resetButton(this.keyFlag); } ; // TODO: temporal StageState.prototype.doRunNextStep = function() { return this.game.isMultiPlay() ? false : true; }; /** * TODO: temporal. Should be in Background? */ StageState.prototype._updateBGScale = function( ) { if( ! this.params[ this.stageIndex ].bgScale ) return ; if( this.isFlagSet( this._FLAG_BOSS_EXIST ) ) return ; for( var i = 0; i < this.params[ this.stageIndex ].bgScale.length; i++ ) { var value = this.params[ this.stageIndex ].bgScale[ i ] ; if( this.count >= value.beginCount + this.pending && this.count < value.endCount + this.pending ) { if( value.a ) this.bgScale = value.a ; if( value.d ) this.bgScale += value.d ; } } } ; /** * TODO: temporal */ StageState.prototype._soundEffectDependsOnFlag = function( ) { var game = Game; if( this.isFlagSet( this._FLAG_SE_ENEMY_VANISH ) ) { this._soundEffect( game._SE_ENEMY_VANISH ) ; this.clearFlag( this._FLAG_SE_ENEMY_VANISH ) ; if( this.isFlagSet( this._FLAG_SE_ENEMY_DAMAGE ) ) { this.clearFlag( this._FLAG_SE_ENEMY_DAMAGE ) ; } } if( this.isFlagSet( this._FLAG_SE_ENEMY_DAMAGE ) ) { this._soundEffect( game._SE_ENEMY_DAMAGE ) ; this.clearFlag( this._FLAG_SE_ENEMY_DAMAGE ) ; } if( this.isFlagSet( this._FLAG_SE_SHOT ) ) { this._soundEffect( game._SE_SHOT ) ; this.clearFlag( this._FLAG_SE_SHOT ) ; } if( this.isFlagSet( this._FLAG_SE_ENEMY_SHOT ) ) { this._soundEffect( game._SE_ENEMY_SHOT ) ; this.clearFlag( this._FLAG_SE_ENEMY_SHOT ) ; } if( this.isFlagSet( this._FLAG_SE_DEAD ) ) { this._soundEffect( game._SE_DEAD ) ; this.clearFlag( this._FLAG_SE_DEAD ) ; } if( this.isFlagSet( this._FLAG_SE_GRAZE ) ) { this._soundEffect( game._SE_GRAZE ) ; this.clearFlag( this._FLAG_SE_GRAZE ) ; } if( this.isFlagSet( this._FLAG_SE_POWERUP ) ) { this._soundEffect( game._SE_POWERUP ) ; this.clearFlag( this._FLAG_SE_POWERUP ) ; } if( this.isFlagSet( this._FLAG_SE_POWER_EFFECT ) ) { this._soundEffect( game._SE_POWER_EFFECT ) ; this.clearFlag( this._FLAG_SE_POWER_EFFECT ) ; } } ; /** * Order is important. */ StageState.prototype.updateDisplay = function( surface ) { this.game.clear( surface ) ; this.game.bgLayer.clear(); this._displayBG(); this._displayElements( surface ) ; this._displayBossVital( surface ) ; this._displayStageTitle( surface ) ; this.states[ this.state ].updateDisplay( surface ) ; this._drawSide( surface ) ; } ; /** * TODO: temporal */ StageState.prototype._displayBG = function() { var darken = false; if(this.isFlagSet(this._FLAG_BOMB) || this.spellCard) { darken = true; } this.backgroundManager.draw(this.game.bgLayer, darken); }; StageState.prototype._displayBossVital = function( surface ) { if( ! this.isFlagSet( this._FLAG_BOSS_EXIST ) ) return ; surface.save( ) ; surface.fillStyle = 'rgb( 255, 255, 255 )' ; // surface.globalAlpha = 0.2 ; // surface.fillRect( 50, 15, 380 * 1, 5 ) ; surface.globalAlpha = 0.8 ; surface.fillRect( 50, 15, 380 * this.bossManager.getBoss( ).vital / this.bossManager.getBoss( ).maxVital, 5 ) ; // TODO: temporal if( this.spellCard ) { surface.fillStyle = 'rgb( 0, 0, 0 )' ; surface.globalAlpha = 0.4 ; surface.fillRect( 50, 22, 380, 24 ) ; surface.fillStyle = 'rgb( 255, 255, 255 )' ; surface.textAlign = 'right' ; surface.textBaseAlign = 'middle' ; surface.font = '16px Arial' ; surface.globalAlpha = 0.8 ; surface.fillText( 'Spell Card: ' + this.spellCard, 420, 40 ) ; } surface.restore( ) ; } ; /** * The order is important. */ StageState.prototype._displayElements = function( surface ) { this.bulletManager.draw(this.game.bgLayer); this.fighterManager.draw(this.game.bgLayer); this.fighterOptionManager.draw(this.game.bgLayer); this.bombManager.draw(this.game.bgLayer); this.enemyManager.draw(this.game.bgLayer); this.bossManager.draw(this.game.bgLayer); this.effectManager.draw(this.game.bgLayer); this.enemyBulletManager.draw(this.game.bgLayer); this.itemManager.draw(this.game.bgLayer); this.spellCardManager.display(surface); } ; StageState.prototype._displayStageTitle = function( surface ) { if( ! this.isFlagSet( this._FLAG_STAGE_TITLE ) ) return ; surface.save( ) ; var alpha = 1.0 ; if( this.count < 100 ) alpha = 0.01 * this.count ; else if( this.count > this._STAGE_TITLE_SPAN - 100 ) alpha = 0.01 * ( this._STAGE_TITLE_SPAN - this.count ) ; surface.fillStyle = 'rgb( 0, 0, 0 )' ; surface.globalAlpha = alpha * 0.2 ; surface.fillRect( 0, 170, 480, 100 ) ; surface.globalAlpha = alpha ; surface.fillStyle = 'rgb( 255, 255, 255 )' ; surface.textAlign = 'left' ; surface.font = '16px Arial' ; surface.fillText( 'Stage' + ( this.stageIndex + 1 ), 100, 210 ) ; surface.textAlign = 'right' ; surface.fillText( this.params[ this.stageIndex ].title, 380, 250 ) ; surface.fillRect( 100, 225, 280, 1 ) ; surface.restore( ) ; } ; /** * TODO: remove strings? */ StageState.prototype._drawSide = function(surface) { surface.save(); surface.fillStyle = 'rgb(0, 0, 0)' ; surface.fillRect(this.getWidth(), 0, Game._SIDE_WIDTH, this.getHeight()); surface.fillStyle = 'rgb(255, 255, 255)'; surface.fillRect(this.getWidth(), 0, 2, this.getHeight()); surface.drawImage(this._getFaceImage(), this.getWidth() + 30, 330, 100, 100); surface.font = '16px Arial'; surface.fillText('Toho-like STG JS', this.getWidth( ) + 15, 70); surface.fillText('for debug', this.getWidth( ) + 15, 210); surface.textAlign = 'right'; surface.fillText('Score:', this.getWidth() + 70, 100); surface.fillText(this.viewScore, this.getWidth() + 140, 100); surface.fillText('Power:', this.getWidth() + 70, 120); surface.fillText(this.fighter.getPower(), this.getWidth() + 140, 120); surface.fillText('Graze:', this.getWidth() + 70, 140); surface.fillText(this.graze, this.getWidth() + 140, 140); surface.fillText('Players:', this.getWidth() + 70, 160); surface.fillText(this.players, this.getWidth() + 140, 160); surface.fillText('Bomb:', this.getWidth() + 70, 180); surface.fillText(this.bombs, this.getWidth() + 140, 180); surface.fillText(this.count, this.getWidth() + 80, 230); surface.fillText(this.bulletManager.getNum(), this.getWidth() + 80, 250); surface.fillText(this.enemyManager.getNum(), this.getWidth() + 80, 270); surface.fillText(this.enemyBulletManager.getNum(), this.getWidth() + 80, 290); surface.fillText(this.itemManager.getNum(), this.getWidth() + 80, 310); surface.fillText(parseInt(this.bgScale*1000), this.getWidth() + 140, 230); surface.fillText(this.effectManager.getNum(), this.getWidth() + 140, 250); surface.restore(); }; StageState.prototype._getFaceImage = function( ) { switch( this.fighter.characterIndex ) { case 0: if( this.isFlagSet( this._FLAG_BOMB ) ) return this.getImage( Game._IMG_REIMU_FACE_4 ) ; if( this.isFlagSet( this._FLAG_FIGHTER_DEAD ) ) return this.getImage( Game._IMG_REIMU_FACE_3 ) ; if( this.fighter.isFlagSet( this.fighter._FLAG_SHOT ) ) return this.getImage( Game._IMG_REIMU_FACE_2 ) ; return this.getImage( Game._IMG_REIMU_FACE_1 ) ; // case 1: default: if( this.isFlagSet( this._FLAG_BOMB ) ) return this.getImage( Game._IMG_MARISA_FACE_4 ) ; if( this.isFlagSet( this._FLAG_FIGHTER_DEAD ) ) return this.getImage( Game._IMG_MARISA_FACE_3 ) ; if( this.fighter.isFlagSet( this.fighter._FLAG_SHOT ) ) return this.getImage( Game._IMG_MARISA_FACE_2 ) ; return this.getImage( Game._IMG_MARISA_FACE_1 ) ; } } ; StageState.prototype.handleKeyDown = function( e ) { // TODO: temporal if(e.keyCode == 89) // y this.viewFromFighter = ~this.viewFromFighter; if( this.isFlagSet( this._FLAG_AUTO_PLAY ) ) return ; // this.states[ this.state ].handleKeyDown( e ) ; this.keyFlag = this._pushButton(e, this.keyFlag); } ; StageState.prototype.handleKeyUp = function( e ) { if( this.isFlagSet( this._FLAG_AUTO_PLAY ) ) return ; // this.states[ this.state ].handleKeyUp( e ) ; this.keyFlag = this._releaseButton(e, this.keyFlag); } ; /** * TODO: temporal */ StageState.prototype._actAsRecord = function( ) { while( this.replayCount >= this.autoplayParams[ this.autoplayIndex ].count ) { for( var key in this.autoplayParams[ this.autoplayIndex ] ) { if( key == 'count' ) continue ; var e = { } ; e.keyCode = this._toCharCode( key ) ; if( this.autoplayParams[ this.autoplayIndex ][ key ] ) { this.states[ this.state ].handleKeyDown(e, this.fighter); } else { this.states[ this.state ].handleKeyUp(e, this.fighter); } } this.autoplayIndex++ ; if( this.autoplayIndex >= this.autoplayParams.length ) break ; } } ; StageState.prototype._toCharCode = function( str ) { switch( str ) { case 's': return 16 ; case 'sp': return 32 ; case 'l': return 37 ; case 'u': return 38 ; case 'r': return 39 ; case 'd': return 40 ; case 'x': return 88 ; case 'z': return 90 ; // default: // throw Error( ) ; } } ; /** * TODO: temporal */ StageState.prototype.reset = function( ) { this.stageIndex = 0 ; this.count = 0 ; this.animationCount = 0 ; this.replayCount = 0 ; this.oldTime = 0 ; this.graze = 0; this.score = 0 ; this.viewScore = 0 ; this.players = 3 ; this.bombs = 2 ; this.bombCount = 0 ; this.bossSpellCount = 0 ; this.pending = 0 ; this.bgScale = 1 ; this.playRecords = [ ] ; this.autoplayIndex = 0 ; this.spellCard = null ; this.didContinue = false ; this.fighterManager.reset( ) ; this.fighterOptionManager.reset( ) ; this.enemyManager.reset( ) ; this.effectManager.reset( ) ; this.bossManager.reset( ) ; this.bombManager.reset( ) ; this.bulletManager.reset( ) ; this.enemyBulletManager.reset( ) ; this.effectManager.reset( ) ; this.itemManager.reset( ) ; this.spellCardManager.reset( ) ; this.backgroundManager.reset(); this.states[ this._STATE_TALK ].reset( ) ; // TODO: temporal this.flags = 0 ; } ; /** * @param record Array */ StageState.prototype.putKeyOnRecord = function( record ) { if( this.didContinue ) return ; var h = { 'count': this.replayCount } ; for( var i = 0; i < record.length; i++ ) h[ record[ i ] ] = true ; this.playRecords.push( h ) ; } ; /** * @param record Array */ StageState.prototype.putKeyOffRecord = function( record ) { if( this.didContinue ) return ; var h = { 'count': this.replayCount } ; for( var i = 0; i < record.length; i++ ) h[ record[ i ] ] = false ; this.playRecords.push( h ) ; } ; /** * TODO: temporal */ StageState.prototype.exportPlayRecord = function( ) { var params = { } ; params.characterIndex = this.baseCharacterIndex ; params.seed = this.seed ; params.user = 'user' ; // TODO: temporal params.datetime = new Date( ).getTime( ) ; var buffer = '' ; buffer += '[\n' ; for( var i = 0; i < this.playRecords.length; i++ ) { var b = '{' ; var initialized = false ; for( var key in this.playRecords[ i ] ) { if( initialized ) b += ', ' ; b += '"' + key + '": ' + this.playRecords[ i ][ key ] ; initialized = true ; } b += '}' ; buffer += ' ' + b ; if( i != this.playRecords.length - 1 ) buffer += ',\n' ; else buffer += '\n' ; } buffer += ']' ; params.params = buffer ; return params ; } ; StageState.prototype.sendMessageToServer = function(key) { this.game.sendMessageToServer(key); }; StageState.prototype.notifyFighterGotPowerItem = function( fighter, item ) { this.setFlag( this._FLAG_SE_GRAZE ) ; this.score += 100 ; fighter.incrementPower( 1 ) ; } ; StageState.prototype.notifyFighterGotScoreItem = function( fighter, item ) { this.setFlag( this._FLAG_SE_GRAZE ) ; this.score += 1000 ; } ; StageState.prototype.notifyFighterPowerUp = function( ) { this.setFlag( this._FLAG_SE_POWERUP ) ; } ; StageState.prototype.notifyFighterDoShot = function( fighter ) { if( this.count % 5 != 0 ) return ; this.bulletManager.create( fighter ) ; this.setFlag( this._FLAG_SE_SHOT ) ; } ; StageState.prototype.notifyEnemyDoShot = function( enemy, shot ) { this.enemyBulletManager.create( enemy, shot ) ; } ; StageState.prototype.notifyEnemyDidShot = function( enemy, shot ) { if( ! this.isFlagSet( this._FLAG_BOMB ) && ! this.isFlagSet( this._FLAG_BOSS_SPELLCARD ) ) this.setFlag( this._FLAG_SE_ENEMY_SHOT ) ; } ; StageState.prototype.notifyBulletHit = function( bullet, enemy ) { this.effectManager.createDamageEffect( enemy ) ; this.setFlag( this._FLAG_SE_ENEMY_DAMAGE ) ; this.score += 10 ; } ; StageState.prototype.notifyGraze = function(fighter, bullet) { this.setFlag(this._FLAG_SE_GRAZE); this.graze += 1; bullet.graze -= 1; // TODO: should be in EnemyBullet? this.score += 100; this.effectManager.createGraze(fighter, bullet); }; /** * TODO: temporal */ StageState.prototype.notifyFighterDoBomb = function( fighter ) { if( this.bombs <= 0 ) return ; if( this.isFlagSet( this._FLAG_BOMB ) ) return ; this.bombs-- ; this.bombCount = this.count ; this.setFlag( this._FLAG_BOMB ) ; this.enemyManager.bomb( fighter ) ; this.enemyBulletManager.bomb( fighter ) ; this.itemManager.beHomingAll( fighter ) ; this.spellCardManager.create( fighter ) ; this.bombManager.create( fighter ) ; this.setFlag( this._FLAG_SE_POWER_EFFECT ) ; } ; StageState.prototype.notifyEnemyVanished = function( bullet, enemy ) { this.setFlag( this._FLAG_SE_ENEMY_VANISH ) ; // TODO: temporal if( enemy.powerItem ) this.itemManager.createPowerItem(enemy); else if( enemy.scoreItem ) this.itemManager.createScoreItem(enemy); this.effectManager.createExplosion(enemy); this.notifyDoEffect( enemy, 'shockwave', null ) ; this.score += 100 ; } ; StageState.prototype.notifyBossVanished = function( boss ) { this.enemyBulletManager.beItem(this.fighterManager.getClosestFighter(boss)); // TODO: temporal this.setFlag( this._FLAG_SE_ENEMY_VANISH ) ; this.spellCard = null ; this.clearFlag( this._FLAG_BOSS_EXIST ) ; this.score += boss.score ; // TODO: temporal if(this.stageIndex == 0 && this.bossManager.index == 1) this.sendMessageToServer(GameSocket._STATE_DESTROY_STAGE1_MID_BOSS); else if(this.stageIndex == 0 && this.bossManager.index == 2) this.sendMessageToServer(GameSocket._STATE_DESTROY_STAGE1_BIG_BOSS); else if(this.stageIndex == 1 && this.bossManager.index == 1) this.sendMessageToServer(GameSocket._STATE_DESTROY_STAGE2_MID_BOSS); else if(this.stageIndex == 1 && this.bossManager.index == 2) this.sendMessageToServer(GameSocket._STATE_DESTROY_STAGE2_BIG_BOSS); } ; StageState.prototype.notifyBossVanishEnd = function( boss ) { if( boss.vanishedTalk ) { this.state = this._STATE_TALK ; this.fighterManager.beNeutral( ) ; // TODO: temporal. consider if desync can occur. for(var i = 0; i < this.lag; i++) { this.keyFlags.set(i, this.states[this.state].resetButton(this.keyFlags.get(i))); } for(var i = 0; i < this._BUTTON_HISTORY; i++) { this.keyFlags2.set(i, this.states[this.state].resetButton(this.keyFlags2.get(i))); this.keyFlagHistories.set(i, this.states[this.state].resetButton(this.keyFlagHistories.get(i))); } } // this.state = this._STATE_CLEAR ; } ; /** * TODO: temporal. especially name is temporal. */ StageState.prototype.notifyBeginTalk = function() { this.state = this._STATE_TALK; this.fighterManager.beNeutral(); // TODO: temporal. consider if desync can occur. for(var i = 0; i < this.lag; i++) { this.keyFlags.set(i, this.states[this.state].resetButton(this.keyFlags.get(i))); } for(var i = 0; i < this._BUTTON_HISTORY; i++) { this.keyFlags2.set(i, this.states[this.state].resetButton(this.keyFlags2.get(i))); this.keyFlagHistories.set(i, this.states[this.state].resetButton(this.keyFlagHistories.get(i))); } }; /** * TODO: temporal */ StageState.prototype.notifyFighterDead = function( fighter, element ) { this.setFlag( this._FLAG_FIGHTER_DEAD ) ; this.setFlag( this._FLAG_SE_DEAD ) ; this.effectManager.createExplosion(fighter); this.notifyDoEffect(fighter, 'shockwave', null); fighter.setFlag( fighter._FLAG_UNHITTABLE ) ; fighter.deadCount = fighter.count ; if( this.players <= 0 ) { this.sendMessageToServer(GameSocket._STATE_GAME_OVER); // TODO: temporal if( this.isFlagSet( this._FLAG_AUTO_PLAY ) ) { this.game.notifyQuitStage( ) ; return ; } this.state = this._STATE_GAME_OVER ; this.states[ this.state ].init( ) ; fighter.beNeutral( ) ; // TODO: temporal. consider if desync can occur. for(var i = 0; i < this.lag; i++) { this.keyFlags.set(i, this.states[this.state].resetButton(this.keyFlags.get(i))); } for(var i = 0; i < this._BUTTON_HISTORY; i++) { this.keyFlags2.set(i, this.states[this.state].resetButton(this.keyFlags2.get(i))); this.keyFlagHistories.set(i, this.states[this.state].resetButton(this.keyFlagHistories.get(i))); } return ; } this.bombs = 2 ; this.players-- ; fighter.state = fighter._STATE_ALIVE ; fighter.beDefaultPosition( ) ; fighter.deadCount = fighter.count ; this.sendMessageToServer(GameSocket._STATE_DEAD); } ; /** * TODO: temporal */ StageState.prototype.notifyDoEffect = function( element, type, params ) { if(type == 'shockwave' && params) this.effectManager.createBigShockWave( element, type, params ) ; else this.effectManager.create( element, type, params ) ; } ; StageState.prototype.notifyBossAppeared = function( boss ) { } ; StageState.prototype.notifyBossStageChanged = function( boss ) { // this.enemyBulletManager.removeBulletsOfEnemy( boss ) ; this.enemyBulletManager.beItem(this.fighterManager.getClosestFighter(boss)); // TODO: temporal } ; /** * TODO: temporal */ StageState.prototype.notifyBeScoreItem = function(fighter, element) { this.itemManager.createHoming(fighter, element); }; StageState.prototype.notifyBossBecameActive = function( boss ) { this.state = this._STATE_SHOOTING ; if( boss.spellCard ) { this.spellCardManager.create( boss ) ; this.setFlag( this._FLAG_SE_POWER_EFFECT ) ; this.spellCard = boss.spellCard ; this.bossSpellCount = this.count ; this.setFlag( this._FLAG_BOSS_SPELLCARD ) ; } this.setFlag( this._FLAG_BOSS_EXIST ) ; } ; StageState.prototype.notifyBossBeginTalk = function( boss ) { // TODO: temporal if( boss.appearedTalk ) { this.state = this._STATE_TALK ; this.fighterManager.beNeutral( ) ; // TODO: temporal. consider if desync can occur. for(var i = 0; i < this.lag; i++) { this.keyFlags.set(i, this.states[this.state].resetButton(this.keyFlags.get(i))); } for(var i = 0; i < this._BUTTON_HISTORY; i++) { this.keyFlags2.set(i, this.states[this.state].resetButton(this.keyFlags2.get(i))); this.keyFlagHistories.set(i, this.states[this.state].resetButton(this.keyFlagHistories.get(i))); } } else { this.notifyBossBecameActive( boss ) ; } } ; StageState.prototype.notifyBossMovedNextStage = function( boss ) { this.clearFlag( this._FLAG_BOSS_SPELLCARD ) ; // Just in case. this.setFlag( this._FLAG_SE_ENEMY_VANISH ) ; this.spellCard = null ; this.notifyDoEffect( boss, 'shockwave', { 'w': 5, 'g': 5, 'a': 0.1, 'b': 20, 'endCount': 50 } ) ; } ; StageState.prototype.notifyContinue = function( ) { this.didContinue = true ; this.bombs = 2 ; this.players = 3; // TODO: template this.fighterManager.recoverWhenContinue(); this.state = this._STATE_SHOOTING ; } ; StageState.prototype.notifyQuit = function( ) { this.game.notifyQuitStage( true ) ; } ; StageState.prototype.notifyGoNextStage = function( ) { this.state = this._STATE_SHOOTING ; this.count = 0 ; this.animationCount = 0 ; this.pending = 0 ; this.enemyManager.goNextStage( ) ; this.bossManager.goNextStage( ) ; this.backgroundManager.goNextStage(); } ; StageState.prototype.notifyGameClear = function( ) { // TODO: temporal if( this.isFlagSet( this._FLAG_AUTO_PLAY ) ) { this.game.notifyQuitStage( ) ; } else { this.game.notifyGameClear( ) ; } } ; StageState.prototype.notifyStageClear = function( ) { this.clearFlag( this._FLAG_BOSS_SPELLCARD ) ; // Just in case. this.state = this._STATE_CLEAR ; this.states[ this.state ].init( ) ; // TODO: temporal this.viewScore = this.score ; } ; /** * TODO: rename */ StageState.prototype.isBossExist = function() { return this.isFlagSet(this._FLAG_BOSS_EXIST); }; /** * TODO: rename */ StageState.prototype.isBombExist = function() { return this.isFlagSet(this._FLAG_BOMB); }; /** * TODO: temporal */ StageState.prototype.getWidth = function( ) { return this.game.width - Game._SIDE_WIDTH ; } ; StageState.prototype._pushButton = function(e, flag) { switch(e.keyCode) { case 16: // shift flag |= this._BUTTON_SHIFT; break; case 32: // space flag |= this._BUTTON_SPACE; break; case 37: // left flag |= this._BUTTON_LEFT; break; case 38: // up flag |= this._BUTTON_UP; break; case 39: // right flag |= this._BUTTON_RIGHT; break; case 40: // down flag |= this._BUTTON_DOWN; break; // TODO: temporal case 88: // x flag |= this._BUTTON_X; break; case 90: // z flag |= this._BUTTON_Z; break; }; return flag; }; StageState.prototype._releaseButton = function(e, flag) { switch(e.keyCode) { case 16: // shift flag &= ~this._BUTTON_SHIFT; break; case 32: // space flag &= ~this._BUTTON_SPACE; break; case 37: // left flag &= ~this._BUTTON_LEFT; break; case 38: // up flag &= ~this._BUTTON_UP; break; case 39: // right flag &= ~this._BUTTON_RIGHT; break; case 40: // down flag &= ~this._BUTTON_DOWN; break; case 88: // x flag &= ~this._BUTTON_X; break; case 90: // z flag &= ~this._BUTTON_Z; break; }; return flag; }; // TODO: temporal StageState.prototype._deployKeyFlag = function(flag, fighter) { var e = {}; e.keyCode = 16; if(flag & this._BUTTON_SHIFT) { this.states[this.state].handleKeyDown(e, fighter); } else { this.states[this.state].handleKeyUp(e, fighter); } e.keyCode = 32; if(flag & this._BUTTON_SPACE) { this.states[this.state].handleKeyDown(e, fighter); } else { this.states[this.state].handleKeyUp(e, fighter); } e.keyCode = 37; if(flag & this._BUTTON_LEFT) { this.states[this.state].handleKeyDown(e, fighter); } else { this.states[this.state].handleKeyUp(e, fighter); } e.keyCode = 38; if(flag & this._BUTTON_UP) { this.states[this.state].handleKeyDown(e, fighter); } else { this.states[this.state].handleKeyUp(e, fighter); } e.keyCode = 39; if(flag & this._BUTTON_RIGHT) { this.states[this.state].handleKeyDown(e, fighter); } else { this.states[this.state].handleKeyUp(e, fighter); } e.keyCode = 40; if(flag & this._BUTTON_DOWN) { this.states[this.state].handleKeyDown(e, fighter); } else { this.states[this.state].handleKeyUp(e, fighter); } e.keyCode = 88; if(flag & this._BUTTON_X) { this.states[this.state].handleKeyDown(e, fighter); } else { this.states[this.state].handleKeyUp(e, fighter); } e.keyCode = 90; if(flag & this._BUTTON_Z) { this.states[this.state].handleKeyDown(e, fighter); } else { this.states[this.state].handleKeyUp(e, fighter); } }; StageState.prototype._SYNC_CONTAINER = {m: null, a: null}; StageState.prototype._sync = function() { var c = this._SYNC_CONTAINER; c.m = this.keyFlagHistories.min; c.a = this.keyFlagHistories.getValues(); this.game.sync(c); this._runNextStepIfPossible(); }; StageState.prototype.receiveFromPeer = function(data) { this.keyFlags2.insertValues(data.m, data.a); if(this.waitingForOther) this._runNextStepIfPossible(); }; StageState.prototype._runNextStepIfPossible = function() { if(this.keyFlags2.hasValueOfCount(this.syncCount)) { this.waitingForOther = false; this.game.runNextStep(); } else { this.waitingForOther = true; } }; StageState.prototype.doLookAtFromViewpointTarget = function() { return this.viewFromFighter; }; StageState.prototype.getViewpointTarget = function() { return this.fighter; }; /** * TODO: optimize and rename */ function KeyFlagQueue() { this.min = 0; this.max = -1; this.values = []; } KeyFlagQueue.prototype._NONE = -1; KeyFlagQueue.prototype.free = function() { this.min = 0; this.max = -1; this.values.length = 0; }; KeyFlagQueue.prototype.getLength = function() { return this.values.length; }; KeyFlagQueue.prototype.get = function(index) { return this.values[index]; }; KeyFlagQueue.prototype.set = function(index, flag) { if(index < this.values.length) this.values[index] = flag; }; KeyFlagQueue.prototype.push = function(value) { this.values[this.values.length] = value; this.max++; }; KeyFlagQueue.prototype.shift = function() { var value = this.values[0]; for(var i = 0; i < this.values.length-1; i++) { this.values[i] = this.values[i+1]; } this.values.length--; this.min++; return value; }; KeyFlagQueue.prototype.hasValueOfCount = function(count) { while(true) { if(this.getLength() == 0) return false; if(this.min == count) return (this.values[0] != this._NONE) ? true : false; if(this.min > count) return false; this.shift(); } }; /** * TODO: optimize and check the logic */ KeyFlagQueue.prototype.insertValues = function(min, values) { for(var i = this.getLength(); this.max < min - 1; i++) { this.values[i] = this._NONE; this.max++; } var n = this.min - min >= 0 ? this.min - min : 0; for(var i = n, len = values.length; i < len; i++) { this.values[min - this.min + i] = values[i]; if(min + i > this.max) this.max++; } }; KeyFlagQueue.prototype.shiftUntilLengthIs = function(count) { while(this.getLength() > count) { this.shift(); } }; KeyFlagQueue.prototype.getValues = function() { return this.values; }; function StageAbstractState( stage ) { this.stage = stage ; } StageAbstractState.prototype.runStep = function( ) { } ; StageAbstractState.prototype.handleKeyDown = function( e ) { } ; StageAbstractState.prototype.handleKeyUp = function( e ) { } ; StageAbstractState.prototype.updateDisplay = function( surface ) { } ; StageAbstractState.prototype._soundEffect = function( key ) { this.stage._soundEffect( key ) ; } ; StageAbstractState.prototype.getImage = function( key ) { return this.stage.getImage( key ) ; } ; StageAbstractState.prototype.resetButton = function(flag) { return 0; }; /** * @param record Array */ StageAbstractState.prototype._putKeyOnRecord = function( record ) { if( record.length > 0 ) this.stage.putKeyOnRecord( record ) ; } ; /** * @param record Array */ StageAbstractState.prototype._putKeyOffRecord = function( record ) { if( record.length > 0 ) this.stage.putKeyOffRecord( record ) ; } ; function ShootingState(stage) { this.parent = StageAbstractState; this.parent.call(this, stage); } __inherit(ShootingState, StageAbstractState); ShootingState.prototype.handleKeyDown = function(e, fighter) { var p = []; switch(e.keyCode) { case 16: // shift if(fighter.setFlag(fighter._FLAG_SLOW)) p.push('s'); break; case 32: // space fighter.changeCharacter(); p.push('sp'); break; case 37: // left if(fighter.setFlag(fighter._FLAG_MOVE_LEFT)) p.push('l') ; break; case 38: // up if(fighter.setFlag(fighter._FLAG_MOVE_UP)) p.push('u'); break; case 39: // right if(fighter.setFlag(fighter._FLAG_MOVE_RIGHT)) p.push('r'); break; case 40: // down if(fighter.setFlag(fighter._FLAG_MOVE_DOWN)) p.push('d'); break; // TODO: temporal case 88: // x this.stage.notifyFighterDoBomb(fighter); p.push('x'); break; case 90: // z if(fighter.setFlag(fighter._FLAG_SHOT)) p.push('z'); break; }; this._putKeyOnRecord(p); }; ShootingState.prototype.handleKeyUp = function(e, fighter) { var p = []; switch(e.keyCode) { case 16: // shift if(fighter.clearFlag(fighter._FLAG_SLOW)) p.push('s'); break; case 37: // left if(fighter.clearFlag(fighter._FLAG_MOVE_LEFT)) p.push('l'); break; case 38: // up if(fighter.clearFlag(fighter._FLAG_MOVE_UP)) p.push('u'); break; case 39: // right if(fighter.clearFlag(fighter._FLAG_MOVE_RIGHT)) p.push('r'); break; case 40: // down if(fighter.clearFlag(fighter._FLAG_MOVE_DOWN)) p.push('d'); break; case 90: // z if(fighter.clearFlag(fighter._FLAG_SHOT)) p.push('z'); break; } ; this._putKeyOffRecord(p); }; ShootingState.prototype.updateDisplay = function( surface ) { } ; ShootingState.prototype.resetButton = function(flag) { flag &= ~this.stage._BUTTON_SPACE; flag &= ~this.stage._BUTTON_X; return flag; }; function TalkState( stage ) { this.parent = StageAbstractState ; this.parent.call( this, stage ) ; this.stageIndex = 0 ; this.sceneIndex = 0 ; this.index = 0 ; this.params = __talkParams ; } __inherit( TalkState, StageAbstractState ) ; TalkState.prototype.reset = function( ) { this.stageIndex = 0 ; this.sceneIndex = 0 ; this.index = 0 ; } ; TalkState.prototype.handleKeyDown = function( e ) { var p = [ ] ; switch( e.keyCode ) { case 32: // space p.push( 'sp' ) ; this.stage.fighter.changeCharacter( ) ; break ; case 90: // z p.push( 'z' ) ; this.index++ ; // TODO: temporal if( this.index >= this.params[ this.stageIndex ][ this.sceneIndex ][ this.stage.fighter.characterIndex ].length ) { this.sceneIndex++ ; this.index = 0 ; if( this.sceneIndex >= this.params[ this.stageIndex ].length ) { this.stage.notifyStageClear( ) ; this.stageIndex++ ; this.sceneIndex = 0 ; } else { this.stage.notifyBossBecameActive( this.stage.bossManager.getBoss( ) ) ; } } break ; } ; this._putKeyOnRecord( p ) ; } ; TalkState.prototype.handleKeyUp = function( e ) { } ; TalkState.prototype.updateDisplay = function( surface ) { this._displayStandUp( surface, this.params[ this.stageIndex ][ this.sceneIndex ][ this.stage.fighter.characterIndex ][ this.index ].left, 120, 0 ) ; this._displayStandUp( surface, this.params[ this.stageIndex ][ this.sceneIndex ][ this.stage.fighter.characterIndex ][ this.index ].right, 360, 0 ) ; this._displaySerifWindow( surface ) ; this._displaySerif( surface ) ; } ; /** * TODO: temporal */ TalkState.prototype._displayStandUp = function( surface, params, w, dw ) { if( ! params ) return ; surface.save( ) ; if( params.active ) { surface.globalAlpha = 1.0 ; w += dw ; } else { surface.globalAlpha = 0.5 ; } var p = this._getStandUp( params.character ) ; surface.drawImage( p.image, w - p.width * 0.75 / 2, 50, p.width * 0.75, p.height * 0.75 ) ; surface.restore( ) ; } ; TalkState.prototype._getStandUp = function( key ) { var image ; var width ; var height ; switch( key ) { case 'reimu': image = this.stage.getImage( Game._IMG_STAND_REIMU ) ; width = 400 ; height = 600 ; break ; case 'marisa': image = this.stage.getImage( Game._IMG_STAND_MARISA ) ; width = 400 ; height = 600 ; break ; case 'mokou': image = this.stage.getImage( Game._IMG_STAND_MOKOU ) ; width = 512 ; height = 600 ; break ; case 'rumia': image = this.stage.getImage( Game._IMG_STAND_RUMIA ) ; width = 600 ; height = 600 ; break ; case 'chilno': image = this.stage.getImage( Game._IMG_STAND_CHILNO ) ; width = 550 ; height = 600 ; break ; default: // TODO: throw exception? break ; } return { 'image': image, 'width': width, 'height': height } ; } ; TalkState.prototype._displaySerifWindow = function( surface ) { surface.save( ) ; surface.fillStyle = 'rgb( 50, 50, 50 )' ; surface.globalAlpha = 0.7 ; surface.fillRect( 50, 350, 380, 100 ) ; surface.restore( ) ; } ; TalkState.prototype._displaySerif = function( surface ) { surface.save( ) ; surface.fillStyle = 'rgb( 255, 255, 255 )' ; surface.textAlign = 'left' ; surface.font = '16px Arial' ; var array = this.params[ this.stageIndex ][ this.sceneIndex ][ this.stage.fighter.characterIndex ][ this.index ].serif.split( '\n' ) ; for( var i = 0; i < array.length; i++ ) { surface.fillText( array[ i ], 60, 380 + i * 20) ; } surface.restore( ) ; } ; /** * TODO: temporal */ function ClearState( stage ) { this.parent = StageAbstractState ; this.parent.call( this, stage ) ; this.count = 0 ; } __inherit( ClearState, StageAbstractState ) ; ClearState._MOVE_SPEED = 20 ; /** * TODO: temporal */ ClearState.prototype.init = function( ) { this.count = 0 ; } ; /** * TODO: temporal */ ClearState.prototype.runStep = function( ) { this.count++ ; } ; ClearState.prototype.handleKeyDown = function( e ) { var p = [ ] ; switch( e.keyCode ) { case 32: // space p.push( 'sp' ) ; this.stage.fighter.changeCharacter( ) ; break ; case 90: // z p.push( 'z' ) ; // TODO: temporal if( this.count < this.stage.getHeight( ) / ClearState._MOVE_SPEED ) return ; this._toNextStage( ) break ; } ; this._putKeyOnRecord( p ) ; } ; ClearState.prototype.handleKeyUp = function( e ) { } ; ClearState.prototype.updateDisplay = function( surface ) { var base = this.stage.getHeight( ) - this.count * ClearState._MOVE_SPEED ;; if( base < 0 ) base = 0 ; surface.save( ) ; var pattern = surface.createPattern( this.getImage( Game._IMG_SCORE_BACK ), '' ) ; surface.fillStyle = pattern ; surface.fillRect( 0, base, this.stage.getWidth( ), this.stage.getHeight( ) ) ; surface.fillStyle = 'rgb( 30, 30, 30 )' ; surface.globalAlpha = 0.8 ; surface.fillRect( 50, base + 50, 380, 380 ) ; surface.fillStyle = 'rgb( 255, 255, 255 )' ; surface.textAlign = 'left' ; surface.font = '16px Arial' ; surface.fillText( 'Stage' + ( this.stage.stageIndex + 1 ) + ' Clear', 100, base + 100 ) ; surface.restore( ) ; } ; /** * TODO: temporal */ ClearState.prototype._toNextStage = function( ) { this.stage.stageIndex++ ; if( this.stage.stageIndex >= __enemiesParams.length ) { this.stage.notifyGameClear( ) ; } else { this.stage.notifyGoNextStage( ) ; } } ; /** * TODO: temporal */ function GameOverState( stage ) { this.parent = StageAbstractState ; this.parent.call( this, stage ) ; this.index = 0 ; } __inherit( GameOverState, StageAbstractState ) ; GameOverState.prototype.init = function( ) { this.index = 0 ; } ; /** * TODO: temporal */ GameOverState.prototype.runStep = function( ) { } ; GameOverState.prototype.handleKeyDown = function( e ) { switch( e.keyCode ) { case 38: // up case 40: // down this._soundEffect( Game._SE_SELECT ) ; this.index = ( this.index == 0 ) ? 1 : 0 ; break ; case 90: // z this._soundEffect( Game._SE_SELECT ) ; if( this.index == 0 ) this.stage.notifyContinue( ) ; else this.stage.notifyQuit( ) ; break ; } ; } ; GameOverState.prototype.handleKeyUp = function( e ) { } ; GameOverState.prototype.updateDisplay = function( surface ) { surface.save( ) ; surface.fillStyle = 'rgb( 0, 0, 0 )' ; surface.globalAlpha = 0.5 ; surface.fillRect( 0, 170, 480, 100 ) ; surface.fillStyle = 'rgb( 255, 255, 255 )' ; surface.textAlign = 'center' ; surface.textBaseAlign = 'middle' ; surface.font = '16px Arial' ; if( this.index == 0 ) { surface.globalAlpha = 1.0 ; } else { surface.globalAlpha = 0.2 ; } surface.fillText( 'Continue', 240, 200 ) ; if( this.index == 0 ) { surface.globalAlpha = 0.2 ; } else { surface.globalAlpha = 1.0 ; } surface.fillText( 'Quit', 240, 240 ) ; surface.restore( ) ; } ; ================================================ FILE: utility/Draw.js ================================================ /** * */ function __drawComplexRect( surface, image, p, width, height, ax, ay, awidth, aheight ) { if( ! width ) width = image.width ; if( ! height ) height = image.height ; if( ! ax ) ax = 0 ; if( ! ay ) ay = 0 ; if( ! awidth ) awidth = width ; if( ! aheight ) aheight = height ; surface.save( ) ; surface.beginPath( ) ; surface.moveTo( p[0].x, p[0].y ) ; surface.lineTo( p[1].x, p[1].y ) ; surface.lineTo( p[3].x, p[3].y ) ; surface.lineTo( p[2].x, p[2].y ) ; surface.closePath( ) ; surface.clip( ) ; var t1 = ( p[1].x - p[0].x ) / width ; var t2 = ( p[1].y - p[0].y ) / width ; var t3 = ( p[2].x - p[0].x ) / height ; var t4 = ( p[2].y - p[0].y ) / height ; var t5 = p[0].x ; var t6 = p[0].y ; surface.setTransform( t1, t2, t3, t4, t5, t6 ) surface.drawImage( image, ax, ay, awidth, aheight, 0, 0, width, height ) ; surface.restore( ) ; surface.save( ) ; surface.beginPath( ) ; surface.moveTo( p[1].x, p[1].y ) ; surface.lineTo( p[2].x, p[2].y ) ; surface.lineTo( p[3].x, p[3].y ) ; surface.closePath( ) ; surface.clip( ) ; var t1 = ( p[3].x - p[2].x ) / width ; var t2 = ( p[3].y - p[2].y ) / width ; var t3 = ( p[3].x - p[1].x ) / height ; var t4 = ( p[3].y - p[1].y ) / height ; var t5 = p[2].x ; var t6 = p[2].y ; surface.setTransform( t1, t2, t3, t4, t5, t6 ) surface.drawImage( image, ax, ay, awidth, aheight, 0, 0, width, -height ) ; surface.restore( ) ; } function __toBase64Pdf( image ) { var canvas = document.createElement( 'canvas' ) ; var context = canvas.getContext( '2d' ) ; context.drawImage( image, 0, 0 ) ; return canvas.toDataURL( 'image/png' ) ; } ================================================ FILE: utility/FreeList.js ================================================ /** * This class manages object resources to reduce GC. */ function FreeList( num ) { this.num = num ; this.head = null ; this.tail = null ; this.list = [ ] ; this._init( ) ; } FreeList.prototype._init = function( ) { // Just in case. if( this.num <= 0 ) return ; for( var i = 0; i < this.num; i++ ) { var element = this._generateElement( ) ; element.listId = i ; this.list.push( { 'element': element, 'listForw': null, 'available': true } ) ; if( i > 0 ) this.list[ i - 1 ].listForw = this.list[ i ] ; } this.head = this.list[ 0 ] ; this.tail = this.list[ this.num - 1 ] ; } ; /** * Child class must override this method. */ FreeList.prototype._generateElement = function( ) { return { } ; } ; /** * TODO: must implement the object shortage handler. * TODO: verify the functionality. */ FreeList.prototype.get = function( ) { if( this.head == null ) { window.alert( 'ran out of object resources.' ) ; console.log(this); throw new Error( 'ran out of object resources.' ) ; } var head = this.head ; this.head = head.listForw ; head.available = false ; head.listForw = null ; if( this.head == null ) this.tail = null ; return head.element ; } ; FreeList.prototype.free = function( element ) { this.list[ element.listId ].available = true ; if( this.tail != null ) this.tail.listForw = this.list[ element.listId ] ; this.tail = this.list[ element.listId ] ; if( this.head == null ) this.head = this.tail ; } ; ================================================ FILE: utility/Inherit.js ================================================ /** * */ function __inherit( child, parent ) { var getPrototype = function( p ) { if( Object.create ) { return Object.create( p ) ; } function f( ) { } ; f.prototype = p ; return new f( ) ; } ; child.prototype = getPrototype( parent.prototype ) ; child.prototype.constructor = child ; } function __copyParentMethod(child, parent, methodName) { var parentName = parent.name; var name = parentName + '_' + ((methodName[0] == '_') ? methodName.slice(1) : methodName); child.prototype[name] = parent.prototype[methodName]; } ================================================ FILE: utility/Peer.js ================================================ /** * TODO: optimize */ function Peer(room, wsURL, receiver) { this.room = room; this.peopleInTheRoom = 0; this.ws = new WebSocket(wsURL); this.receiver = receiver; this.pc = null; this.channel = null; var self = this; this.gotSDPFunc = function(sdp) {self._gotSDP(sdp);}; this.onIceCandidateFunc = function(event) {self._onIceCandidate(event);}; this.onDataChannelFunc = function(event) {self._onDataChannel(event);}; this.onMessageFunc = function(event) {self._onMessage(event);}; this.onOpenFunc = function(event) {self._onOpen(event);}; this.onCloseFunc = function(event) {self._onClose(event);}; this.onErrorFunc = function(event) {self._onError(event);}; this.dummySendFunc = function() { self._keepSendDummy(); }; this.ws.onmessage = function(event) {self._gotSignal(event);}; this.ws.onopen = function(event) {self._wsReady(event);}; this.interval = null; this.peerConnected = false; } // must be same as the server side ones. Peer.prototype._PEER_ID_DUMMY = -1; Peer.prototype._PEER_ID_NOTICE_ROOM = 0; Peer.prototype._PEER_ID_SYNC = 1; Peer.prototype._ICE_SERVERS = [ {url:'stun:stun01.sipphone.com'}, {url:'stun:stun.ekiga.net'}, {url:'stun:stun.fwdnet.net'}, {url:'stun:stun.ideasip.com'}, {url:'stun:stun.iptel.org'}, {url:'stun:stun.rixtelecom.se'}, {url:'stun:stun.schlund.de'}, {url:'stun:stun.l.google.com:19302'}, {url:'stun:stun1.l.google.com:19302'}, {url:'stun:stun2.l.google.com:19302'}, {url:'stun:stun3.l.google.com:19302'}, {url:'stun:stun4.l.google.com:19302'}, {url:'stun:stunserver.org'}, {url:'stun:stun.softjoys.com'}, {url:'stun:stun.voiparound.com'}, {url:'stun:stun.voipbuster.com'}, {url:'stun:stun.voipstunt.com'}, {url:'stun:stun.voxgratia.org'}, {url:'stun:stun.xten.com'}, { url: 'turn:numb.viagenie.ca', credential: 'muazkh', username: 'webrtc@live.com' }, { url: 'turn:192.158.29.39:3478?transport=udp', credential: 'JZEOEt2V3Qb0y27GRntt2u2PAYA=', username: '28224511:1379330808' }, { url: 'turn:192.158.29.39:3478?transport=tcp', credential: 'JZEOEt2V3Qb0y27GRntt2u2PAYA=', username: '28224511:1379330808' } ]; Peer.prototype._DUMMY_SPAN = 1000 * 20; Peer.prototype._DUMMY_DATA = JSON.stringify({_pid: Peer.prototype._PEER_ID_DUMMY}); Peer.prototype.log = function(data) { // console.log(data); }; Peer.prototype._wsReady = function(event) { if(this.receiver.notifyWsReady !== void 0) this.receiver.notifyWsReady(event); this._noticeRoom(); this._keepSendDummy(); }; Peer.prototype._noticeRoom = function() { var str = JSON.stringify({_pid: this._PEER_ID_NOTICE_ROOM, room: this.room}); this.ws.send(str); }; Peer.prototype.sendSignal = function(params) { var str = JSON.stringify(params); this.ws.send(str); this.log(str); }; Peer.prototype._gotSignal = function(event) { var params = JSON.parse(event.data); if(params._pid === void 0) { switch(params.type) { case 'offer': this._gotOffer(params); break; case 'answer': this._gotAnswer(params); break; case 'candidate': this._gotCandidate(params); break; } } else { if(params._pid == Peer.prototype._PEER_ID_NOTICE_ROOM) { this.peopleInTheRoom = params.num; if(this.receiver.notifyRoomUpdate !== void 0) this.receiver.notifyRoomUpdate(this.peopleInTheRoom); } } this.log(params); }; Peer.prototype.createPeerConnection = function() { var servers = {'iceServers': this._ICE_SERVERS}; this.pc = new webkitRTCPeerConnection(servers); this.pc.onicecandidate = this.onIceCandidateFunc; }; Peer.prototype._onIceCandidate = function(event) { if(event.candidate) { var params = {type: 'candidate', sdpMLineIndex: event.candidate.sdpMLineIndex, candidate: event.candidate.candidate}; this.sendSignal(params); } }; Peer.prototype.offer = function() { this.channel = this.pc.createDataChannel('mychannel', {reliable: false}); this.channel.onmessage = this.onMessageFunc; this.channel.onopen = this.onOpenFunc; this.channel.onclose = this.onCloseFunc; // TODO: temporal this.channel.onerror = function(e) { window.alert(e); console.log(e); }; this.pc.createOffer(this.gotSDPFunc, this.onErrorFunc); }; Peer.prototype._gotSDP = function(sdp) { this.pc.setLocalDescription(sdp); this.sendSignal(sdp); }; Peer.prototype._gotOffer = function(msg) { this.pc.ondatachannel = this.onDataChannelFunc; this._setRemoteDescription(msg); this.pc.createAnswer(this.gotSDPFunc, this.onErrorFunc); }; Peer.prototype._gotAnswer = function(msg) { this._setRemoteDescription(msg); }; Peer.prototype._gotCandidate = function(msg) { var candidate = new RTCIceCandidate(msg); this.pc.addIceCandidate(candidate); }; Peer.prototype._setRemoteDescription = function(msg) { this.pc.setRemoteDescription(new RTCSessionDescription(msg)); }; Peer.prototype._onDataChannel = function(event) { this.channel = event.channel; this.channel.onmessage = this.onMessageFunc; this.channel.onopen = this.onOpenFunc; this.channel.onclose = this.onCloseFunc; }; Peer.prototype._onOpen = function(event) { this.peerConnected = true; this.ws.close(1000); // TODO: consider more if(this.receiver.notifyOpenPeer !== void 0) this.receiver.notifyOpenPeer(event); }; Peer.prototype._onClose = function(event) { this.peerConnected = false; if(this.receiver.notifyClosePeer !== void 0) this.receiver.notifyClosePeer(event); }; Peer.prototype._onError = function(event) { window.alert(event); }; Peer.prototype._onMessage = function(event) { this.log(event.data); this.receiver.receiveFromPeer(JSON.parse(event.data)); }; Peer.prototype.send = function(data) { this.channel.send(JSON.stringify(data)); }; Peer.prototype._keepSendDummy = function() { this.ws.send(this._DUMMY_DATA); this._setIntervalForDummy(); }; Peer.prototype._setIntervalForDummy = function() { if(! this.ws || this.peerConnected) return; this.interval = setTimeout(this.dummySendFunc, this._DUMMY_SPAN); }; ================================================ FILE: utility/Random.js ================================================ function Randomizer() { }; Randomizer.prototype._xors = { x: 123456789, y: 362436069, z: 521288629, w: 88675123 }; Randomizer.prototype._effective = 0x7fffffff ; Randomizer.prototype.seed = function(seed) { this._xors.x = 123456789; this._xors.y = 362436069; this._xors.z = 521288629; this._xors.w = seed; }; Randomizer.prototype.random = function() { var xors = this._xors; var effective = this._effective; var t = xors.x ^ (xors.x << 11); xors.x = xors.y; xors.y = xors.z; xors.z = xors.w; xors.w = (xors.w ^ (xors.w >> 19)) ^ (t ^ (t >> 8)); return (xors.w % effective) / effective; }; var __randomizer = new Randomizer(); ================================================ FILE: utility/WebGL.js ================================================ function Layer(canvas) { this.canvas = canvas; this.gl = this._initGl(canvas); this.gl.clearColor(0.0, 0.0, 0.0, 1.0); this.shader = this._initShader(this.gl); this.mvMatrix = mat4.create(); this.pMatrix = mat4.create(); // These are for one texture drawing. // TODO: remove magic numbers. this.vArray = this.createFloatArray(12); this.cArray = this.createFloatArray(8); this.iArray = this.createUintArray(6); this.aArray = this.createFloatArray(16); this.vBuffer = this.gl.createBuffer(); this.cBuffer = this.gl.createBuffer(); this.iBuffer = this.gl.createBuffer(); this.aBuffer = this.gl.createBuffer(); }; Layer.prototype.mat4 = mat4; // only for reference. Layer.prototype._NAMES = ['webgl', 'experimental-webgl']; Layer.prototype._BLEND_ALPHA = 0; Layer.prototype._BLEND_ALPHA2 = 1; Layer.prototype._BLEND_ADD_ALPHA = 2; Layer.prototype._SHADERS = {}; Layer.prototype._SHADERS['shader-vs'] = {}; Layer.prototype._SHADERS['shader-vs'].type = 'x-shader/x-vertex'; Layer.prototype._SHADERS['shader-vs'].src = '\ attribute vec3 aVertexPosition;\ attribute vec2 aTextureCoordinates;\ attribute vec4 aColor;\ \ uniform mat4 uMVMatrix;\ uniform mat4 uPMatrix;\ \ varying vec2 vTextureCoordinates;\ varying vec4 vColor;\ void main() {\ gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);\ vTextureCoordinates = aTextureCoordinates;\ vColor = aColor;\ }\ '; Layer.prototype._SHADERS['shader-fs'] = {}; Layer.prototype._SHADERS['shader-fs'].type = 'x-shader/x-fragment'; Layer.prototype._SHADERS['shader-fs'].src = '\ precision mediump float;\ varying vec2 vTextureCoordinates;\ uniform sampler2D uSampler;\ varying vec4 vColor;\ void main() {\ vec4 textureColor = texture2D(uSampler, vTextureCoordinates);\ gl_FragColor = textureColor * vColor;\ }\ '; Layer.prototype._initGl = function(canvas) { var names = this._NAMES; var context = null; for(var i = 0; i < names.length; i++) { try { context = canvas.getContext(names[i]); } catch(e) { if(context) break; } } if(context) { context.viewportWidth = canvas.width; context.viewportHeight = canvas.height; } else { alert("Failed to create WebGL context!"); } return context; }; Layer.prototype._compileShaderFromDOM = function(gl, id) { var script = document.getElementById(id); if(!script) return null; var source = ''; var currentChild = script.firstChild; while(currentChild) { if(currentChild.nodeType == 3) { // 3 corresponds to TEXT_NODE source += currentChild.textContent; } currentChild = currentChild.nextSibling; } return this._compileShader(gl, source, script.type); }; Layer.prototype._compileShader = function(gl, source, type) { var shader; if(type == 'x-shader/x-fragment') { shader = gl.createShader(gl.FRAGMENT_SHADER); } else if(type == 'x-shader/x-vertex') { shader = gl.createShader(gl.VERTEX_SHADER); } else { return null; } gl.shaderSource(shader, source); gl.compileShader(shader); if(!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) { alert(gl.getShaderInfoLog(shader)); return null; } return shader; }; Layer.prototype._initVertexShader = function(gl) { var params = this._SHADERS['shader-vs']; return this._compileShader(gl, params.src, params.type); }; Layer.prototype._initFragmentShader = function(gl) { var params = this._SHADERS['shader-fs']; return this._compileShader(gl, params.src, params.type); }; Layer.prototype._initShader = function(gl) { var vertexShader = this._initVertexShader(gl); var fragmentShader = this._initFragmentShader(gl); var shader = gl.createProgram(); gl.attachShader(shader, vertexShader); gl.attachShader(shader, fragmentShader); gl.linkProgram(shader); if(!gl.getProgramParameter(shader, gl.LINK_STATUS)) { alert("Failed to setup shaders"); } gl.useProgram(shader); shader.vertexPositionAttribute = gl.getAttribLocation(shader, 'aVertexPosition'); gl.enableVertexAttribArray(shader.vertexPositionAttribute); shader.textureCoordAttribute = gl.getAttribLocation(shader, 'aTextureCoordinates'); gl.enableVertexAttribArray(shader.textureCoordAttribute); shader.colorAttribute = gl.getAttribLocation(shader, 'aColor'); gl.enableVertexAttribArray(shader.colorAttribute); shader.pMatrixUniform = gl.getUniformLocation(shader, 'uPMatrix'); shader.mvMatrixUniform = gl.getUniformLocation(shader, 'uMVMatrix'); shader.uSamplerUniform = gl.getUniformLocation(shader, 'uSampler'); return shader; } Layer.prototype.setMatrixUniforms = function(gl) { gl.uniformMatrix4fv(this.shader.pMatrixUniform, false, this.pMatrix); gl.uniformMatrix4fv(this.shader.mvMatrixUniform, false, this.mvMatrix); } Layer.prototype.viewport = function() { this.gl.viewport(0, 0, this.gl.viewportWidth, this.gl.viewportHeight); }; Layer.prototype.clear = function() { this.gl.clear(this.gl.COLOR_BUFFER_BIT); }; Layer.prototype.perspective = function(theta, near, far) { this.mat4.perspective(theta, this.gl.viewportWidth / this.gl.viewportHeight, near, far, this.pMatrix); }; Layer.prototype.ortho = function(near, far) { this.mat4.ortho(0, this.gl.viewportWidth, -this.gl.viewportHeight, 0, near, far, this.pMatrix); }; Layer.prototype.lookAt = function(eye, center, up) { this.mat4.lookAt(eye, center, up, this.mvMatrix); }; Layer.prototype.identity = function() { this.mat4.identity(this.mvMatrix); }; /** * pre_multiplied argument is a last resort. */ Layer.prototype.generateTexture = function(image) { var gl = this.gl; var texture = gl.createTexture(); gl.bindTexture(gl.TEXTURE_2D, texture); // gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, true); // gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true); gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT); gl.bindTexture(gl.TEXTURE_2D, null); return texture; }; Layer.prototype.draw = function(texture, vBuffer, cBuffer, iBuffer, aBuffer, blend) { var gl = this.gl; var shader = this.shader; gl.bindBuffer(gl.ARRAY_BUFFER, vBuffer); gl.vertexAttribPointer(shader.vertexPositionAttribute, vBuffer.itemSize, gl.FLOAT, false, 0, 0); gl.bindBuffer(gl.ARRAY_BUFFER, aBuffer); gl.vertexAttribPointer(shader.colorAttribute, aBuffer.itemSize, gl.FLOAT, false, 0, 0); gl.bindBuffer(gl.ARRAY_BUFFER, cBuffer); gl.vertexAttribPointer(shader.textureCoordAttribute, cBuffer.itemSize, gl.FLOAT, false, 0, 0); gl.activeTexture(gl.TEXTURE0); gl.bindTexture(gl.TEXTURE_2D, texture); gl.uniform1i(shader.uSamplerUniform, 0); var param1; var param2; switch(blend) { case this._BLEND_ALPHA2: param1 = gl.ONE; param2 = gl.ONE_MINUS_SRC_ALPHA; break; case this._BLEND_ADD_ALPHA: param1 = gl.SRC_ALPHA; param2 = gl.ONE; break; // case this._BLEND_ALPHA: // case null: default: param1 = gl.SRC_ALPHA; param2 = gl.ONE_MINUS_SRC_ALPHA; break; } gl.blendFuncSeparate(param1, param2, gl.ONE, gl.ONE); // gl.enable(gl.DEPTH_TEST); // gl.depthFunc(gl.LEQUAL); gl.disable(gl.DEPTH_TEST); gl.enable(gl.BLEND); gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, iBuffer); this.setMatrixUniforms(gl); gl.drawElements(gl.TRIANGLES, iBuffer.numItems, gl.UNSIGNED_SHORT, 0); }; /** * TODO: gl.bufferSubData and pratial update could improve * CPU-GPU transfer performance. */ Layer.prototype.pourArrayBuffer = function(buffer, array, itemSize, numItems) { var gl = this.gl; gl.bindBuffer(gl.ARRAY_BUFFER, buffer); gl.bufferData(gl.ARRAY_BUFFER, array, gl.STATIC_DRAW); buffer.itemSize = itemSize; buffer.numItems = numItems; }; Layer.prototype.pourElementArrayBuffer = function(buffer, array, itemSize, numItems) { var gl = this.gl; gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, buffer); gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, array, gl.STATIC_DRAW); buffer.itemSize = itemSize; buffer.numItems = numItems; }; Layer.prototype.createFloatArray = function(num) { return new Float32Array(num); }; Layer.prototype.createUintArray = function(num) { return new Uint16Array(num); }; Layer.prototype.createBuffer = function() { return this.gl.createBuffer(); }; /** * This method is to easily draw one texture. * I wanna use image, not texture. * But cannot do that cuz of performance reason. */ Layer.prototype.drawOneTexture = function(texture, x, y, z, w, h, d, a, blend) { y = -y; this.vArray[0] = x-w/2; this.vArray[1] = y-h/2; this.vArray[2] = z; this.vArray[3] = x+w/2; this.vArray[4] = y-h/2; this.vArray[5] = z; this.vArray[6] = x+w/2; this.vArray[7] = y+h/2; this.vArray[8] = z; this.vArray[9] = x-w/2; this.vArray[10] = y+h/2; this.vArray[11] = z; this.pourArrayBuffer(this.vBuffer, this.vArray, 3, 4); this.cArray[0] = 0.0; this.cArray[1] = 1.0; this.cArray[2] = 1.0; this.cArray[3] = 1.0; this.cArray[4] = 1.0; this.cArray[5] = 0.0; this.cArray[6] = 0.0; this.cArray[7] = 0.0; this.pourArrayBuffer(this.cBuffer, this.cArray, 2, 4); this.iArray[0] = 0; this.iArray[1] = 1; this.iArray[2] = 2; this.iArray[3] = 0; this.iArray[4] = 2; this.iArray[5] = 3; this.pourElementArrayBuffer(this.iBuffer, this.iArray, 1, 6); this.aArray[0] = d; this.aArray[1] = d; this.aArray[2] = d; this.aArray[3] = a; this.aArray[4] = d; this.aArray[5] = d; this.aArray[6] = d; this.aArray[7] = a; this.aArray[8] = d; this.aArray[9] = d; this.aArray[10] = d; this.aArray[11] = a; this.aArray[12] = d; this.aArray[13] = d; this.aArray[14] = d; this.aArray[15] = a; this.pourArrayBuffer(this.aBuffer, this.aArray, 4, 4); this.draw(texture, this.vBuffer, this.cBuffer, this.iBuffer, this.aBuffer, blend); }; Layer.prototype.calculateSquareValue = function(num) { return Layer.calculateSquareValue(num); }; /** * Static method. */ Layer.calculateSquareValue = function(num) { var val = 1; while(num > val) { val = val << 1; } return val; }; ================================================ FILE: webgl_test.html ================================================
Turn your hardware acceleration on to use this benchmark.
See "chrome://gpu" and "chrome://flags" on your chrome to check if your hardware acceleration is enabled.
Thanks
This game is made by @suprehoge
================================================ FILE: webrtc_test.html ================================================
Turn your hardware acceleration on to use this benchmark.
See "chrome://gpu" and "chrome://flags" on your chrome to check if your hardware acceleration is enabled.
Note
Thanks
This game is made by @suprehoge
================================================ FILE: webrtc_trial.html ================================================ Room No