ブロック崩し(4) ボールの反射角度を変える

ボールがラケットに当たる場所によって、ボールの反射角度が変わるようにします。

これまで、ラケットにボールが当たったときは、入射角と反射角が同じようにボールをはね返していました。これを、ラケットに当たる場所が右であれば右方向にはね返るようにします(左側も同様)。

ラケットの端に当たった時にどのくらいの角度で反射させるかが問題です。90度(真横)にしてしまうと、ボールが上にいかず、プレイし続けられなくなってしまいます。また、X 方向にどれくらいのスピードで進むようにするかも重要です。X 方向のスピードが速すぎると、それまでから急にスピードが速まってしまいプレイしにくくなります。

今回は、この角度を変える処理を、X 方向のスピードを変えるだけで(角度を使わずに)簡易的に表現してみたいと思います。
まず、ボールの中心(ball.x)とラケットの中心(player.x+25)の差を求めます。ボールがラケットの中心の右側であれば正の値に、左側であれば負の値になります。ラケットの幅が50なので、この差の値は-25~+25の値をとります。これを、距離を表す新しい変数 dis を用意し、代入します。今回はこの値を便宜的に6で割って、xDir に代入しています。この6という値は適当です。この値が小さくなれば、より大きい角度ではね返り、ラケットの端に当たったときのスピードが少々速くなります。

<Ballクラス>
float x, y, r, hr, xDir, yDir;
↓ 以下に修正
float x, y, r, hr, xDir, yDir, dis;

xDir = random(-1, 1);
↓ 以下に修正(2箇所あります)
xDir = 0;

<Ballクラス move()メソッド>
if ((y-hr<=0) || ((y+hr >= player.y) && (y+hr <= player.y + 5) && (x >= player.x) && (x <= player.x+50))) 
      yDir *= -1;
↓ 以下に修正
if (y-hr<=0) yDir *= -1; if ((y+hr >= player.y) && (y+hr <= player.y + 5) && (x >= player.x) && (x <= player.x+50)){
  yDir *= -1;
  dis = ball.x - (player.x+25);
  xDir = dis/6;
}

これで、ボールがラケットに当たる場所によって、ボールの反射角度が変わるようになりました。
まっすぐボールが落ちてきて・・・

ラケット右側に当たると右方向にボールをはね返します。
簡単な処理ですが、ラケットの右端であればおおむね45度から60度の角度ではね返ります。もっと正確に角度を求める方法もありますが、この方法でもほとんど気にならないと思います。

今日のコードです。

Ball ball;
Block[][] block;
Player player;
int bw, bh;

class Ball{
  float x, y, r, hr, xDir, yDir, dis;
  Ball(){
    x = width/2;
    y = height/3 * 2;
    r = 10;
    xDir = 0;
    yDir = random(2, 4);
    hr = r/2;
  }
  void move(){
    if ((x+hr > width) || (x-hr < 0)) 
      xDir *= -1;
    if (y-hr<=0) yDir *= -1; 
  if ((y+hr >= player.y) && (y+hr <= player.y + 5) && (x >= player.x) && (x <= player.x+50)){ 
   yDir *= -1; 
   dis = ball.x - (player.x+25); 
   xDir = dis/6; 
  } 
  if (y > height) {
      player.score --;
      xDir = 0;
      yDir = random(2, 4);
      x = width/2;
      y = height/3 * 2;
    }
    
    x += xDir; 
    y += yDir;
    fill(255);
    ellipse(x, y, r, r);
  }   
}

class Block{
  int n, x, y;
  Block(){
    n = 1;
  }
  void display(){
    if (n == 1){
      fill(255);
      rect(x, y, bw, bh);
      if (((x <= ball.x) && (ball.x <= x+bw) && (ball.y+ball.hr >= y) && (ball.y+ball.hr <= y+5)) || // top
          ((x <= ball.x) && (ball.x <= x+bw) && (ball.y-ball.hr >= y+5) && (ball.y-ball.hr <= y+bh))){ //down
          ball.yDir *= -1;
          n = 0;
      }
      if (((ball.x+ball.hr <= x+5) && (x <= ball.x+ball.hr) && (ball.y >= y) && (ball.y <= y + bh)) || // left
          ((ball.x+ball.hr <= x+bw) && (x+bw-5 <= ball.x-ball.hr) && (ball.y >= y) && (ball.y <= y + bh))){ //right
          ball.xDir *= -1;
          n = 0;
      }
    }
  }
}

class Player{
  float x, y, easing, targetX;
  int score;

  Player(){
    x = width/2-13;
    y = 470;
    easing = 0.1;
    score = 10;
  }
  void move(){
    targetX = mouseX-25; 
    x += (targetX - x) * easing; 
    rect(x, y, 50, 10);
  }
}

void setup(){
  size(600, 500);
  ball = new Ball();
  player = new Player();
  block = new Block[10][10];
  bw = 40;
  bh = 10;
  for (int i = 0; i < 10; i++){
    for(int j = 0; j < 10; j++){
      block[i][j] = new Block();
      block[i][j].x = i + 50 + i * 50;
      block[i][j].y = j + 45 + j * 20;
    }
  }
}

void draw(){
  background(0);
  ball.move();
  player.move();
  for (int i = 0; i < 10; i ++){
    for (int j = 0; j < 10; j ++)
      block[i][j].display();
  }
}

Leave a Reply

Your email address will not be published. Required fields are marked *