Javaの勉強として、YouTuberの「エンジニアねずみ」さんと言う方の「JavaでSnakeGameをつくってみた!」という動画を参考に実際にゲームを作ってみました。
まずは完成形から。
このようにスネークのようなものがランダムに生成される赤い球を取っていくゲームです。球を食べたスネークは自分の体が1ブロックずつ伸びます。
スネークが自分の体にぶつかるか枠の外に出てしまうとゲームオーバーになります。
ゲームオーバーになるとこの画面になります。
まずは、メインメソッドとなる「SnakeGame」というクラスの中に
public class SnakeGame {
public static void main(String[]args) {
new GameFrame();
}
}
Game Frameというクラスをインスタンス化している。
GameFrameクラス
次に、GameFrameクラスを作る。
GameFrame()というコンストラクタの中に記述していく。
コンストラクタとは、「クラスがnewされた直後に自動的に実行される」もので、コンストラクタとして定義されたGameFrameはnewされると自動的に実行される。※コンストラクタは開発者が直接呼び出せない。
this.add(new GamePanel());
まずは後述するGamePanelというクラスを呼び出している??
this.setTitle(“SnakeGame”)
これはウインドウの上部に表示されるタイトルを表示させる部分に「SnakeGame」というタイトルをつけることができる。
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
これによってウインドを閉じることができる。
this.setResizable(false);
これはフレームのサイズを変更できるかどうかを設定するもの。引数をfalseにしているので変更はできない。
this.pack()
これはコンテナーに登録(add()メソッド)されているコンポーネントの推奨サイズと設定したレイアウトからコンテナーのサイズを決定してくれるメソッド。
このメソッドを書いていないと、
この部分しか表示されなくなり、全体がうまく見えなくなるとわかった(適切なサイズに調整してくれている)。
this.setVisible(true);
このメソッドの引数にtrueを指定すると対象のフレームが表示される。
this.setLocationRelativeTo(null);
画面の中央にフレームを表示させる(引数にnull)ことができる。
GamePanel
最後にGamePanelクラスを作成する。
public class GamePanel extends JPanel implements ActionListener {}
GamePanelはActionListenerを継承している。
ActionListenerはアクション・イベントを受け取るためのリスナー・インターフェースである。アクション・イベントが発生すると、オブジェクトのactionPerformedメソッドが呼び出される。このゲームではオーバライドしている。
まずはフィールドを定義する。
static final int SCREEN_WIDTH = 1300;
static final int SCREEN_HEIGHT = 750;
static final int UNIT_SIZE = 50;
static final int GAME_UNITS = (SCREEN_WIDTH * SCREEN_HEIGHT)/(UNIT_SIZE * UNIT_SIZE);
static final int DELAY = 175;
final int x[] = new int[GAME_UNITS];
final int y[] = new int[GAME_UNITS];
int bodyParts = 6;
int applesEaten;
int appleX;
int appleY;
char direction = ‘R’;
boolean running = false;
Timer timer;
Random random;
ーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーー
ここからはまだ自分ではよくわかりませんでした。
GamePanel(){
random = new Random();
this.setPreferredSize(new Dimension(SCREEN_WIDTH,SCREEN_HEIGHT));
this.setBackground(Color.black);
this.setFocusable(true);
this.addKeyListener(new MyKeyAdapter());
startGame();
}
public void startGame() {
newApple();
running = true;
timer = new Timer(DELAY,this);
timer.start();
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
draw(g);
}
public void draw(Graphics g) {
if(running) {
g.setColor(Color.red);
g.fillOval(appleX,appleY,UNIT_SIZE,UNIT_SIZE);
for(int i = 0; i < bodyParts;i++) {
if(i==0) {
g.setColor(Color.green);
g.fillRect(x[i], y[i], UNIT_SIZE, UNIT_SIZE);
}else {
g.setColor(new Color(45,180,0));
g.fillRect(x[i], y[i], UNIT_SIZE, UNIT_SIZE);
}
}
g.setColor(Color.red);
g.setFont(new Font(“Ink Free”,Font.BOLD,40));
FontMetrics metrics = getFontMetrics(g.getFont());
g.drawString(“Score: ” +applesEaten, (SCREEN_WIDTH – metrics.stringWidth(“SCORE: “+applesEaten))/2,g.getFont().getSize());
}else {
gameOver(g);
}
}
public void newApple() {
appleX = random.nextInt((int)(SCREEN_WIDTH/UNIT_SIZE))*UNIT_SIZE;
appleY = random.nextInt((int)(SCREEN_WIDTH/UNIT_SIZE))*UNIT_SIZE;
}
public void move() {
for(int i = bodyParts; i>0;i–) {
x[i] = x[i-1];
y[i] = y[i-1];
}
switch(direction) {
case ‘U’:
y[0] = y[0] – UNIT_SIZE;
break;
case ‘D’:
y[0] = y[0] + UNIT_SIZE;
break;
case ‘L’:
x[0] = x[0] – UNIT_SIZE;
break;
case ‘R’:
x[0] = x[0] + UNIT_SIZE;
break;
}
}
public void checkApple() {
if((x[0] == appleX) && (y[0] == appleY)) {
bodyParts++;
applesEaten++;
newApple();
}
}
public void checkCollisions() {
for(int i = bodyParts; i>0; i–) {
if((x[0]==x[i])&&(y[0]==y[i])) {
running = false;
}
}
if(x[0] < 0) {
running = false;
}
if(x[0]>SCREEN_WIDTH) {
running = false;
}
if(y[0] < 0) {
running = false;
}
if(y[0]>SCREEN_HEIGHT) {
running = false;
}
if(!running) {
timer.stop();
}
}
public void gameOver(Graphics g) {
g.setColor(Color.red);
g.setFont(new Font(“Ink Free”,Font.BOLD,40));
FontMetrics metrics1 = getFontMetrics(g.getFont());
g.drawString(“Score: ” +applesEaten, (SCREEN_WIDTH – metrics1.stringWidth(“SCORE: “+applesEaten))/2,g.getFont().getSize());
g.setColor(Color.red);
g.setFont(new Font(“ink Free”,Font.BOLD,75));
FontMetrics metrics2 = getFontMetrics(g.getFont());
g.drawString(“Game Over”, (SCREEN_WIDTH – metrics2.stringWidth(“Game Over”))/2, SCREEN_HEIGHT/2);
}
@Override
public void actionPerformed(ActionEvent e) {
if(running) {
move();
checkApple();
checkCollisions();
}
repaint();
}
public class MyKeyAdapter extends KeyAdapter{
@Override
public void keyPressed(KeyEvent e) {
switch(e.getKeyCode()) {
case KeyEvent.VK_LEFT:
if(direction !=’R’) {
direction = ‘L’;
}
break;
case KeyEvent.VK_RIGHT:
if(direction !=’L’) {
direction = ‘R’;
}
break;
case KeyEvent.VK_UP:
if(direction !=’D’) {
direction = ‘U’;
}
break;
case KeyEvent.VK_DOWN:
if(direction !=’U’) {
direction = ‘D’;
}
break;
}
}
}
}
実行すると動くには動くのですが、赤い球を三個取るとそこから赤い球が出なくなったり、そもそも赤い球が出ない時もありました。
今の自分ではこれを治す方法がわからないので勉強していつかこの問題を解決したいと思います。
コメント