Advertisement
Guest User

javascript シューティングゲーム的な何か

a guest
Apr 30th, 2016
48
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 15.04 KB | None | 0 0
  1. "use strict"
  2. // 全体で使用する変数を定義
  3. var canvas, ctx;
  4. // FPS管理に使用するパラメータを定義
  5. var FPS = 30;
  6. var MSPF = 1000 / FPS;
  7. // キー状態管理変数の定義(確か256以上のキーコードは無いと思う…ちょっと怪しい)
  8. var KEYS = new Array(256);
  9. // キーの状態を false (押されていない)で初期化
  10. for(var i=0; i<KEYS.length; i++) {
  11. KEYS[i] = false;
  12. }
  13.  
  14. // 敵キャラの数を定義
  15. var ENEMIES = 10;
  16. // 発射インターバルの値を定義(この値が大きいほど連射が遅くなる)
  17. var FIRE_INTERVAL = 20;
  18. // 無敵インターバルの値を定義(この値が大きいほど無敵時間が長くなる)
  19. var STAR_INTERVAL = 20;
  20. // 弾の数を定義(同時に描画される弾の最大数より大きい必要あり)
  21. var BULLETS = 5;
  22. // プレイヤーの画像を保持する変数を定義
  23. var img_player;
  24. // プレイヤーの弾画像を保持する変数を定義
  25. var img_player_bullet;
  26. // 敵キャラの画像を保持する変数を定義
  27. var img_enemy;
  28. // プレイヤーの現在位置を保持する変数を定義
  29. // player_x -- プレイヤーのx座標
  30. // player_y -- プレイヤーのy座標
  31. var player_x, player_y;
  32. // プレイヤーの弾の現在位置(配列)を保持する変数を定義し
  33. // BULLETS分だけ要素数を持つ配列を代入
  34. var player_bullets_x = new Array(BULLETS);
  35. var player_bullets_y = new Array(BULLETS);
  36. // 敵キャラの現在位置(配列)を保持する変数を定義し
  37. // ENEMIES分だけ要素数を持つ配列を代入
  38. var enemies_x = new Array(ENEMIES);
  39. var enemies_y = new Array(ENEMIES);
  40. // プレイヤーのヒットポイント
  41. var player_hp;
  42. // 弾のヒットポイント(配列)を保持する変数を定義し
  43. // BULLETS分だけ要素数を持つ配列を代入
  44. var player_bullets_hp = new Array(BULLETS);
  45. // 敵キャラのヒットポイント(配列)を保持する変数を定義し
  46. // ENEMIES分だけ要素数を持つ配列を代入
  47. var enemies_hp = new Array(ENEMIES);
  48. // プレイヤーの発射インターバル
  49. var player_fire_interval=0;
  50. // プレイヤーの無敵インターバル
  51. var player_star_interval=0;
  52.  
  53.  
  54.  
  55. // 再描画する関数(無引数、無戻り値)
  56. var redraw = function() {
  57. // キャンバスをクリアする
  58. ctx.clearRect(0, 0, canvas.width, canvas.height);
  59.  
  60. // 生きている場合だけ新しい位置にプレイヤーを描画
  61. if(player_hp > 0) {
  62. ctx.drawImage(img_player, player_x, player_y);
  63. }
  64.  
  65. // 弾の画像を (bullets_x[i], bullets_y[i]) の位置に表示
  66. for(var i=0; i<BULLETS; i++) {
  67. // 生きている場合だけ描画
  68. if(player_bullets_hp[i] > 0) {
  69. ctx.drawImage(img_player_bullet,
  70. player_bullets_x[i],
  71. player_bullets_y[i]);
  72. }
  73. }
  74.  
  75. // 敵キャラの画像を (enemies_x[i], enemies_y[i]) の位置に表示
  76. for(var i=0; i<ENEMIES; i++) {
  77. // 生きている場合だけ描画
  78. if(enemies_hp[i] > 0) {
  79. ctx.drawImage(img_enemy, enemies_x[i], enemies_y[i]);
  80. }
  81. }
  82.  
  83. // コンテキストの状態を保存(fillStyleを変えたりするので)
  84. ctx.save();
  85. // HPの最大値(10)x 5 の短形を描画(白)
  86. ctx.fillStyle = '#fff';
  87. ctx.fillRect(10, canvas.height-10, 10 * 5, 5);
  88. // 残りHP x 5 の短形を描画(赤)
  89. ctx.fillStyle = '#f00';
  90. ctx.fillRect(10, canvas.height-10, player_hp * 5, 5);
  91. // コンテキストの状態を復元
  92. ctx.restore();
  93.  
  94. // プレイヤーが死んでいた場合ゲームオーバー画面を表示する
  95. if(player_hp <= 0){
  96. // 全体を半透明の黒い四角で覆う(オーバーレイ)
  97. ctx.globalAlpha = 0.5;
  98. ctx.fillStyle = '#000';
  99. ctx.fillRect(0, 0, canvas.width, canvas.height);
  100. ctx.globalAlpha = 1.0;
  101.  
  102. // 真ん中に大きな文字でゲームオーバー(赤)と表示する
  103. ctx.font = '20px sans-serif';
  104. ctx.textBaseline = 'middle'; // 上下位置のベースラインを中心に
  105. ctx.fillStyle = '#f00';
  106. context.fillText("abcABCあいう漢字");
  107. width = ctx.measureText(text).width;
  108. ctx.fillText(text,
  109. (canvas.width - width) / 2,
  110. canvas.height / 2);
  111. }
  112. // 敵を殲滅していた場合はゲームクリア画面を表示
  113. else if(killed == ENEMIES){
  114. // 全体を半透明の黒い四角で覆う(オーバーレイ)
  115. ctx.globalAlpha = 0.5;
  116. ctx.fillStyle = '#000';
  117. ctx.fillRect(0, 0, canvas.width, canvas.height);
  118. ctx.globalAlpha = 1.0;
  119.  
  120. // 真ん中に大きな文字でゲームクリア(白)と表示する
  121. ctx.font = '20px sans-serif';
  122. ctx.textBaseline = 'middle'; // 上下位置のベースラインを中心に
  123. ctx.fillStyle = '#fff';
  124. text = "Game Clear";
  125. width = ctx.measureText(text).width;
  126. ctx.fillText(text,
  127. (canvas.width - width) / 2,
  128. canvas.height / 2);
  129. }
  130.  
  131. // コンテキストの状態を復元
  132. ctx.restore();
  133. };
  134.  
  135. // プレイヤーの移動処理を定義
  136. var movePlayer = function() {
  137. // ヒットポイントを確認し、生きている場合のみ処理をする
  138. if(player_hp <= 0) {
  139. return;
  140. }
  141.  
  142. // 上下左右の移動速度を定義
  143. var SPEED = 2.6;
  144.  
  145. // キー番号だとわかりにくいため予め変数に格納
  146. var UP = 40
  147. var DOWN = 38
  148. var RIGHT = 39;
  149. var LEFT = 37;
  150. var SPACE = 32;
  151.  
  152. if(KEYS[UP] && player_y+img_player.height < canvas.height) {
  153. // プレイヤーのy座標を少し増やす
  154. player_y += SPEED;
  155. }
  156. if(KEYS[DOWN] && player_y > 0) {
  157. // プレイヤーのy座標を少し減らす
  158. player_y -= SPEED;
  159. }
  160. if(KEYS[RIGHT] && player_x+img_player.width < canvas.width) {
  161. // プレイヤーのx座標を少し増やす
  162. player_x += SPEED;
  163. }
  164. if(KEYS[LEFT] && player_x > 0) {
  165. // プレイヤーのx座標を少し減らす
  166. player_x -= SPEED;
  167. }
  168.  
  169. // スペースキーが押され、なおかつ発射インターバルが0の時だけ発射する
  170. if(KEYS[SPACE] && player_fire_interval == 0) {
  171. // 未使用の弾があれば発射する
  172. for(var i=0; i<BULLETS; i++) {
  173. if(player_bullets_hp[i] == 0) {
  174. // 弾の初期位置はプレイヤーと同じ位置にする
  175. player_bullets_x[i] = player_x;
  176. player_bullets_y[i] = player_y;
  177. // 弾のHPを1にする。これにより次のループから描画や移動処理
  178. // が行われるようになる
  179. player_bullets_hp[i] = 1;
  180. // 弾を打ったので発射インターバルの値を上げる
  181. player_fire_interval = FIRE_INTERVAL;
  182. // 弾は打ったのでループを抜ける
  183. // ループ処理を途中でやめる場合は `break` を使う
  184. break;
  185. }
  186. }
  187. }
  188. // 発射インターバルの値が0より大きい場合は値を減らす。
  189. if(player_fire_interval > 0) {
  190. // 変数++; や 変数--; はそれぞれ1増やす、減らすという処理
  191. // そのため下記は `player_fire_interval -= 1;`と等価
  192. player_fire_interval--;
  193. }
  194. // プレイヤーがはみ出てしまった場合は強制的に中に戻す
  195. if(player_x < 0) {
  196. player_x = 0;
  197. } else if (player_x + img_player.width > canvas.width) {
  198. player_x = canvas.width - img_player.width;
  199. } else if(player_y < 0) {
  200. player_y = 0;
  201. } else if (player_y + img_player.height > canvas.height) {
  202. player_y = canvas.height - img_player.height;
  203. }
  204. };
  205. // プレイヤーの弾の移動処理を定義
  206. var movePlayerBullets = function() {
  207. // 上下左右の移動速度を定義
  208. var SPEED = -6;
  209.  
  210. // 各弾ごとに処理を行う
  211. for(var i=0; i<BULLETS; i++) {
  212. // ヒットポイントを確認し、生きている場合のみ処理をする
  213. if(player_bullets_hp[i] <= 0) {
  214. // ループの残りのステップを無視して次のループに行く場合
  215. // は `continue` を指定する
  216. continue;
  217. }
  218.  
  219. // 弾のy座標を少し増やす(減らす)
  220. player_bullets_y[i] += SPEED;
  221.  
  222. // 弾が上画面にはみ出た場合はHPを0にして未使用状態に戻す
  223. if (player_bullets_y[i] < img_player_bullet.height) {
  224. player_bullets_hp[i] = 0;
  225. }
  226. }
  227. };
  228. // 敵キャラの移動処理を定義
  229. var moveEnemies = function() {
  230. // 上下左右の移動速度を定義
  231. var SPEED = 2;
  232.  
  233. // 各敵キャラごとに処理を行う
  234. for(var i=0; i<ENEMIES; i++) {
  235. // ヒットポイントを確認し、生きている場合のみ処理をする
  236. if(enemies_hp[i] <= 0) {
  237. // ループの残りのステップを無視して次のループに行く場合
  238. // は `continue` を指定する
  239. continue;
  240. }
  241.  
  242. // 敵キャラのy座標を少し増やす
  243. enemies_y[i] += SPEED;
  244.  
  245. // 敵キャラが下画面にはみ出た場合は上に戻す
  246. if (enemies_y[i] > canvas.height) {
  247. enemies_y[i] = -img_enemy.height;
  248. // せっかくなので x座標を再度ランダムに設定
  249. enemies_x[i] = Math.random() * (canvas.width - img_enemy.width);
  250. }
  251. }
  252. };
  253.  
  254. // 汎用的当たり判定関数
  255. var hitCheck = function(x1, y1, obj1, x2, y2, obj2) {
  256. var cx1, cy1, cx2, cy2, r1, r2, d;
  257. // 中心座標の取得
  258. cx1 = x1 + obj1.width/2;
  259. cy1 = y1 + obj1.height/2;
  260. cx2 = x2 + obj2.width/2;
  261. cy2 = y2 + obj2.height/2;
  262. // 半径の計算
  263. r1 = (obj1.width+obj1.height)/4;
  264. r2 = (obj2.width+obj2.height)/4;
  265. // 中心座標同士の距離の測定
  266. // Math.sqrt(d) -- dのルートを返す
  267. // Math.pow(x, a) -- xのa乗を返す
  268. d = Math.sqrt(Math.pow(cx1-cx2, 2) + Math.pow(cy1-cy2, 2));
  269. // 当たっているか判定
  270. // ちなみに `return r1+r2 > d;` とだけ書いてもOK
  271. if(r1 + r2 > d) {
  272. // 当たってる
  273. return true;
  274. } else {
  275. // 当たっていない
  276. return false;
  277. }
  278. };
  279.  
  280. // メインループを定義
  281. var mainloop = function() {
  282. // 処理開始時間を保存
  283. var startTime = new Date();
  284.  
  285. // プレイヤーの移動処理
  286. movePlayer();
  287. // プレイヤーの弾の移動処理
  288. movePlayerBullets();
  289. // 敵キャラの移動処理
  290. moveEnemies();
  291.  
  292. // プレイヤーと敵キャラの当たり判定(プレイヤーが生きている場合)
  293. // かつプレイヤーが無敵ではない場合
  294. if(player_hp > 0 && player_star_interval == 0) {
  295. for(var i=0; i<ENEMIES; i++) {
  296. // 敵が生きている場合のみ判定する
  297. if(enemies_hp[i] > 0) {
  298. if(hitCheck(player_x, player_y, img_player,
  299. enemies_x[i], enemies_y[i], img_enemy)){
  300. // 当たっているのでお互いのHPを1削る
  301. player_hp -= 1;
  302. enemies_hp[i] -=1;
  303. // プレイヤーを無敵状態にする
  304. player_star_interval = STAR_INTERVAL;
  305. }
  306. }
  307. }
  308. }
  309. // プレイヤーの無敵インターバルを減少させる
  310. if(player_star_interval > 0) {
  311. player_star_interval--;
  312. }
  313.  
  314. // プレイヤー弾と敵キャラの当たり判定(プレイヤーが生きている場合)
  315. if(player_hp > 0) {
  316. for(var i=0; i<ENEMIES; i++) {
  317. // 敵が死んでいる場合はスルーする
  318. if(enemies_hp[i] <= 0) {
  319. continue;
  320. }
  321. for(var j=0; j<BULLETS; j++) {
  322. // 弾が死んでいる場合はスルーする
  323. if(player_bullets_hp[j] <= 0) {
  324. continue;
  325. }
  326. if(hitCheck(player_bullets_x[j],
  327. player_bullets_y[j],
  328. img_player_bullet,
  329. enemies_x[i],
  330. enemies_y[i],
  331. img_enemy)){
  332. // 当たっているのでお互いのHPを1削る
  333. player_bullets_hp[j] -= 1;
  334. enemies_hp[i] -=1;
  335. }
  336. }
  337. }
  338. }
  339.  
  340. // 描画処理
  341. redraw();
  342.  
  343. // 処理経過時間および次のループまでの間隔を計算
  344. var deltaTime = (new Date()) - startTime;
  345. var interval = MSPF - deltaTime;
  346. if(interval > 0) {
  347. // 処理が早すぎるので次のループまで少し待つ
  348. setTimeout(mainloop, interval);
  349. } else {
  350. // 処理が遅すぎるので即次のループを実行する
  351. mainloop();
  352. }
  353. };
  354.  
  355. // キーが押された時に呼び出される処理を指定
  356. window.onkeydown = function(e) {
  357. // キーを押された状態に更新
  358. KEYS[e.keyCode] = true;
  359. }
  360. // キーが離された時に呼び出される処理を指定
  361. window.onkeyup = function(e) {
  362. // キーを離された状態に更新
  363. KEYS[e.keyCode] = false;
  364. }
  365.  
  366. // ページロード時に呼び出される処理を指定
  367. window.onload = function() {
  368. // コンテキストを取得(おまじない)
  369. canvas = document.getElementById('screen');
  370. ctx = canvas.getContext('2d');
  371.  
  372. // Playerの画像(id='player'で指定された<img>)を取得
  373. img_player = document.getElementById('player');
  374. // Playerの弾画像(id='player_bullet'で指定された<img>)を取得
  375. img_player_bullet = document.getElementById('player_bullet');
  376. // 敵キャラの画像(id='enemy'で指定された<img>)を取得
  377. img_enemy = document.getElementById('enemy');
  378.  
  379. // Playerの初期位置およびHPを指定
  380. // player_x = キャンバスの左右中央
  381. // player_y = キャンバスの下から20px上
  382. player_x = (canvas.width - player.width) / 2;
  383. player_y = (canvas.height -player.height) - 20;
  384. player_hp = 10;
  385.  
  386. // 弾の初期位置およびHPを指定
  387. for(var i=0; i<BULLETS; i++) {
  388. player_bullets_x[i] = 0;
  389. player_bullets_y[i] = 0;
  390. player_bullets_hp[i] = 0;
  391. }
  392. // 敵キャラの初期位置およびHPを指定
  393. for(var i=0; i<ENEMIES; i++) {
  394. enemies_x[i] = Math.random() * (canvas.width - img_enemy.width);
  395. enemies_y[i] = Math.random() * (canvas.height - img_enemy.height);
  396. enemies_hp[i] = 2;
  397. }
  398.  
  399. // メインループを開始する
  400. mainloop();
  401. };
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement