0
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

[Processing]当たり判定のあるゲームを作る(作った)

Last updated at Posted at 2019-12-27

Processingでエアーホッケーを作りました

エアーホッケー.gif
当たり判定の計算は負荷軽減とか考えず、毎フレーム行ってます(てへぺろ)
当時負荷軽減という概念を考えなかったから許して
右のプレイヤーはマウスで
左のプレイヤーはWASDで動きます
どなたかの参考になれば...

プログラム

拡張子本当は.pdeですけど、javaにした方が色ついて見やすいかなって

Air_Hocckey.java


//プレイヤーの得点
int RightPlayerPoints = 0;
int LeftPlayerPoints = 0;

//ゴールライン
int Goal_Line = 150;

//ゴールメッセージポジション
int Goal_Text_PosX ;
  
//アニメーション画像
PImage[] LefPlayers = new PImage[4];
PImage[] RigPlayers = new PImage[4];

//ゴールライン切ったかどうか
boolean goal = false;

//ボールクラス配列で管理
Ball[] balls = new Ball[6];

enum Play_Mode{
    Mouse , Key
}
  
void setup(){
  size(1800,800);
  frameRate(30);
  ellipseMode(RADIUS);
  imageMode(CENTER);
  randomSeed(millis());
  
  //Ball(位置座標 , 角度(ラジアン) , (int)半径 , 移動速度)
  for(int i = 0;i<4;i++){
      balls[i] = new Ball(random((i+2)* width/6 , width * (i+2)/6f),height/6 * (i+2) 
                , random(-1f,1f)*PI , 40 ,random(3f,6f) , loadImage("Neon"+i+".png"));
  }
  
  //左プレイヤーのアニメーション読み込み
  for(int i = 0;i<4;i++){
    LefPlayers[i] = loadImage("LefPlayer"+i+".png");
  }
  
  //右プレイヤーのアニメーション読み込み
  for(int i = 0;i<4;i++){
    RigPlayers[i] = loadImage("RigPlayer"+i+".png");
  }
  
  //Mallet(float x , float y , float rad , int size , float speed , Play_Mode mode)
  //左側のプレイヤー キーボード操作
  balls[4] = new Mallet( 60 , height/2f , 0 , 50 ,4 ,Play_Mode.Key , LefPlayers[0]);
  
  //右側のプレイヤー マウス操作
  balls[5] = new Mallet(width - 60 , height/2 , 1 , 50 , 4 , Play_Mode.Mouse , RigPlayers[0]);
  
  Goal_Text_PosX = width;
  goal = false;
}

void Start(){
  
  //パックの位置をランダムで配置
  for(int i =0;i<4;i++){
    balls[i].Set_Pos((int)random((i+1)*width/6,width*5/6),(int)random((i+1)*height/6,height*5/6));
  }
  
  //変化のあった値のリセット
  Goal_Text_PosX = width;
  goal = false;
}

void draw(){
  background(0);
  
  //ゴールライン
  fill(0);
  strokeWeight(10);
  stroke(255);
  ellipse(0,height/2,50,Goal_Line);
  ellipse(width,height/2,50,Goal_Line);
  
  //センターライン
  line(width/2,0,width/2,height);
  noStroke();
  
  for(int i=0; i < balls.length; i++){
    
    for(int j=0;j<balls.length;j++){
      
      if(i==j){ 
        //自身を参照しないように continue
        continue;
      }
      if(Collision(balls[i],balls[j])){
        balls[i].Collision(balls[j]);
        balls[j].Collision(balls[i]);
      }
    }
    
    //ゴールした場合動かない
    if(!goal){
      balls[i].Move();
      
    }
    
    //画像表示
    image(balls[i]);
    
  } // balls[i] for() end }
    
  //スコア表示
  textSize(50);
  fill(0,255,0);
  text(LeftPlayerPoints,width *1/4 , 70);
  text(RightPlayerPoints,width *3/4 , 70);
  
  if(goal){
    textSize(200);
    
    //ゴールメッセージ
    if(Goal_Text_PosX > -5000){
      fill(255,255,0);
      text("GOOOOOOOOOOOOOOOOOOOOOOOOOOOOL!!!!!!!!!!",Goal_Text_PosX + 8,height/2);
      fill(255,0,0);
      text("GOOOOOOOOOOOOOOOOOOOOOOOOOOOOL!!!!!!!!!!",Goal_Text_PosX,height/2);
      Goal_Text_PosX -= 50;
    }
    else{
      //ゴールメッセージ表示後、パックの位置を再配置
      Start();
    }
    
  }
    
} // draw() end }


//ボールクラス
class Ball{
  
  //direction x y は、radian があれば求まるため削除
  
  //位置座標
  protected Vector pos;
  
  //ベクトルの角度
  protected float radian;
  
  //半径
  protected int radius;
  
  //移動速度
  protected float speed;
  
  //画像
  protected PImage image;
  
  //ゴール in 判定
  protected boolean goal_In = false;
  
  //コンストラクタ
  Ball(float x , float y , float rad , int size , float speed , PImage ima){
    this.pos = new Vector(x,y);
    radian = rad;
    radius = size;
    this.speed = speed;
    image = ima;
  }
  
  //エアホッケーのパック (パック同士跳ね返る)
  public void Move(){
    
    //画面右端or左端 X向き反転
    // Pi * 1/6  →  PI * 5/6
    if(pos.x < radius || pos.x > width - radius ){
      
      if(!goal_In){
        
        //ゴール範囲外
        //画面右端or左端 X向き反転
        // Pi * 1/6  →  PI * 5/6
        if(pos.y < height/2 - Goal_Line + radius || pos.y > height/2 + Goal_Line - radius){
          radian = PI - radian;
        }
        else{ // ゴール範囲内
          goal_In = true;
        }
         
      } // if(!goal_In) end }
      else{
        
          //高さ調整
          if(pos.y > height/2 + Goal_Line - radius || pos.y < height/2 - Goal_Line + radius){
            radian *= -1;
          }
        
          //左のゴールに入り切ったら
          if(pos.x < -radius * 1.5f){
              RightPlayerPoints++;
          }
          else if(pos.x > width + radius * 1.5f)
          {
            //右のゴールに入り切ったら
            LeftPlayerPoints++;
          }
          //入り切ったらゴール
          goal = pos.x < -radius * 1.5f || pos.x > width + radius * 1.5f;
          goal_In = !goal;
      } //if("goal_In) else end }
      
    } // xの範囲 else end }
      
  
      //画面上or下 Y向き反転
      //PI * 1/6  →  PI * (- 1/6)
      if(pos.y < radius || pos.y > height - radius){
        radian *= -1;
      }
     
      //角度からそれぞれの移動距離を得て、速度を考慮する
      pos.x += cos(radian) * speed;
      pos.y += sin(radian) * speed;
      
  } // Move() end }
  
  //引数のボールとの角度を求め、その逆方向に radian を設定
  // → ボール同士で跳ね返る
  public void Collision(Ball ball){
    
    //引き算の関係を逆にすることで、逆向きの角度を得る
    float x = pos.x - ball.Get_Pos().x;
    float y = pos.y - ball.Get_Pos().y;
    
    radian = atan2(y,x);
  }
  
  //セッターズ&ゲッターズ
  public void Set_Radian(float rad){ radian = rad; }
  public void Set_Speed(float spe) { speed = spe; }
  public void Set_Pos(int x , int y){ pos.x = x; pos.y = y; }
  public PImage Get_Image(){ return image; }
  public float Get_Radian(){ return radian; }
  public float Get_Speed(){ return speed; }
  public int Get_Radius(){ return radius; }
  public Vector Get_Pos(){ return pos; }
}

//エアホッケーのプレイヤー
class Mallet extends Ball {
  
  //マレットの移動範囲
  Vector xRange;
  
  //操作モード
  Play_Mode mode;
  
  Mallet(float x , float y , float rad , int size , float speed , Play_Mode mode , PImage ima){
    super(x,y,rad,size,speed,ima);
    this.mode = mode;
    
    //操作モードによって移動範囲を制限
    if(mode == Play_Mode.Mouse){
      xRange = new Vector(width/2 + radius, width - radius);
    }
    else{
      xRange = new Vector(radius , width/2 - radius);
    }
  }
  
  //for文で回すためMove()をオーバーライドしてプレイヤー仕様にする
  public void Move(){
    float x = 0;
    float y = 0;
    int alfa = 0;
    int f = (frameCount/10) % 2;
    
    //マウス操作
    if(mode == Play_Mode.Mouse){
        
      x = mouseX - pos.x;
      y = mouseY - pos.y;
     
      //マウスと近いなら移動しない
      if(abs(x) < speed && abs(y) < speed){
        return;
      }
      
    }//キーボード操作
    else // mode == Play_Mode.Key
    { 
      if(keyPressed){
        if(key == 'a' || key == 'A'){
          x = -1;
        }else if(key == 'd' || key == 'D'){
          x = 1;
        }
        
        if(key == 'w' || key == 'W'){
          y = -1;
        }else if(key == 's' || key == 'S'){
          y = 1;
        }
        
      }else{ // なにもキーボードが押されてないなら動かない
        return;
      }
      
    } // Play_Mode end }
    
    //それぞれの x,y 関係から角度を得る
    radian = atan2(y,x);
    
    //角度からそれぞれの移動距離を得て、速度を考慮する
    if( (pos.x > xRange.x || x > 0 ) && (pos.x < xRange.y || x < 0) ){
      pos.x += cos(radian) * speed;
    }
    if( (pos.y > radius || y > 0) && (pos.y < height - radius || y < 0) ){
      pos.y += sin(radian) * speed;
    }
    
    //左移動時は、配列の後半の画像を参照させるための alfa
    if(x < 0){
          alfa = 2;
    }
    
    if(mode == Play_Mode.Mouse){
      image = RigPlayers[f + alfa];
    }
    else{
      image = LefPlayers[f + alfa];
    }
    
  } // Move() end }
  
} // class Mallet end }

//2次元ベクトルクラス
class Vector{
  
  //使いやすさ考慮のため public 
  public float x;
  public float y;
  
  Vector(float x , float y){
    this.x = x;
    this.y = y;
  }
  
  Vector(){
    this(0,0);
  }
  
}

//当たっていたら true を返す
boolean Collision(Ball b1,Ball b2){
  return ( dist(b1.Get_Pos().x,b1.Get_Pos().y,b2.Get_Pos().x,b2.Get_Pos().y) < b1.Get_Radius() + b2.Get_Radius() );
}


//ボールクラスから画像を表示するメソッド
void image(Ball ball){
  image(ball.Get_Image(),ball.Get_Pos().x,ball.Get_Pos().y,180,180);
}

使用画像

左のプレイヤー

LefPlayer0.png~LefPlayer3.png
LefPlayer0.png
LefPlayer1.png
LefPlayer2.png
LefPlayer3.png

右のプレイヤー

RigPlayer0.png~RigPlayer3.png
RigPlayer0.png
RigPlayer1.png
RigPlayer2.png
RigPlayer3.png

マレット

Neon0.png~Neon3.png
Neon0.png
Neon1.png
Neon2.png
Neon3.png

0
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?