#やること
前回の記事は以下にあります
https://qiita.com/strict39275/items/41da2ad3bb8fd60228e0
じっくり考えても、自分の理想には届かなかったコードですが、これから改善をしていきたいと思います。今回の記事はそれぞれのクラス説明をしていきたいと思っております。いきなり全部説明すると途方にない時間になりそうなので、次回は別のクラスを一つずつ丁寧に説明した方が良さそう。やったるぞ。
#クラス構造の図
shiracamus様が作りましたクラス構造図です。breakoutクラスをメインにして、その中にクラスのインスタンス変数を作った感じですかね。
#プログラムコード
一つずつ、反省も含めて説明をしていきたいと思っております
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import java.util.Timer;
import java.util.TimerTask;
import文はコードの先頭に宣言した方がよさそうですね。そうすれば、このコードが何のライブラリを用いるか分かりやすくなるからです。
import javax.swingなどの宣言を入力することで。javaが作ったクラスを利用することができるようになります。つまり、自分でコードを作らなくても、画面表示できたり、マウスイベントが入力できるようになります。
import文をほとんどを、オンデマンド型インポートを使用していますね。オンデマンド型をインポートすると例えば javax.util内の機能を全て使えるようになります。つまり、インポート文の最後に✳︎つければ、エラーの心配もなくなります。ただし、どの機能を使えば良いか分からなくなるので、気をつけたほうがいいですね
#breakoutクラスの説明
今回はbreakoutクラスの説明のみとさせていただきます
public class breakout extends JPanel implements MouseMotionListener{
static int countball =15;
Racket racket;
Ball[] ball;
Block[] block;
Unbreakblock[] block1;
Twobreakblock[] block2;
Threebreakblock[] block3;
double time;
int remain=37;
boolean gameover=false;
##このコード内にある機能
・breakoutクラスはJPanelの機能を継承し、実際に画面を表示できる機能を有する。そのパネルの中で、implementsを入力し、マウスの機能を使えるようにした
・staticでクラス変数として宣言し、ボールの数を15個にする。
・staticで宣言されていないインスタンス変数racket,ballblock1 block2,block3を宣言し、それぞれのクラスの機能を有する変数を取る。
・実行してからgameoverの値がTrueになるまでの時間を37秒と設定した
・初期状態はgameoverの状態ではないので、初期の真偽値はfalseとした。
##言い換えると何をしたのか
ゲームを作るうえでの土台を作るところです。ゲームを作ったとしても画面表示されないと意味ないですし、マウスの機能を持たないとボールを跳ね返すラケットすらも使えないので、いったんそのように使える環境を作ったのがこのコードです。ボール作りたいのに何個あればわからないとゲームできるわけないので、とりあえずは初期値を定義しました。
##ブロックの数と画面の大きさのコード
static int x=855;
static int y=800;
static int size =15; //countballでボール数が宣言されているのでいらないです
//水色のブロックの数
static final int NUM_BLOCK_ROW = 4;
// ブロックの列数
static final int NUM_BLOCK_COL = 9;
// ブロック数
static final int NUM_BLOCK = NUM_BLOCK_ROW * NUM_BLOCK_COL;
//灰色のブロックの数
static final int NUM_BLOCK_ROW1 = 8;
static final int NUM_BLOCK_COL1 = 1;
static final int NUM_BLOCK1 = NUM_BLOCK_ROW1 * NUM_BLOCK_COL1;
//緑のブロックの数
static final int NUM_BLOCK_ROW2 = 8;
static final int NUM_BLOCK_COL2 = 3;
static final int NUM_BLOCK2 = NUM_BLOCK_ROW2 * NUM_BLOCK_COL2;
//黄色のブロックの数
static final int NUM_BLOCK_ROW3 = 8;
static final int NUM_BLOCK_COL3 = 4;
static final int NUM_BLOCK3 = NUM_BLOCK_ROW3 * NUM_BLOCK_COL3;
//すべてのブロックの数を求める
static final int SumBlock= NUM_BLOCK+NUM_BLOCK2+NUM_BLOCK3;
static int size=15は忘れてください
##このコード内にある機能
・パネルの横の大きさを855縦の長さを800とした
・ここでブロックの数を宣言する。ROWはブロックの列の数COLはブロックの行の数を指す
・掛け算を行いブロックの数を求める。例えば列8行4とすると8×4=32のブロックができる
・水色、灰色、緑、黄色のブロックの数を求める
・それぞれの合計をSumblockとする
##言い換えると何をしたのか
ゲーム画面の大きさを定義し、また、ブロックの数を宣言しました。ここで、ブロックの数を自由に変えることができます。
このブロックの数は減った際の値を引き継ぎたいのでstaticとして宣言し、ほかにもクラス変数として使うためにも用いました。finalの宣言は必要なかったですね。
##ブロックの初期位置のコード
//二次元マップの作成
private char[][] map;
private int MX = 20, MY = 18;
private String[] map_str = {
" B",
" B",
" B",
" B",
" B",
" B",
" B",
" B",
" B",
" B",
" B",
" B",
" B",
" B",
" B",
" B",
" B",
" B",
" B",
};
##このコード内にある機能
・char型のmap変数で、実際にブロックを描画する変数を作る
・描画するブロックの範囲は横20縦18とする
・ブロックの配置場所は右のみとなっている
ここでなぜ 左の壁と上の壁にもブロックが配置されているかはなんと今後のコードに初期値として定義されているからでした。
##ボールの機能とブロックの位置のコード
public breakout(){
time = System.currentTimeMillis() * 0.001 + remain;
addMouseMotionListener(this);
racket =new Racket();
ball = new Ball[countball];
Random rand = new Random();
int n=countball;
int num[] = new int [n];
for(int i=0;i<n;i++){
num[i]= 40+rand.nextInt(700);
ball[0]=new Ball(num[0],250,5,-6,7);
ball[1]=new Ball(num[1],260,-5,-3,10);
ball[2]=new Ball(num[2],420,4,6,8);
ball[3]=new Ball(num[3],480,-5,2,10);
ball[4]=new Ball(num[4],590,5,-6,11);
ball[5]=new Ball(num[5],550,-5,-3,12);
ball[6]=new Ball(num[6],570,4,6,13);
ball[7]=new Ball(num[7],480,-5,2,14);
ball[8]=new Ball(num[8],490,5,-6,8);
ball[9]=new Ball(num[9],400,-5,-3,8);
ball[10]=new Ball(num[10], 350,4,6,9);
ball[11]=new Ball(num[11],400,-5,2,10);
ball[12]=new Ball(num[12],390,-5,-3,10);
ball[13]=new Ball(num[13],500,4,6,10);
ball[14]=new Ball(num[14],530,-5,2,7);
}
block = new Block[NUM_BLOCK];
block1 = new Unbreakblock[NUM_BLOCK1];
block2 = new Twobreakblock[NUM_BLOCK2];
block3 =new Threebreakblock[NUM_BLOCK3];
for (int i = 0; i < NUM_BLOCK_ROW; i++) {
for (int j = 0; j < NUM_BLOCK_COL; j++) {
int x =2* j * Block.WIDTH + Block.WIDTH+50;
int y =2* i * Block.HEIGHT + Block.HEIGHT+600;
block[i * NUM_BLOCK_COL + j] = new Block(x, y);
}
}
for ( int c = 0; c < NUM_BLOCK_ROW1; c++) {
for (int d = 0; d < NUM_BLOCK_COL1; d++) {
int a = 2*c * Unbreakblock.WIDTH1 + Unbreakblock.WIDTH1+50;
int b = d * Unbreakblock.HEIGHT1 + Unbreakblock.HEIGHT1+450;
block1[d * NUM_BLOCK_COL1 + c] = new Unbreakblock(a, b);
}
}
for ( int c = 0; c < NUM_BLOCK_ROW2; c++) {
for (int d = 0; d < NUM_BLOCK_COL2; d++) {
int a = 2*c * Twobreakblock.WIDTH2 + Twobreakblock.WIDTH2+50;
int b = 2*d * Twobreakblock.HEIGHT2 + Twobreakblock.HEIGHT2+300;
block2[c* NUM_BLOCK_COL2 + d] = new Twobreakblock(a, b);
}
}
for ( int c = 0; c < NUM_BLOCK_ROW3; c++) {
for (int d = 0; d < NUM_BLOCK_COL3; d++) {
int a =2* c * Threebreakblock.WIDTH3 + Threebreakblock.WIDTH3+50;
int b = 5*d * Threebreakblock.HEIGHT3 + Threebreakblock.HEIGHT3+60;
block3[c * NUM_BLOCK_COL3 + d] = new Threebreakblock(a, b);
}
}
TimeBomb timeBomb = new TimeBomb();
Timer timer = new Timer();
timer.schedule(timeBomb, 5000);
map = new char[MY+2][MX+2];
for (int x = 0; x <= MX+1; x++) {
map[0][x] = 'B';
// map[MY+1][x] = 'B';いらないです
}
for (int y = 0; y <= MY+1; y++) {
map[y][0] = 'B';
//map[y][MX+1] = 'B'; //いらないです
}
for (int y = 1; y <= MY; y++) {
for (int x = 1; x <= MX; x++) {
map[y][x] = map_str[y-1].charAt(x-1);
}
}
}
##このコード内にある機能
・制限時間を有するdouble型のtimeにremainにプラス、現在の制限時間の×0.001とする。
・ここでRacket,Ballクラスのインスタンス変数を用いる
・ボールの横の座標をランダムにするためにrandを宣言する
・ボールの横の座標を40に続いて0~700までのランダムに数字を配列numに代入させる。つまり、15個のボールの横の座標をランダムに生成して、その値をnumに代入する。
・Ballクラスに宣言されている引数は左から、ボールの横の座標、ボールの縦の座標、ボールの横へ進む速度、ballの縦へ進む速度 としている。縦の座標はブロックの座標と被らないように、手動で入力した。
・ブロックの数をそのままblock,block1,block2,block3にインスタンス変数を生成した。
・縦の座標、横の座標を記入するために、for文で多重ループさせて、x,yやa,bなどにブロックの座標をそれぞれ設置した。
・ timer.schedule(timeBomb, 5000);でプログラムが実行されてもボール、ブロックの機能などを最初の5秒間は停止するようにした。
・ブロックの配置初期位置を定義した。ブロックのいらないとコメントしたところは壁以外でブロックを置けるようにした機能なのでいらないです
##言い換えると何をしたのか
ここで初めて、ボールの機能、ブロックの位置、緑の壁の位置を定義しました。ブロックとボールの座標がかぶらないようにボールの縦の座標は手動に設定しました。そうでないと、ブロックの中にボールがある状態となってしまい、風船が割れて中身が出てきたような感じになってしまうので縦の座標はランダムは無しにしました。前回のBBBと表示されているコードもありましたがここでも、ブロックを置けることができます。
##コードのいらない部分
for(int i=0;i<n;i++){
num[i]= 40+rand.nextInt(700);
}
ball[0]=new Ball(num[0],250,5,-6,7);
ball[1]=new Ball(num[1],260,-5,-3,10);
ball[2]=new Ball(num[2],420,4,6,8);
ball[3]=new Ball(num[3],480,-5,2,10);
ball[4]=new Ball(num[4],590,5,-6,11);
ball[5]=new Ball(num[5],550,-5,-3,12);
ball[6]=new Ball(num[6],570,4,6,13);
ball[7]=new Ball(num[7],480,-5,2,14);
ball[8]=new Ball(num[8],490,5,-6,8);
ball[9]=new Ball(num[9],400,-5,-3,8);
ball[10]=new Ball(num[10], 350,4,6,9);
ball[11]=new Ball(num[11],400,-5,2,10);
ball[12]=new Ball(num[12],390,-5,-3,10);
ball[13]=new Ball(num[13],500,4,6,10);
ball[14]=new Ball(num[14],530,-5,2,7);
でも問題がないような感じがしてきました。実際にコンパイラして、わざわざ何回もインスタンス宣言する必要がなくて、for文の中に入るのは num[i]= 40+rand.nextInt(700);で十分でしたね。
#感想
breakoutクラスのメソッドと、それ以降のクラスや、TimerTaskは次回にします。
正直なところ、やりたいことはなんとなく理解しましたが、無駄なコードを書く部分が多すぎましたね。疑問点が多すぎる。中途半端すぎるのが残念ですね。完璧にしすぎては時間が消えるので、ある程度は削って、加えたりしていきたいと思います。