Processingでエアーホッケーを作りました
当たり判定の計算は負荷軽減とか考えず、毎フレーム行ってます(てへぺろ)
当時負荷軽減という概念を考えなかったから許して
右のプレイヤーはマウスで
左のプレイヤーは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);
}