2011年7月23日土曜日

HTML5 - Canvas アニメーション - 陣取りゲーム

マウスドラッグの向きにプレイヤー(青いボール)が動きます。動いている途中のパスが敵か自分に当たったらプレイヤーが死にます。ボールを動かして陣地を80%以上確保したらステージクリアです。敵を閉じ込めたら敵を倒せてボーナス点数がもらえます。(キーボード入力がきかないです。)

http://endo-yuta2.appspot.com/practice7




Code

<canvas id="game2" width="270" height="400"></canvas>
<script type="text/javascript">
var canvas = document.getElementById("game2");
var ctx = canvas.getContext("2d");

var w,p,f,pa,tm,e,st,t,l,score,game,area_anime,enemy_del_anime;
var c_w = canvas.width;
var c_h = canvas.height;
var e = [];

//Life用の画像
var img_heart = new Image();
img_heart.src = '/pic/heart_48.png';

//初期化メソッド
function init(){
 enemy_del_anime = [];
 area_anime = [];
 game = new Game();
 w = new Waku();
 t = new Timer();
 st = new Stage();
 l = new Life();
 s = new Status();
 s.init();
 p = new Player();
 pa = new Path();
 f = new Fix_path();
 f.init();
 e = new AllEnemy();
 e.init();
 score = new Score();
}

init();

tm = setInterval(main,10);

function main(){
 ctx.clearRect(0,0,c_w,c_h); //画面のクリア
 w.view_waku(); //外枠の表示
 //start画面
 if(game.game_start){
  game.game_start_animation();
  return;
 }
 w.view_waku_fill();
 f.view_paths(); //枠パスの表示
 s.main();
 //ラウンド(ステージ)開始画面
 if(game.round_start && !game.game_over){
  game.round_start_animation();
  return;
 }
 //プレイヤーがしんだとき
 if(game.player_death){
  //敵は動かずに表示だけされる
  e.all_enemys_view();
  //プレイヤーのですあにめ
  p.death_animation();
  if(p.size == 0){
   game.player_death = false;
   //初期化
   st.dead_init();
  }
 }else if(game.game_over){
  //敵は動かずに表示だけされる
  e.all_enemys_view();
  //GameOverあにめ
  if(game.game_over_anim_sec>0){
   game.game_over_animation();
  }else if(game.game_score_sec>0){
   //スコア・ランキングページ
   game.game_score_animation();
  }else{
   //初期化
   init(); 
  }
 }else if(game.game_clear){
  //Clear!あにめ
  if(game.game_clear_finish_sec>0){
   game.clear_animation();
  }else if(game.game_score_sec>0){
   //スコアページ
   game.game_clear_score_animation();
  }else{
   game.init();
   st.next_stage_init();
  }
  //エリアスコアアニメあれば実施
  for(var i=0;i<area_anime.length;i++){
   area_anime[i].main();
  }
  //敵スコアアニメあれば実施
  for(var i=0;i<enemy_del_anime.length;i++){
   enemy_del_anime[i].main();
  }
 }else{
  p.main();
  e.main_all();
  t.main();
  //エリアスコアアニメあれば実施
  for(var i=0;i<area_anime.length;i++){
   area_anime[i].main();
  }
  //敵スコアアニメあれば実施
  for(var i=0;i<enemy_del_anime.length;i++){
   enemy_del_anime[i].main();
  }
 }
}

//ゲームクラス
function Game(){
 var obj = this;
 obj.font = 'verdana';
 obj.game_start = true;
 obj.round_start =false;
 obj.player_death = false;
 obj.game_over = false;
 obj.game_over_anim_sec = 100;
 obj.game_score_sec = 200;
 obj.game_clear = false;
 obj.game_clear_normal_sec = 100;
 obj.score_stage_bounus = 0;
 obj.game_clear_finish_sec = 150;
 obj.round_sec = 150;
 obj.area_make = false;
 
 //init
 obj.init = function(){
  obj.player_death = false;
  obj.game_over_anim_sec = 150;
  obj.game_score_sec = 200;
  obj.game_clear = false;
  obj.game_clear_normal_sec = 150;
  obj.score_stage_bounus = 0;
  obj.game_clear_finish_sec = 150;
  obj.round_sec = 150;
 }
 
 //ラウンドスタート
 obj.round_start_animation = function(){
  if(obj.round_sec>0){
   //背景表示
   ctx.beginPath();
   ctx.fillStyle = "rgba(0,153,204, 0.3)";
   ctx.moveTo(w.z[0][0],w.z[0][1]); //左上
   ctx.lineTo(w.z[1][0],w.z[1][1]); //右上
   ctx.lineTo(w.z[2][0],w.z[2][1]); //右下
   ctx.lineTo(w.z[3][0],w.z[3][1]); //左下
   ctx.closePath();
   ctx.fill();
   //文字表示
   ctx.beginPath();
   ctx.fillStyle = "#000000";
   ctx.font = "30px "+obj.font;
   ctx.fillText('Round '+st.big_num+'-'+st.small_num,60, 200);
   ctx.font = "16px "+obj.font;
   ctx.fillText('Get 80% Area.',60, 250);
   ctx.fill();
   obj.round_sec--;
  }else{
   obj.round_start =false;
  }
 }
 
 var c_r_a_no = 0;
 var blank_time = 5;
 var vec = 1;
 //スタートあにめ用色あにめ(色返すメソッド)
 obj.color_red_animation = function(){
  var color_arr = ['#ff0000','#ff1111','#ff2222','#ff3333','#ff4444','#ff5555','#ff6666','#ff7777','#ff8888','#ff9999'];
  if(blank_time<0){
   if(vec == 1){
    if(c_r_a_no == color_arr.length-1){
     vec = -1;
     c_r_a_no--;
    }else c_r_a_no++;
   }else{
    if(c_r_a_no == 0){
     vec = 1;
     c_r_a_no++;
    }else c_r_a_no--;
   }
   blank_time=5;
  }
  blank_time--;
  return color_arr[c_r_a_no];
 }
 
 //スタートあにめ
 obj.game_start_animation = function(){
  //クリックされたらアクション(スタート)
  if(m.d_x>=95&&m.d_x<=160&&m.d_y>=230&&m.d_y<=258){
   obj.game_start = false;
   obj.round_start = true;
   obj.init();
  }
  //クリックされたらアクション(ランク)
  
  //クリックされたらアクション(ハウツー)
  
  //マウスがのったら色あにめ
  //$('#hoge').text(m.m[0]+','+m.m[1]);
  if(m.m[0]>=95&&m.m[0]<=160&&m.m[1]>=230&&m.m[1]<=258){
   var color_start = obj.color_red_animation(c_r_a_no);
  }else{
   var color_start = '#ffffff'; 
  }
  if(m.m[0]>=95&&m.m[0]<=160&&m.m[1]>=270&&m.m[1]<=298){
   var color_rank = obj.color_red_animation(c_r_a_no);
  }else{
   var color_rank = '#ffffff'; 
  }
  if(m.m[0]>=73&&m.m[0]<=185&&m.m[1]>=310&&m.m[1]<=338){
   var color_how = obj.color_red_animation(c_r_a_no);
  }else{
   var color_how = '#ffffff'; 
  }
  //背景表示
  ctx.beginPath();
  ctx.fillStyle = "#0099cc";
  ctx.moveTo(w.z[0][0],w.z[0][1]); //左上
  ctx.lineTo(w.z[1][0],w.z[1][1]); //右上
  ctx.lineTo(w.z[2][0],w.z[2][1]); //右下
  ctx.lineTo(w.z[3][0],w.z[3][1]); //左下
  ctx.closePath();
  ctx.fill();
  //文字表示
  ctx.beginPath();
  ctx.fillStyle = "#ffffff";
  ctx.font = "40px "+obj.font;
  ctx.fillText('GinTori',60, 200);
  ctx.font = "20px "+obj.font;
  ctx.fillStyle = color_start;
  ctx.fillText('Start',100, 250);
  ctx.fillStyle = color_rank;
  ctx.fillText('Rank',100, 290);
  ctx.font = "16px "+obj.font;
  ctx.fillStyle = color_how;
  ctx.fillText('How to Play?',75, 330);
  ctx.fill();
 }
 
 //Game Overあにめ
 obj.game_over_animation = function(){
  ctx.beginPath();
  ctx.fillStyle = "#000000";
  ctx.font = "16px "+obj.font;
  ctx.fillText('Game Over...', 90, 240);
  ctx.fill();
  obj.game_over_anim_sec--;
 }
 
 //スコアランキングページ(GameOver時用)
 obj.game_score_animation = function(){
  //黒いページ
  obj.black_page_view();
  //スコア表示
  ctx.beginPath();
  ctx.fillStyle = "#ffffff";
  ctx.font = "16px "+obj.font;
  ctx.fillText('Score: '+s.score, 90, 240);
  ctx.fill();
  obj.game_score_sec--; 
 }
 
 //クリア時のアニメーション
 obj.clear_animation = function(){
  ctx.beginPath();
  ctx.fillStyle = "#000000";
  ctx.font = "16px "+obj.font;
  ctx.fillText('Clear!!!', 90, 240);
  ctx.fill();
  obj.game_clear_finish_sec --;
 }
 
 //スコアページ(クリア時用)
 obj.game_clear_score_animation  =function(){
  //黒いページ表示
  obj.black_page_view();
  if(obj.game_clear_normal_sec>0){
   //ステージボーナス(難しい程稼いだ点に応じてボーナスがもらえる)
   var stage_sc = score.stage_score_bounus();
   obj.clear_base_method(stage_sc);
   obj.game_clear_normal_sec--;
  //タイムボーナスあにめ
  }else if(t.min>0||t.sec>0){
   if(t.sec == 0){
    t.min--;
    t.sec = 59;
   }else{
    t.sec--;
   }
   s.score += 100;
   score.this_stage_score += 100;
   //ステージボーナス(難しい程稼いだ点に応じてボーナスがもらえる)
   var stage_sc = score.stage_score_bounus();
   obj.score_stage_bounus = stage_sc;
   obj.clear_base_method(stage_sc);
  //ステージボーナスあにめ
  }else{
   if(obj.score_stage_bounus>0){
    s.score += 100;
    obj.score_stage_bounus -=100;
   }else{
    obj.game_score_sec --;
   }
   obj.clear_base_method(obj.score_stage_bounus);
  }
 }
  
 //クリア時スコアページ用の標準動作
 obj.clear_base_method = function(stage_sc){
  //secの表示調整
  var sec_t = s.sec_text();
  //現在のスコア表示
  ctx.beginPath();
  ctx.fillStyle = "#ffffff";
  ctx.font = "16px "+obj.font;
  ctx.fillText('Score: '+s.score, 50, 240);
  ctx.fillText('Time Bounus: '+t.min+':'+sec_t, 50, 270);
  ctx.fillText('Stage Bounus: '+stage_sc, 50, 300);
  ctx.fill();
 }
 
 //黒いページ表示するメソッド
 obj.black_page_view = function(){
  ctx.beginPath();
  ctx.fillStyle = "black";
  ctx.moveTo(w.z[0][0],w.z[0][1]); //左上
  ctx.lineTo(w.z[1][0],w.z[1][1]); //右上
  ctx.lineTo(w.z[2][0],w.z[2][1]); //右下
  ctx.lineTo(w.z[3][0],w.z[3][1]); //左下
  ctx.closePath();
  ctx.fill();
 }
}


//ステータスクラス
function Status(){
 var obj = this;
 var x = 0;
 var y = 0;
 var h = 40;
 var w = c_w;
 obj.score = 0;
 obj.sum = 0;
 
 obj.init = function(){
  
 }
 
 obj.main = function(){
  obj.waku_view();
  obj.status_view();
  //面積クリアした場合
  if(obj.check_area()){
   st.clear();
  }
  
 }
 
 //ステータスバーを表示
 obj.waku_view = function(){
  ctx.beginPath();
  ctx.fillStyle = "#ffffff";
  ctx.moveTo(x,y); //左上
  ctx.lineTo(c_w,y); //右上
  ctx.lineTo(c_w,h); //右下
  ctx.lineTo(x,h); //左下
  ctx.closePath();
  ctx.fill();
 }
 
 //scoreを10桁のテキストにするメソッド
 obj.score_text = function(){
  var st = '' + obj.score;
  var zero_count = 10-st.length;
  var zero = '';
  for(var i=0;i<zero_count;i++){zero += '0';}
  return zero + st;
 }
 
 //secを2桁のテキストにするメソッド
 obj.sec_text = function(){
  var sec = ''+t.sec;
  var zero_count = 2 - sec.length;
  var zero = '';
  for(var i=0; i<zero_count;i++){zero += 0;}
  return zero + sec;
 }
 
 //ステータスの中身表示
 obj.status_view = function(){
  var s = obj.score_text();
  var sec = obj.sec_text();
  ctx.beginPath();
  ctx.fillStyle = "#000000";
  ctx.font = "12px "+game.font;
  ctx.fillText('Score: '+s, 140, 10);
  ctx.fillText('Area: '+obj.sum+'%', 140, 30);
  ctx.fillText(st.big_num+'-'+st.small_num, 10, 10);
  ctx.fillText('Time: '+t.min+':'+sec, 10, 30);
  ctx.drawImage(img_heart,50,-3,16,16);
  ctx.fillText('x '+l.count, 68, 10);
  ctx.fill();
 }
 
 //取得した面積の割合を出すメソッド
 obj.get_sum = function(){
  obj.sum = Math.floor((f.start_sum-f.now_sum)/f.start_sum*100);
 }
 
 //Areaチェク
 obj.check_area = function(){
  if(obj.sum >= st.area) return true;
 }
}

//Stageクラス
function Stage(){
 var obj = this;
 obj.big_num =1;
 obj.small_num = 1;
 obj.enemy_cnt = 1;
 obj.enemy_v = 0.5;
 obj.area = 80; //何%でクリアか?
 
 //clear時に実施するメソッド
 obj.clear = function(){
  game.game_clear = true;
 }
 
 //next stage用初期化
 obj.next_stage_init = function(){
  obj.small_num ++;
  if(obj.small_num == 6){
   obj.small_num = 1;
   obj.big_num ++;
   obj.enemy_v += 0.1;
  }
  obj.enemy_cnt = obj.small_num;
  e.init(); //敵の初期化
  t.init(); //timerの初期化
  f.init(); //pathの初期化
  s.sum = 0; //エリアの初期化
  p = new Player(); //プレイヤーの初期化
  pa = new Path(); //パスの初期化
  score.this_stage_score = 0; //ステージスコアの初期化
  game.round_start = true;
  game.init();
  area_anime = [];
  enemy_del_anime = [];
 }
 
 //dead時の実施メソッド
 obj.dead = function(){
  game.player_death = true;
 }
 
 //dead時の初期化メソッド
 obj.dead_init = function(){
  l.count --;
  if(l.count == -1){
   //Game Over
   game.game_over = true;
   l.count = 0;
  }
  e.init(); //敵の初期化
  t.init(); //timerの初期化
  f.init(); //pathの初期化
  s.sum = 0; //エリアの初期化
  p = new Player(); //プレイヤーの初期化
  pa = new Path(); //パスの初期化
  game.round_start = true;
  game.init();
  area_anime = [];
  enemy_del_anime = [];
 }
}

//Scoreクラス
function Score(){
 var obj = this;
 obj.this_stage_score = 0;
 
 //path(エリア)作ったときのスコア算出(sumは割合%)
 obj.area_score = function(sum){
   return sum*100*1.2^(sum/10);
 }
 
 //timer残数に応じたスコア算出
 obj.timer_score = function(sec){
  return 100*sec;
 }
 
 //敵をたおしたときのスコア算出
 obj.enemy_score = function(death_enemy_cnt,alive_enemy_cnt){
  var score = 0;
  score += 4000*Math.pow(death_enemy_cnt,2);
  if(alive_enemy_cnt == 0&&death_enemy_cnt>0) score += 20000;
  return score;
 }
 
 //ステージボーナスの算出
 obj.stage_score_bounus = function(){
  //ステージの算出
  var k = st.big_num + 0.1*st.small_num;
  return 10000*k;
 }
 
}

//Lifeクラス
function Life(){
 var obj = this;
 obj.count = 3;
}

//Timerクラス
function Timer(){
 var obj = this;
 obj.min = 2;
 obj.sec = 0;
 obj.msec = 0;
 
 obj.init = function(){
  obj.min = 2;
  obj.sec = 0;
  obj.msec = 0;
 }
 
 //タイマーのメインメソッド
 obj.main = function(){
  //時間切れの場合
  if(obj.min==0 && obj.sec==0){
   st.dead();
   return;
  }
  obj.msec += 10;
  if(obj.msec==1000){
   obj.msec = 0;
   obj.sec--;
   if(obj.sec==-1){
    obj.min--;
    obj.sec = 59;
   }
  }
 }
}

//外枠クラス
function Waku(){
 var obj = this;
 obj.w = c_w-10; //プレイヤーの大きさにあわせましょう
 obj.h = c_h-50; //-50はステータスの高さ+プレイヤの大きさにあわせましょう
 obj.x = (c_w-obj.w)/2;
 obj.y = (c_h-obj.h)-5; //-5はプレイヤーの大きさ÷2にあわせましょう
 obj.z = [[obj.x,obj.y],[obj.x+obj.w,obj.y],[obj.x+obj.w,obj.y+obj.h],[obj.x,obj.y+obj.h]]; //枠の座標4点の配列
  
 //Waku表示メソッド(fill)
 obj.view_waku_fill = function(){
  ctx.beginPath();
  ctx.fillStyle = "white";
  ctx.moveTo(obj.z[0][0],obj.z[0][1]); //左上
  ctx.lineTo(obj.z[1][0],obj.z[1][1]); //右上
  ctx.lineTo(obj.z[2][0],obj.z[2][1]); //右下
  ctx.lineTo(obj.z[3][0],obj.z[3][1]); //左下
  ctx.closePath();
  ctx.fill();
 }
 //Waku表示メソッド(storke)
 obj.view_waku = function(){
  ctx.beginPath();
  ctx.strokeStyle = "white";
  ctx.moveTo(obj.z[0][0],obj.z[0][1]); //左上
  ctx.lineTo(obj.z[1][0],obj.z[1][1]); //右上
  ctx.lineTo(obj.z[2][0],obj.z[2][1]); //右下
  ctx.lineTo(obj.z[3][0],obj.z[3][1]); //左下
  ctx.closePath();
  ctx.stroke();
 }
}

//確定パス保存クラス
function Fix_path(){
 var obj = this;
 obj.path_count = 0;
 obj.before_sum = 0;
 obj.now_sum = 0;
 obj.start_sum = 0;
 obj.paths =[];
 
 //pathsを表示するメソッド
 obj.view_paths = function(){
  ctx.strokeStyle = '#4682B4';
  ctx.beginPath();
  ctx.moveTo(obj.paths[0][0],obj.paths[0][1]);
  for(var i=1; i<obj.paths.length; i++){
   ctx.lineTo(obj.paths[i][0],obj.paths[i][1]);
  }
  ctx.closePath();
  //ctx.fill();
  ctx.stroke();
 }
 
 //pathを登録するメソッド
 obj.put_path = function(path,sum){
  obj.paths = path;
  obj.path_count ++;
  obj.before_sum = obj.now_sum;
  obj.now_sum = sum;
  s.get_sum();
  //スコア加算(エリア)
  obj.add_score_area();
  //エリア消したときのアニメーション
  area_anime.push(new Area_animation(score.area_score((obj.before_sum -obj.now_sum)/obj.start_sum*100),[p.x,p.y]));
  //敵を倒しているかチェック
  e.check_hit_path_all_enemys();
 }
 
 /*
  * 初期化メソッド
  * 枠をpathsに登録する
  * 枠の面積をstart_sumに登録する
  */
 obj.init = function(){
  obj.paths = [w.z[0],w.z[1],w.z[2],w.z[3]];
  obj.start_sum = pa.area(obj.paths);
  obj.now_sum = obj.start_sum;
  obj.before_sum = 0;
  obj.path_count = 0;
 }
 
 //点と点が作る辺にボールが存在するか否かを返すメソッド(汎用)
 //存在したらtrueを返す
 obj.is_ball_line =function(a,b,ball){
  x1 = a[0];
  y1 = a[1];
  x2 = b[0];
  y2 = b[1];
  if(x1 == x2){
   if(y1<y2){
    if(y1<=ball[1] && y2>=ball[1] && x1 == ball[0]) return true;
   }else{
    if(y1>=ball[1] && y2<=ball[1] && x1 == ball[0]) return true;
   }
  }else if(y1 == y2){
   if(x1<x2){
    if(x1<=ball[0] && x2>=ball[0] && y1 == ball[1]) return true;
   }else{
    if(x1>=ball[0] && x2<=ball[0] && y1 == ball[1]) return true;
   }
  }else{
   alert('ずれてます');
  }
  return false;
 }
 
 //点が多角形の中に存在するかをチェックするメソッド
 obj.check_in_path = function(dot){
  var k,counter = 0;
  //敵用dotの小数点を切り上げる
  dot[0] = Math.ceil(dot[0]);
  dot[1] = Math.ceil(dot[1]);
  while(dot[1] < w.z[2][1]+1){
   for(var i=0; i<obj.paths.length; i++){
    k = i+1;
    if(i == obj.paths.length-1) k = 0;
    if(obj.is_ball_line(obj.paths[i],obj.paths[k],dot)) counter++;
   }
   dot[1]++;
  }
  //counterが奇数であれば中、counterが偶数あるいは0であれば外
  if(counter % 2 != 0) return true;
  else return false;
 }
 
 //エリア分のスコア追加
 obj.add_score_area = function(){
  var sc = score.area_score((obj.before_sum -obj.now_sum)/obj.start_sum*100);
  s.score += sc;
  score.this_stage_score += sc;
 }
}

//エリア消したときのアニメーションクラス
function Area_animation(num,xy){
 var obj = this;
 obj.x = xy[0];
 obj.y = xy[1];
 obj.num = num;
 obj.view_sec = 100;
 
 //場所によって位置調整
 if(obj.x<w.w/2) obj.x += 25;
 if(obj.x>w.w/2) obj.x -= 40;
 if(obj.y<w.h/2) obj.y += 30;
 if(obj.y>w.h/2) obj.y -= 30;
 
 obj.main = function(){
  if(obj.view_sec>0){  
   //文字表示
   ctx.beginPath();
   ctx.fillStyle = "rgba(0,102,190,"+obj.view_sec/100+")";
   ctx.font = "14px "+game.font;
   ctx.fillText(obj.num,obj.x, obj.y);
   ctx.fill();
   obj.view_sec--;
  }
 }
 
}

//敵を消したときのアニメーションクラス
function Enemy_animation(score,hit_count,xy){
 var obj = this;
 obj.x = xy[0];
 obj.y = xy[1];
 obj.num = score;
 obj.hc = hit_count;
 obj.view_sec = 100;
 
 //場所によって位置調整
 if(obj.x<w.w/2){obj.x += 10; obj.x2 = obj.x+10;}
 if(obj.x>w.w/2){obj.x -= 10; obj.x2 = obj.x-10;}
 if(obj.y<w.h/2){obj.y += 10; obj.y2 = obj.y+10;}
 if(obj.y>w.h/2){obj.y -= 10; obj.y2 = obj.y-10;}
 
 obj.main = function(){
  if(obj.view_sec>0){  
   //文字表示
   ctx.beginPath();
   ctx.fillStyle = "rgba(255,0,0,"+obj.view_sec/100+")";
   ctx.font = "14px "+game.font;
   ctx.fillText(obj.num,obj.x, obj.y);
   ctx.fillText('x'+obj.hc,obj.x2, obj.y2);
   ctx.fill();
   obj.view_sec--;
  }
 }
 
}

//敵グループクラス
function AllEnemy(){
 var obj = this;
 obj.v = 0; //enemyの速度
 obj.cnt = 0; // enemyの数
 obj.enemy = [];
 obj.enemy_cnt = 0;
 obj.dead_enemys = [];
 
 //初期化メソッド
 obj.init = function(){
  obj.v = st.enemy_v;
  obj.cnt = st.enemy_cnt;
  obj.enemy = [];
  obj.make_enemys();
  obj.enemy_cnt = obj.enemy.length;
  obj.dead_enemys = [];
 } 
 
 //敵の配列作成メソッド
 obj.make_enemys = function(){
  for(var i=0;i<obj.cnt;i++){
   obj.enemy[i] = new Enemy();
   obj.enemy[i].init(obj.v);
  }
 }
 
 //全ての敵のメインメソッド実施
 obj.main_all = function(){
  for(var i=0;i<obj.enemy.length;i++){
   obj.enemy[i].main();
  }
 }
 
 //全ての敵のcheck_hit_action_pathメソッド実施
 obj.check_hit_action_path = function(){
  for(var i=0;i<obj.enemy.length;i++){
   if(obj.enemy[i].check_hit_action_path()) return true;
  }
 }
 
 //全ての敵がパス内にいるか調べる。いない場合はですあにめ
 obj.check_hit_path_all_enemys = function(){
  var hit_enemys = [];
  for(i=0;i<obj.enemy.length;i++){
   if(!f.check_in_path([obj.enemy[i].x,obj.enemy[i].y])){
    var flag = false;
    for(var j=0;j<obj.dead_enemys.length;j++){
     if(i==obj.dead_enemys[j]){flag = true;} 
    }
    if(!flag){
     hit_enemys.push([i]);
     //ですあにめ
     obj.enemy[i].death_animation();
    }
   }
  }
  obj.enemy_cnt -= hit_enemys.length;
  //スコア加算(敵倒し用)
  var sc = score.enemy_score(hit_enemys.length,obj.enemy_cnt);
  s.score += sc;
  score.this_stage_score += sc; //ステージスコアも加算
  
  //敵スコアアニメ
  if(hit_enemys.length>0){
   var idx = hit_enemys[0];
   enemy_del_anime.push(new Enemy_animation(sc,hit_enemys.length,[obj.enemy[idx].x,obj.enemy[idx].y]));   
  }
  [].push.apply(obj.dead_enemys, hit_enemys);
 }
 
 //全ての敵を表示するだけのメソッド
 obj.all_enemys_view = function(){
  for(var i=0;i<obj.enemy.length;i++){
   obj.enemy[i].view();
  }
 }
}

//敵単体クラス
function Enemy(){
 var obj = this;
 obj.size = 7;
 obj.x = 0;
 obj.y = 0;
 obj.vec = [];
 obj.death_flag = false;
 
 //初期化メソッド
 obj.init = function(total_v){
  obj.x = Math.floor(Math.random()*(w.w-obj.size))+w.x;
  obj.y = Math.floor(Math.random()*(w.h-obj.size))+w.y; 
  obj.vec = obj.make_vec(total_v);
 }
 
 //mainメソッド
 obj.main = function(){
  if(obj.death_flag){
   obj.death_animation();
   return;
  }
  obj.view();
  //1進む
  obj.x += obj.vec[0];
  obj.y += obj.vec[1];
  //衝突チェック
  obj.check_hit_path();
 }
 
 //enemyを表示するメソッド
 obj.view = function(){
  ctx.beginPath();
  ctx.fillStyle = "red";
  ctx.moveTo(obj.x,obj.y); //左上
  ctx.lineTo(obj.x+obj.size,obj.y); //右上
  ctx.lineTo(obj.x+obj.size,obj.y+obj.size); //右下
  ctx.lineTo(obj.x,obj.y+obj.size); //左下
  ctx.closePath();
  ctx.fill();
 }
 
 //パスとの衝突判定メソッド
 obj.check_hit_path = function(){
  var a1x,a1y,a2x,a2y,j,tmp=0;
  var x = obj.x;
  var y = obj.y;
  var s = obj.size;
  for(var i=0; i<f.paths.length; i++){
   a1x = f.paths[i][0];
   a1y = f.paths[i][1];
   if(i==f.paths.length-1) j=0;
   else j= i+1;
   a2x = f.paths[j][0];
   a2y = f.paths[j][1];
   if(a1x==a2x&&a2y<a1y){tmp=a1y; a1y=a2y; a2y=tmp;}
   if(a1y==a2y&&a2x<a1x){tmp=a1x; a1x=a2x; a2x=tmp;}
   if(x<=a2x && a1x<=x+s && y<=a2y && a1y<=y+s){
    //衝突したのがxに垂直なのか、yに垂直なのか?
    if(a1y==a2y){
     //上からなのか、下からなのか?
     if(obj.vec[1]<0) obj.y = a1y; //位置の調整
     else obj.y = a1y-s; //位置の調整
     obj.vec[1] = -obj.vec[1]; //向きを変える
    }else if(a1x==a2x){
     //右からか、左からか?
     if(obj.vec[0]<0) obj.x = a1x;
     else obj.x = a1x-s;
     obj.vec[0] = -obj.vec[0];
    }
   } 
  }
 }
 
 //向きと速さを決めるメソッド
 obj.make_vec = function(total_v){
  var x = Math.random()*total_v;
  if(Math.random()<0.5) x = -x;
  var y = total_v-x;
  if(Math.random()<0.5) y = -y;
  return [x,y];
 }
 
 //アクション中のパスとの衝突判定メソッド
 obj.check_hit_action_path = function(){
  var a1x,a1y,a2x,a2y,tmp=0;
  var x = obj.x;
  var y = obj.y;
  var s = obj.size;
  for(var i=0; i<pa.path.length; i++){   
   a1x = pa.path[i][0];
   a1y = pa.path[i][1];
   if(i==pa.path.length-1){
    a2x = p.x;
    a2y = p.y;
   }else{
    a2x = pa.path[i+1][0];
    a2y = pa.path[i+1][1];
   }
   if(a1x==a2x&&a2y<a1y){tmp=a1y; a1y=a2y; a2y=tmp;}
   if(a1y==a2y&&a2x<a1x){tmp=a1x; a1x=a2x; a2x=tmp;}
   if(x<=a2x && a1x<=x+s && y<=a2y && a1y<=y+s){
    return true;
   }
  }  
  return false;
 }
 
 //ですあにめ メソッド
 obj.death_animation =function(){
  var color = 'gray'; 
  if(!obj.death_flag) obj.death_flag = 1;
  if(obj.death_flag < 25)obj.size = obj.size *1.1;
  if(obj.death_flag == 25){
   obj.size = 3;
  }
  ctx.beginPath();
  ctx.fillStyle = color;
  ctx.moveTo(obj.x,obj.y); //左上
  ctx.lineTo(obj.x+obj.size,obj.y); //右上
  ctx.lineTo(obj.x+obj.size,obj.y+obj.size); //右下
  ctx.lineTo(obj.x,obj.y+obj.size); //左下
  ctx.closePath();
  ctx.fill();
  if(obj.death_flag == 25){
   obj.size = 0; 
  }
  obj.death_flag ++;
 }
}

function Player(){
 var obj = this;
 obj.size = 10;
 obj.x = w.z[3][0]; //円中心のx座標
 obj.y = w.z[3][1]; //円中心のy座標
 obj.mouseX = false;
 obj.mouseY = false;
 obj.action_mode = false; //action中(クリック座標に向かっている状態)(フラグ)
 var becs = [[0,-1],[1,0],[0,1],[-1,0]] //上右下左
 obj.bec = becs[0];
 obj.key_down = false;
 
 //main(最初に起動するメソッド)
 obj.main = function(){
  obj.view_ball();
  
  //actionモード時
  if(obj.action_mode){
   obj.action();
   return;
  }
  
  //mouseイベント発生時
  if((obj.mouseX && obj.mouseY)|| obj.key_down) {
   if(obj.mouse_bec()){
    pa.path.push([obj.x,obj.y]); //パスの追加
    obj.action_mode = true;
   }
   obj.key_down = false;
   obj.go();
   return;
  }
  
  //ノーマルアクションを実行
  obj.normal_action();
 }
 
 //actionモード
 obj.action = function(){
  //パスの軌跡を表示
  obj.view_path_stroke();
  //アクションパスに衝突している場合
  if(obj.check_hit_pass()){
   st.dead();
   return;
  }
  
  //アクションパスに敵が衝突している場合
  if(e.check_hit_action_path()){
   st.dead();
   return;
  }
  
  //枠パスに到着した場合
  if(obj.check_on_paths()){
   obj.action_mode = false;
   obj.go();
   pa.path.push([obj.x,obj.y]); //パスの追加
   obj.fix_path();
   pa.path = []; //パスのクリア
   return;
  }
  //マウスイベント時
  if((obj.mouseX && obj.mouseY) || obj.key_down){
   if(obj.mouse_bec()) pa.path.push([obj.x,obj.y]); //パスの追加
   obj.key_down = false;
  }
  obj.go();
 }
 
 /*
  * パスのFIX
  * 登録されたパスから枠パスの頂点を追加することでエリアが完成されるが、
  * 作成しうるエリアは2通りある。どちらが大きいかを確認し、大きい方の
  * エリアを作成するパスをFIXとし、枠パスを更新する
  */
 obj.fix_path = function(){
  var temp_path = [];
  var x = obj.x;
  var y = obj.y;
  var v = obj.bec;
  var counter_temp = 0;
  temp_path = make_area(x,y,v,'r'); //右に進んでエリアをつくる
  pa.sum = pa.area(pa.path.concat(temp_path)); //右に行った場合の面積を求める
  //面積が大きいか確認
  if(pa.sum > f.now_sum/2){
   f.put_path(pa.path.concat(temp_path),pa.sum); //パスをFIX
  }else{
   temp_path = make_area(x,y,v,'l'); //小さい場合は、左に進んでエリアをつくる
   pa.sum = pa.area(pa.path.concat(temp_path)); //左に行った場合の面積を求める
   f.put_path(pa.path.concat(temp_path),pa.sum); //パスをFIX
  }
 }
 
 //エリアを作成するメソッド(x,y,向き,右か左か)
 //追加パスを返す
 var make_area = function(x,y,v,rl){
  var temp_path = [];
  if(rl == 'r') obj.bec_next_r();
  else obj.bec_next_l();
  while(!array_compare([obj.x,obj.y],pa.path[0])){
   //1進んだ場合枠からはみ出さないか確認
   if(!obj.check_on_paths()){
    temp_path.push([obj.x,obj.y]); //temp_pathに登録
    obj.right_or_left();
   }
   obj.go();
  }
  obj.x = x; obj.y = y; obj.bec = v; //位置・向きを元に戻す
  return temp_path;
 }
 
 //mouseX,mouseYをbecに変換
 //有効なドラッグであれば向きを変更しtrueを返す。無効ならfalseを返す。
 obj.mouse_bec = function(){  
  if(obj.mouseX>0 && obj.bec[0] == 0 && f.check_in_path([obj.x+1,obj.y])){
   obj.bec = [1,0];
  }else if(obj.mouseX<0 && obj.bec[0] == 0 && f.check_in_path([obj.x-1,obj.y])){
   obj.bec = [-1,0];
  }else if(obj.mouseY>0 && obj.bec[1] == 0 && f.check_in_path([obj.x,obj.y+1])){
   obj.bec = [0,1];
  }else if(obj.mouseY<0 && obj.bec[1] == 0 && f.check_in_path([obj.x,obj.y-1])){
   obj.bec = [0,-1];
  }else{
   obj.del_mouse();
   return false;
  }
  obj.del_mouse();
  return true;
 }
 
 //normal action
 obj.normal_action = function(){
  //1進んだときにパスから出ないか調べる
  if(!obj.check_on_paths()) obj.right_or_left();
  obj.go();
 }
 
 //1進んだ場合にパスからはみ出さないか調べるメソッド
 //登録されているすべてのパス(f.paths)を調べる
 obj.check_on_paths = function(){
  var x1 = obj.x + obj.bec[0];
  var y1 = obj.y + obj.bec[1];
  var k;
  for(var i=0;i<f.paths.length;i++){
   if(i==f.paths.length-1) k=0;
   else k = i+1;
   if(f.is_ball_line(f.paths[i],f.paths[k],[x1,y1])) return true;
  }
  return false;
 }
 
 //右に向きを変えてpathがなければ左に向きを変えるメソッド
 obj.right_or_left = function(){
  //右に向きを変える
  obj.bec_next_r();
  //1進んだ場合に衝突中のパスからはみ出すか確認
  if(!obj.check_on_paths()){
   //右ではみ出すなら、左にする
   obj.bec_next_l();
   obj.bec_next_l();
  }
 }
 //mouseX,mouseYの消去メソッド
 obj.del_mouse = function(){
  obj.mouseX = false;
  obj.mouseY = false;
 }
 
 //ボールを表示するメソッド
 obj.view_ball = function(){
  ctx.beginPath()
  ctx.fillStyle = '#191970';
  ctx.arc(obj.x, obj.y, obj.size/2, 0, 360,false);
  ctx.fill();
 }
 
 //obj.becの次を決めるメソッド(右回り)
 obj.bec_next_r = function(){
  for(var i=0; i<becs.length; i++){
   if(array_compare(becs[i],obj.bec)){
    if(i==becs.length-1) obj.bec = becs[0];
    else obj.bec = becs[i+1];
    break;
   }
  }
 }
 
 //obj.becの次を決めるメソッド(左回り)
 obj.bec_next_l = function(){
  for(var i=0; i<becs.length; i++){
   if(array_compare(becs[i],obj.bec)){
    if(i==0) obj.bec = becs[becs.length-1];
    else obj.bec = becs[i-1];
    break;
   }
  }
 }
 
 //ボールを向きに1進めるメソッド
 obj.go = function(){
  obj.x += obj.bec[0];
  obj.y += obj.bec[1];
 } 
  
 //アクション中にボールがパスの軌跡に衝突していないか確認するメソッド
 obj.check_hit_pass = function(){
  for(var i=0; i<pa.path.length-1; i++){
   if(f.is_ball_line(pa.path[i],pa.path[i+1],[obj.x,obj.y])) return true;
  }
  return false;
 }
 
 //パスを軌跡を表示するメソッド
 obj.view_path_stroke = function(){
  ctx.beginPath();
  ctx.moveTo(pa.path[0][0],pa.path[0][1]);
  for(var i=0; i < pa.path.length; i++){
   ctx.lineTo(pa.path[i][0],pa.path[i][1]); 
  }
  ctx.lineTo(obj.x,obj.y);
  ctx.strokeStyle = 'red';
  ctx.stroke();
 }
 
 //プレイヤーのですあにめ
 obj.death_animation = function(){
  var color = 'gray'; 
  if(!obj.death_flag) obj.death_flag = 1;
  if(obj.death_flag < 25)obj.size = obj.size *1.1;
  if(obj.death_flag == 25){
   obj.size = 3;
  }
  ctx.beginPath();
  ctx.fillStyle = color;
  ctx.moveTo(obj.x,obj.y); //左上
  ctx.lineTo(obj.x+obj.size,obj.y); //右上
  ctx.lineTo(obj.x+obj.size,obj.y+obj.size); //右下
  ctx.lineTo(obj.x,obj.y+obj.size); //左下
  ctx.closePath();
  ctx.fill();
  if(obj.death_flag == 25){
   obj.size = 0; 
  }
  obj.death_flag ++;
 }
}

/*
アクション中に曲がった点の集まり
1アクションが終了したら完成させる
*/
function Path(){
 var obj = this;
 obj.path = [];
 obj.sum; //パスが作成する図形の面積
 
 //面積を求めるメソッド
 obj.area = function(paths){
  var num = 0;
  //座標法で求める
  for(var i=0; i < paths.length; i++){
   if(i+1 == paths.length){
    num = num + paths[i][0]*paths[0][1]-paths[0][0]*paths[i][1];
   }else{
    num = num + paths[i][0]*paths[i+1][1]-paths[i+1][0]*paths[i][1];
   }
  }
  return 0.5*Math.abs(num);
 }
}

var m = new Mouse();

//マウスイベント感知関連
function Mouse(){
 var obj = this;
 obj.d_x = false;
 obj.d_y = false;
 obj.u_x = false;
 obj.u_y = false;
 obj.m = [];
 obj.vector = function(){
  //d_x,d_yがfalseじゃないか確認
  if(obj.d_x && obj.d_y){
   p.mouseX = obj.u_x - obj.d_x;
   p.mouseY = obj.u_y - obj.d_y; 
  }
 }
 obj.d_init = function(){
  obj.d_x = false;
  obj.d_y = false;
 }
}

//イベントリスナーの登録
canvas.addEventListener("mousedown", mouseDownHandler, false);
canvas.addEventListener("mouseup", mouseUpHandler, false);
canvas.addEventListener("mouseover", mouseOverHandler, false);
canvas.addEventListener("mousemove", mouseMoveHandler, false);

function mouseDownHandler(e) {
 var rect = e.target.getBoundingClientRect();
 m.d_x =  Math.floor(e.clientX - rect.left);
 m.d_y =  Math.floor(e.clientY - rect.top);
}

function mouseUpHandler(e) {
 var rect = e.target.getBoundingClientRect();
 m.u_x =  Math.floor(e.clientX - rect.left);
 m.u_y =  Math.floor(e.clientY - rect.top);
 m.vector();
 m.d_init();
}

function mouseOverHandler(e) {
 var rect = e.target.getBoundingClientRect();
 //m.o[0] =  Math.floor(e.clientX - rect.left);
 //m.o[1] =  Math.floor(e.clientY - rect.top);
 //alert(2343);
}

function mouseMoveHandler(e) {
 var rect = e.target.getBoundingClientRect();
 m.m[0] =  Math.floor(e.clientX - rect.left);
 m.m[1] =  Math.floor(e.clientY - rect.top);
 //alert(2343);
}

//キーコード
var KEY_LEFT = 37;
var KEY_RIGHT = 39;
var KEY_UP = 38;
var KEY_DOWN = 40;
var KEY_SPACE = 32;
var KEY_ENTER = 13;
var KEY_ESC = 27;
var KEY_A = 65;

//キー入力検出
$(window).keydown(function(e){
 //スペースか上を押したら...
 if(e.keyCode == KEY_UP){
  p.key_down = true;
  p.mouseX = 0;
  p.mouseY = -1; 
  m.d_init();
  return false;
 //左を押したら...
 }else if(e.keyCode == KEY_LEFT){
  p.key_down = true;
  p.mouseX = -1;
  p.mouseY = 0; 
  m.d_init();
  return false;
 //右を押したら...
 }else if(e.keyCode == KEY_RIGHT){
  p.key_down = true;
  p.mouseX = 1;
  p.mouseY = 0; 
  m.d_init();
  return false;
 //下を押したら...
 }else if(e.keyCode == KEY_DOWN){
  p.key_down = true;
  p.mouseX = 0;
  p.mouseY = 1; 
  m.d_init();
  return false;
 //Aを押したら...
 }else if(e.keyCode == KEY_A){
  return false;
 }
});

//配列を比較する関数
function array_compare(a1,a2){
 if(a1.length != a2.length) return false;
 else{
  for(var i=0; i<a1.length; i++){
   if(a1[i] != a2[i]) return false; 
  }
  return true;
 }
}

</script>

0 件のコメント:

コメントを投稿