[Processing]バレーボールゲームを作る

#こんな
![Mr Robot.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/554244/bcbaafb3-ed8f-10b2-cebb-9c1b0a749190.gif)

#操作方法
| 操作       |       左プレイヤー |    右プレイヤー    |
|:----------------:|------------------:|-------------------:|
|移動             |              WASD|        方向キー        |
| レシーブ           |            Shift |       Enter|
| からかう（得点up）             |              F |        L        |
やり直し R

#プログラム
```Mr_Robot.java
PShape Ball;
float CourtX = 1000,CourtZ = 1000;

Robot bot;
Robot bot2;

Ball ball;

enum Mode {
  Stop,Walk,Receive,Fool
}

void Start(){
  RobotReset();
  BallReset();
}

void BallReset(){
  ball = new Ball();
}

void RobotReset(){
  bot = new Robot(-500,255);
  bot2 = new Robot(500,0);
}

void setup(){
  size(1600,800,P3D);
  frameRate(30);
  Ball = createShape(SPHERE,100);
  Ball.setTexture(loadImage("Ball.png"));
  Ball.setStrokeWeight(0);
  Start();
}

void draw(){
  background(200);
  lights();
  perspective();
  
  translate(width/2,height/2,-50);
  
  camera(0,-1000,1500,0,-200,0,0,1,0);
  
  //コート
  fill(0,255,0);
  strokeWeight(10);stroke(255);
  line(0,0,-CourtZ/2,0,0,CourtZ/2);
  pushMatrix();
    rotateX(PI/2);
    //quad(-CourtX,-CourtZ/2,-CourtX,CourtZ/2,CourtX,CourtZ/2,CourtX,-CourtZ/2);
  popMatrix();
  
  pushMatrix();
    textSize(200);
    textAlign(CENTER);
    translate(0,-800);
    fill(0,0,255);
    //rotateX(atan2(200,1500));
    text(ball.point,0,0);
  popMatrix();
  
  bot.Draw();
  
  bot2.Draw();
  
  ball.Draw();
}

class Robot {
  
  //アニメーションモード
  Mode mode = Mode.Walk;
  
  int armAlfa = 1; //Walk時の腕の動く向き
  int r,g,b; //色
  int foolMode = 0; //からかうアニメーションのモード番号
  int foolNum = 1;  //からかい回数
  float x = 0,y = -276,z = 0; //ポジション
  float speed = 30; //移動速度
  float direX = 0,direZ = 1; //それぞれの移動成分
  float rotate = 0; //Y軸の回転
  float ar = 0,hr = 0,fr = 0; //ArmR,HeadR,FootRそれぞれの回転角度
  float sholder = 0; //肩のX軸方向
  //キーボード入力の有無
  boolean up = false,left = false,down = false,right = false,receive = false;
  boolean swing = true; //腕を回す方向
  boolean fool = false; //からかいモード
  boolean sholderSwing = true; //肩を回す向き
  
  //コンストラクタ
  Robot(float X,int r,int g,int b){x=X;this.r=r;this.g=g;this.b=b;}
  Robot(float X,int rgb){this(X,rgb,rgb,rgb);}
  
  void Draw(){
    
    fill(r,g,b);
    stroke(255-r,255-g,255-b);
    strokeWeight(2);
    
    pushMatrix();
      shapeMode(CENTER);
      
      //ポジション移動
      translate(x,y,z);
      
      //ロボットの回転
      rotateY(rotate);

      //胴体
      box(150,250,100);
      
      //頭
      pushMatrix();
        translate(0,-225);
        rotateY(hr);
        box(300,200,200);
        
        //顔
        translate(0,0,100);
        ellipse(-50,-50,25,25);
        ellipse(50,-50,25,25);
        line(25,50,-25,50);
        line(-25,50,0,25);
        line(0,25,25,50);
      popMatrix();
      
      //腕
      for(int i = -1;i<=1;i++){
        if(i == 0) continue;
        pushMatrix();
          translate(100 * i,-75);
          if(mode != Mode.Receive){
            rotateX(ar * i);
          }
          else{
            rotateX(ar);
          }
          rotateZ(sholder*i);
          translate(0,75);
          box(50,200,50);
        popMatrix();
      }
      
      //足
      pushMatrix();
        translate(0,125);
        //足の可動部分
        HalfPipe(150,25);
        
        for(int i = -1;i<=1;i++){
          if(i == 0) continue;
          pushMatrix();
            translate(50 * -i,0);
            rotateX(fr * i);
            translate(0,75);
            box(50,100,50);
          popMatrix();
        }
      popMatrix();
      
      //影
      Shadow(0,-y-1,0,200);
      
    popMatrix();
    
    //移動、操作まわりの処理
    if(!fool){ //からかい時は何もできない
      if(up || left || down || right || receive){
    
        
        if(!receive){ //レシーブ時は動けない
          mode = Mode.Walk;
          if(up){
            x += direX * speed;
            z += direZ * speed;
          }
          else if(down){
            x -= direX * speed;
            z -= direZ * speed;
          }
          
          if(left){
            rotate += PI/30f;
            //軸方向の移動距離を計算
            direX = sin(rotate);
            direZ = cos(rotate);
          }
          else if(right){
            rotate -= PI/30f;
            //軸方向の移動距離を計算
            direX = sin(rotate);
            direZ = cos(rotate);
          }
        }  //if(!receive) 
        else{
          mode = Mode.Receive;
        }  
      }//if(up || left || down || right || receive) end }
      else{ //キーボード入力がなければ
        mode = Mode.Stop;
      }
    }//if(!fool) end }
    
    
    //アニメーション
    switch(mode){
      case Stop:
        if(ar != 0){ //腕が回っていれば戻す
          ar -= Sign(ar) * 0.05f;
          if(abs(ar) <= 0.1) ar = 0;
        }
        if(fr != 0){ //足が回っていれば戻す
          fr -= Sign(fr) * 0.05f;
          if(abs(fr) <= 0.1) fr = 0;
        }
        if(sholder != 0){ //肩が回っていれば戻す
          sholder -= Sign(sholder) * 0.05f;
          if(abs(sholder) <= 0.1f) sholder = 0;
        }
        break;
        
      case Walk: //歩くモーション
        sholder = 0;
        ar += 0.01f * armAlfa * speed;
        fr = ar;
        if(swing){ //一定以上回ったら逆向きにする
          if(ar > PI/4) {
            armAlfa = -1;
            swing = false;
          }
        }
        else{
          if(ar < -PI/4){
            armAlfa = 1;
            swing = true;
          }
        }
        break;
        
      case Receive: //レシーブモーション
        sholder = PI/8f;
        if(ar <= PI/5) ar += 0.3f;
        fr = 0;
        break;
        
      case Fool: //からかいモード
        //頭回す
        hr += 0.3f;
        ar = 0;
        switch(foolMode){
          case 0: //上に飛ぶ
            y -= 10;
            sholder = 0;
            if(y <= -400)foolMode++;
            break;
            
          case 1: // はばたきながら降りてくる
            if(sholderSwing){ //一定以上肩が回転したら逆向きにする
              sholder -= 0.5f;
              if(sholder <= -0.6 * PI) sholderSwing = false;
            }
            else{
              sholder += 0.5f;
              if(sholder >= 0) sholderSwing = true;
            }
            y += 5;
            if(y >= -276){
              foolMode++;
              y = -276;
            }
            break;
            
          default: //からかいモード解除
            fool = false;
            foolMode = 0;
            hr = 0;
            foolNum++; //からかい回数増加
            break;
        } // switch(foolNum) end }
        break; // case Fool end break;
    } // switch(mode) end }
  } // Draw() end }
  
  //ハーフパイプを描くメソッド
  void HalfPipe(float leng,float radius){
    float x,y,z,radians = 0;
  
    //底面
    for(int i = -1;i<=1;i+=2){//iは-1か1
      beginShape(TRIANGLE_FAN);
        x = leng / 2 * i;
        vertex(x, 0, 0);
        for(int deg = 0; deg <= 180; deg += 30){
          radians = radians(deg);
          z = cos(radians) * radius;
          y = sin(radians) * radius;
          vertex(x, y, z);
        }
      endShape(); 
    }
  
    //円周
    beginShape(QUAD_STRIP);
        
      for(int deg = 0; deg <= 180; deg += 30){
        radians = radians(deg);
        z = cos(radians) * radius;
        x = -leng / 2;
        y = sin(radians) * radius;
        vertex(x, y, z);
        vertex(-x, y, z);
      }
    endShape();
  }
  
  float Sign(float a){
    if(a > 0) return 1;
    else if(a < 0) return -1;
    else return 0;
  }
  
} // class Robot end }

class Ball{
  
  int point = 0; //点数
  float x = 500,y = -300,z = 0; //ポジション
  float direX = -10,direZ = 0; //軸方向の移動量
  float speed = 10; //速度
  float speedY = -20; //上下の速度
  float r = random(-PI,PI); //ボールの回転
  float rotating = 0; //ボールの回転量
  boolean oneceLock = true; //レシーブ判定が連続しないためのboolean
  
  void Draw(){
    
    pushMatrix();
      translate(x,y,z);
      Shadow(0,-y-1,0,250+y/10);
      
      translate(50,0,0);
      rotateY(r);
      rotateX(r);
      shape(Ball);
    popMatrix();
    
    if(y <-100){
      y += speedY;
      x += direX;
      z += direZ;
      speedY += 0.5f;
      r += rotating;
    }
    
    if(bot.receive){
      if(abs(x-bot.x)<300 && abs(z-bot.z)<300){
        Received(bot);
      }
    }
    if(bot2.receive){
      if(abs(x-bot2.x)<300 && abs(z-bot2.z)<300){
        Received(bot2);
      }
    }
    
    if(!oneceLock){
      if(speedY>0){
        oneceLock = true;
      }
    }
    
  } // Draw() end }
  
  //レシーブメソッド
  void Received(Robot bot){
    if(oneceLock && y>-350){ 
      oneceLock = false; //連続しないために
      
      float ro = atan2(z-bot.z,x-bot.x);
      speedY *= -1;
      direX = cos(ro) * speed;
      direZ = sin(ro) * speed;
      point += bot.foolNum;
      bot.foolNum = 1;
      rotating = random(-0.02,0.02);
    }
  }
} //class Ball end }

// 影を描くメソッド
// Shadow(ポジションX,Y,Z,大きさ)
void Shadow(float x,float y,float z,float size){
  pushMatrix();
    translate(x,y,z);
    rotateX(PI/2);
    fill(0);noStroke();
    ellipse(0,0,size,size);
  popMatrix();
}



void keyPressed(){
  if(key == 'w' || key == 'W') bot.up = true;
  if(key == 'a' || key == 'A') bot.left = true;
  if(key == 's' || key == 'S') bot.down = true;
  if(key == 'd' || key == 'D') bot.right = true;
  if(keyCode == SHIFT) bot.receive = true;
  if(key == 'f' || key == 'F'){
    bot.fool = true;
    bot.mode = Mode.Fool;
  }
  
  if(keyCode == UP) bot2.up = true;
  if(keyCode == LEFT) bot2.left = true;
  if(keyCode == DOWN) bot2.down = true;
  if(keyCode == RIGHT) bot2.right = true;
  if(keyCode == ENTER) bot2.receive = true;
  if(key == 'l' || key == 'L'){
    bot2.fool = true;
    bot2.mode = Mode.Fool;
  }
  
  if(key == 'r' || key == 'R') BallReset();
}

void keyReleased(){
  if(key == 'w' || key == 'W') bot.up = false;
  if(key == 'a' || key == 'A') bot.left = false;
  if(key == 's' || key == 'S') bot.down = false;
  if(key == 'd' || key == 'D') bot.right = false;
  if(keyCode == SHIFT) bot.receive = false;
  
  if(keyCode == UP) bot2.up = false;
  if(keyCode == LEFT) bot2.left = false;
  if(keyCode == DOWN) bot2.down = false;
  if(keyCode == RIGHT) bot2.right = false;
  if(keyCode == ENTER) bot2.receive = false;
}
```

#使用画像
「Ball.png」
![Ball.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/554244/3c8b8e07-37b5-66da-66c4-b650ceccfbc1.png)