VSCodeでJavaを始める方法(環境構築)
①VSCodeのインストール
(※VSCodeをすでにインストールしている場合は飛ばしてかまいません。)
まず初めに、下記のVSCode公式サイトからVSCodeをダウンロードします。
https://code.visualstudio.com/
使用しているOSを選んで、左側のStableを選択してVSCodeのUserSetup.exeをダウンロードします。
次に、ダウンロードしたUserSetup.exeを起動して、インストールを行います。使用許諾契約書に同意し、
・デスクトップ上にアイコンを作成する
・PATHへの追加
にチェックを付けて最後にインストールをクリックします。
インストールをクリックすると、インストールが開始され、インストールが終了するとデスクトップにVSCodeのショートカットアイコンが表示されます。
アイコンをダブルクリックしてVSCodeが起動すれば、VSCodeのインストールは正常に行えています。
②JDKのインストール
Javaの開発に必要となるJDK(Java Development Kit)をインストールします。下記の公式サイトからJDKのインストーラをダウンロードします。
https://www.oracle.com/java/technologies/downloads/#jdk17-windows
使用しているOSを選んで、Windowsであれば「x64 Installer」を選択してインストーラをダウンロードします。
インストーラがダウンロードできたら、インストーラを起動し、インストーラの指示に従ってそのままの設定で次に進んでダウンロードします。
③Extension Pack for Java(拡張機能)のインストール
VSCodeに拡張機能をインストールし、VSCode内で簡単にjavaファイルを実行できるようにします。
VSCodeを起動し、画面左にあるアイコンの上から5番目の拡張機能(Extension)をクリックします。左上の検索欄に「Extension Pack for Java」と入れて、Extension Pack for Javaをインストールします。
拡張機能がインストール出来たら、最後にパスを通します。「ファイル→ユーザー設定→設定」と移動し、画面上部の検索欄に「java.home」と入力します。
「settings.jsonで編集」をクリックして、
"java.home": "C:\\Program Files\\Java\\{JDKのバージョン}"
を追加します。また、settings.jsonに複数の項目がある場合は、最後にコンマも付けます。jdk-17.0.1の場合は次のようになります。
"java.home": "C:\\Program Files\\Java\\jdk-17.0.1",
これでパスが通り、環境構築は完了です。最後に再起動しておきましょう。
④プロジェクトの作成
環境構築が完了したら、プロジェクトを作成して、実際にコードを書いていきます。
まず、Cドライブなどにプロジェクトを保存するフォルダを新規作成します。
次にコマンドパレットを開いて、「create java project」と入力し、java projectを作成します。
「No build tools」を選択したら、先ほど作成した保存用のフォルダを選択し、プロジェクト名(自由な名前)を入力します。
プロジェクト名を入力すると新しいウィンドウが起動します。srcフォルダにあるApp.javaは"Hello, World!"と出力するテンプレートです。
画面右の再生マークから「Run Java」をクリックするとプログラムを実行することができます。
画面下のターミナルに「Hello, World!」と出力されれば成功です。
VSCodeでPythonを始める方法(環境構築)
①VSCodeのインストール
(※VSCodeをすでにインストールしている場合は飛ばしてかまいません。)
まず初めに、下記のVSCode公式サイトからVSCodeをダウンロードします。
https://code.visualstudio.com/
使用しているOSを選んで、左側のStableを選択してVSCodeのUserSetup.exeをダウンロードします。
次に、ダウンロードしたUserSetup.exeを起動して、インストールを行います。使用許諾契約書に同意し、
- デスクトップ上にアイコンを作成する
- PATHへの追加
にチェックを付けて最後にインストールをクリックします。
インストールをクリックすると、インストールが開始され、インストールが終了するとデスクトップにVSCodeのショートカットアイコンが表示されます。
アイコンをダブルクリックしてVSCodeが起動すれば、VSCodeのインストールは正常に行えています。
②Pythonのインストール
下記のPython公式サイトからPythonをダウンロードします。
https://www.python.org/downloads/windows/
赤枠で囲まれた最新バージョンをクリックします。
最新バージョンのページに飛ぶので、下にスクロールするとインストーラのダウンロードボタンがあります。
赤枠で囲まれたWindows用のインストーラをダウンロードします。
(macOSの場合はmacOS用のインストーラをダウンロードしてください。)
次に、ダウンロードしたインストーラを起動して、インストールを行います。
下の画像の赤枠のように、「Add python.exe to PATH」にチェックを入れてください。
後から手動で設定することもできますが、チェックを入れるだけでできるので必ずやりましょう。
チェックを入れたら「Install Now」をクリックしてインストールを開始します。
インストールが完了したら下のような画面になるので、「Close」をクリックしてウィンドウを閉じて大丈夫です。
これで環境構築は完了です。
③プログラムの作成
環境構築が完了したら、実際にプログラムを書いていきます。 まず、Cドライブなどにプログラムを保存するためのフォルダを新規作成します。
次にVSCodeを起動して、「ファイル→フォルダを開く」と移動し、新規作成したフォルダを指定します。
下の画像の赤丸からファイルを作成し、ファイル名を入力します。
ここでは「test.py」としています。
「Hello World!」を出力するプログラムを作ります。
コードは単純で
print("Hello World!")
だけです。
コードが書けたら、画面左の虫と再生マークのアイコンから実行を行います。
「実行とデバッグ」を押して
「Pythonファイル」を選択するとプログラムが実行できます。
画面下のターミナルに「Hello World!」と出力されれば成功です。
Javaでブロック崩し(解説)⑵パドルを動かす
①キー入力の処理
ボールを動かすことができたら、ボールを跳ね返すパドルを作ります。今回は、パドルを作り、ボールを跳ね返すところまで作ります。
まず、キーボードから操作できるように、キー入力が行われたときの処理を追加します。Sceneには、setOnKeyPressedというキーが押されたされたときに呼び出される関数と、setOnKeyReleasedというキーが離されたときに呼び出される関数があるので、それらをBreakoutクラスに追加します。
//キーが押されたときの処理 scene.setOnKeyPressed( new EventHandler<KeyEvent>(){ public void handle(KeyEvent e){ //ここにキーが押されたときの処理を記述 } } ); //キーが離されたときの処理 scene.setOnKeyReleased( new EventHandler<KeyEvent>(){ public void handle(KeyEvent e){ //ここにキーが離されたときの処理を記述 } } );
同時押しにも対応させたいため、リストを宣言して、キーが押されたときにリストに追加、キーが離されたときにリストから削除を行います。 インポートも忘れず行いましょう。
import java.util.ArrayList;
Breakoutクラスのメンバ変数に追加します。
//キャンバスの幅と高さ final int WIDTH = 1000; final int HEIGHT = 800; //入力キーを保持するリスト ArrayList<String> input = new ArrayList<>();
具体的な処理を記述します。 *1
//キーが押されたときの処理 scene.setOnKeyPressed( new EventHandler<KeyEvent>(){ public void handle(KeyEvent e){ //ここにキーが押されたときの処理を記述 String key = e.getCode().toString(); if(!input.contains(key)){ input.add(key); } } } ); //キーが離されたときの処理 scene.setOnKeyReleased( new EventHandler<KeyEvent>(){ public void handle(KeyEvent e){ //ここにキーが離されたときの処理を記述 String key = e.getCode().toString(); input.remove(key); } } );
あとは、リストに特定のキーが存在したら、そのキーが押されたときの処理を行えばよいです。 例えば、リストに"A"が存在したら、パドルを左に動かす処理をするといった具合です。 その前に、パドルクラスを作っておきます。
②パドルクラスの作成
パドルクラスに必要な変数は次の2つです。
・パドルの座標
・パドルの幅と高さ
必要なメソッドは次の3つです。
・変数に初期値を代入するコンストラクタ
・パドルを移動するメソッド
・パドルを描画するメソッド
ボールを跳ね返すメソッドは、ボール側のクラスに実装します。
(後々作ることになるブロックにも跳ね返りの処理があるので、本当は長方形の親クラスを作ってから、それを継承したパドルクラス、ブロッククラスというように作ったほうがいいですが、今回は分かりやすさ重視で行きます。)
import javafx.scene.canvas.GraphicsContext; import javafx.scene.paint.Color; public class Paddle{ //パドルの左上の座標 int x; int y; //パドルの幅と高さ int w; int h; //コンストラクタ public Paddle(int x, int y, int w, int h){ //初期値を代入 this.x = x; this.y = y; this.w = w; this.h = h; } //移動するメソッド(移動量と画面サイズを引数で受け取る) public void move(int vx, int vy, int width, int height){ //パドルが左右に画面外に行かないとき左右に移動する if(x + vx > 0 && x + vx + w < width){ x += vx; } //パドルが上下に画面外に行かないとき上下に移動する if(y + vy > 0 && y + vy + h < height){ y += vy; } } //描画メソッド public void draw(GraphicsContext gc){ //青色 gc.setFill(Color.BLUE); //長方形を描画 gc.fillRect(x, y, w, h); } }
パドルクラスを作ったので、Breakoutクラスに追加してインスタンスの生成を行います。 ・メンバ変数に追加
//ボール Ball ball; //パドル Paddle paddle;
・インスタンスの生成(画面の高さを0.9倍することで、画面下部に生成することができます。)
//ボールをインスタンス化 ball = new Ball(WIDTH / 2, HEIGHT / 2, 5, 1, 1); //パドルをインスタンス化 paddle = new Paddle(WIDTH / 2, (int)(HEIGHT * 0.9), 40, 10);
現時点でのBreakoutクラスのソースコードはこのようになります。
import java.util.ArrayList; import javafx.animation.KeyFrame; import javafx.animation.Timeline; import javafx.application.Application; import javafx.event.ActionEvent; import javafx.event.EventHandler; import javafx.scene.Scene; import javafx.scene.canvas.Canvas; import javafx.scene.canvas.GraphicsContext; import javafx.scene.input.KeyEvent; import javafx.scene.layout.BorderPane; import javafx.stage.Stage; import javafx.util.Duration; import javafx.scene.paint.Color; public class Breakout extends Application{ public static void main(String[] args) throws Exception { launch(); } //キャンバスの幅と高さ final int WIDTH = 1000; final int HEIGHT = 800; //入力キーを保持するリスト ArrayList<String> input = new ArrayList<>(); //ボール Ball ball; //パドル Paddle paddle; @Override public void start(Stage stage) throws Exception { //ウィンドウのタイトルをセット stage.setTitle("Breakout"); //親ノードをボーダーパネルで生成 BorderPane root = new BorderPane(); //親ノードを引数としてシーンを生成 Scene scene = new Scene(root); //描画するためのキャンバスを生成 Canvas canvas = new Canvas(WIDTH, HEIGHT); //キャンバスに描画するGraphicsContextを生成 GraphicsContext gc = canvas.getGraphicsContext2D(); //キャンバスをボーダーパネルの中央に配置 root.setCenter(canvas); //シーンをステージにセット stage.setScene(scene); //ステージを表示 stage.show(); //ボールをインスタンス化 ball = new Ball(WIDTH / 2, HEIGHT / 2, 5, 1, 1); //パドルをインスタンス化 paddle = new Paddle(WIDTH / 2, (int)(HEIGHT * 0.9), 40, 10); //キーが押されたときの処理 scene.setOnKeyPressed( new EventHandler<KeyEvent>(){ public void handle(KeyEvent e){ //ここにキーが押されたときの処理を記述 String key = e.getCode().toString(); if(!input.contains(key)){ input.add(key); } } } ); //キーが離されたときの処理 scene.setOnKeyReleased( new EventHandler<KeyEvent>(){ public void handle(KeyEvent e){ //ここにキーが離されたときの処理を記述 String key = e.getCode().toString(); input.remove(key); } } ); Timeline timeline = new Timeline(); KeyFrame keyframe = new KeyFrame(Duration.seconds(0), new EventHandler<ActionEvent>() { public void handle(ActionEvent e){ //ここに処理を記述 //ボールを移動 ball.update(WIDTH, HEIGHT); //描画メソッドを呼び出す draw(gc); } }); timeline.getKeyFrames().addAll(keyframe, new KeyFrame(Duration.seconds(0.01))); //1フレームの間隔 timeline.setCycleCount(Timeline.INDEFINITE); timeline.play(); } //描画メソッド public void draw(GraphicsContext gc){ //背景を白で塗りつぶす gc.setFill(Color.WHITE); gc.fillRect(0, 0, WIDTH, HEIGHT); //ボールの描画メソッドを呼び出す ball.draw(gc); //パドルの描画メソッドを呼び出す paddle.draw(gc); } }
③キー入力でパドルを動かす
入力キーをリストで保持しているため、リストに移動キーが存在するなら、パドルの移動メソッドを呼び出します。操作はWASDで行います。
注意点として、パドルの速度とボールの速度が異なると挙動がおかしくなる場合があります。一応異なる速度に対応させることはできますが、処理が複雑になってしまうのでおすすめしません。
KeyFrame keyframe = new KeyFrame(Duration.seconds(0), new EventHandler<ActionEvent>() { public void handle(ActionEvent e){ //ここに処理を記述 //左移動 if(input.contains("A")){ paddle.move(-1, 0, WIDTH, HEIGHT); } //右移動 if(input.contains("D")){ paddle.move(1, 0, WIDTH, HEIGHT); } //上移動 if(input.contains("W")){ paddle.move(0, -1, WIDTH, HEIGHT); } //上移動 if(input.contains("S")){ paddle.move(0, 1, WIDTH, HEIGHT); } //ボールを移動 ball.update(WIDTH, HEIGHT); //描画メソッドを呼び出す draw(gc); } });
実行すると、パドルが描画され、WASDでパドルを動かすことができます。 最後に、ボールとパドルの当たり判定を付けます。(当たり判定がブロック崩し最大の難関です。)
④ボールとパドルの当たり判定
ボールとパドルの当たり判定はボールが移動する直前に行います。衝突判定のメソッドはボールクラスに作成します。このメソッドは、パドルを引数として受け取り、パドルのどこ(上下左右)と衝突しているかを返します。
まず、ボールクラスに上下左右の方向を定数として宣言しておきます。ボールのインスタンスごとに値が変わるものではないので、クラス変数(static)の定数(final)で宣言します。
//方向定数 static final int TOP = 1; static final int BOTTOM = 2; static final int RIGHT = 3; static final int LEFT = 4; //ボールの中心座標 int x; int y; //ボールの半径 int r; //ボールの速度 int vx; int vy;
まず、パドルの上側の当たり判定について考えます。衝突しているときのボールとパドルのx座標、y座標の関係は図から次のようにわかります。
x座標は、「ボールの中心座標がパドルの幅に入っている」という条件が成り立ちます。
y座標は、「ボールの上側の座標<パドルの上側の座標<ボールの下側の座標」という大小関係が成り立ちます。
この条件から、上側の当たり判定はこのようになります。
//ボールとパドルの衝突判定 public int isCollideWithPaddle(Paddle paddle){ //パドルの座標と幅高さ int px = paddle.x; int py = paddle.y; int pw = paddle.w; int ph = paddle.h; //パドルの上側衝突判定 if(px < x && x < px + pw && y - r < py && py < y + r){ return TOP; } }
下左右にたいしても同じように考えることで、衝突判定のメソッドはこうなります。また、衝突していないときは0を返します。
//ボールとパドルの衝突判定 public int isCollideWithPaddle(Paddle paddle){ //パドルの座標と幅高さ int px = paddle.x; int py = paddle.y; int pw = paddle.w; int ph = paddle.h; //パドルの上側衝突判定 if(px < x && x < px + pw && y - r < py && py < y + r){ return TOP; } //パドルの下側衝突判定 if(px < x && x < px + pw && y - r < py + ph && py + ph < y + r){ return BOTTOM; } //パドルの左側衝突判定 if(py < y && y < py + ph && x - r < px && px < x + r){ return LEFT; } //パドルの右側衝突判定 if(py < y && y < py + ph && x - r < px + pw && px + pw < x + r){ return RIGHT; } //衝突していないときは0を返す return 0; }
衝突判定メソッドができたので、ボールの移動メソッドの中に入れて、switch文で衝突したときの処理を記述します。衝突判定にパドルが引数として必要なので、ボールの移動メソッドにも引数にパドルを追加します。
//ボールを動かすメソッド public void update(int width, int height, Paddle paddle){ int result = isCollideWithPaddle(paddle); switch(result){ case TOP: vy = -Math.abs(vy); break; case BOTTOM: vy = Math.abs(vy); break; case LEFT: vx = -Math.abs(vx); break; case RIGHT: vx = Math.abs(vx); break; } //ボールが画面端の左右に衝突していないか判定 if(x - r < 0 || x + r > width){ //速度を反転 vx = -vx; } //ボールが画面端の上下に衝突していないか判定 if(y - r < 0 || y + r > height){ //速度を反転 vy = -vy; } //座標に速度を足して動かす x += vx; y += vy; }
衝突したときは、各速度の絶対値を取って、プラスマイナスを付けています。単にマイナスをつけて反転するだけでは、ボールがパドルにめり込んだ時に速度が反転し続けて、パドルから出てこなくなることがあります。そこで、単に反転させるのではなく絶対値を取るやり方をしています。
最後に、ボールの移動メソッドの引数にパドルを追加したので、ボールの移動メソッドを呼び出しているところにパドルを引数で渡してあげます。
//ボールを移動 ball.update(WIDTH, HEIGHT, paddle); //描画メソッドを呼び出す draw(gc);
これで実行すると、パドルでボールを跳ね返すことができていることが分かります。
次回はいよいよブロック崩しのブロックを作成します。最後に現時点のソースコードを貼っておきます。
import java.util.ArrayList; import javafx.animation.KeyFrame; import javafx.animation.Timeline; import javafx.application.Application; import javafx.event.ActionEvent; import javafx.event.EventHandler; import javafx.scene.Scene; import javafx.scene.canvas.Canvas; import javafx.scene.canvas.GraphicsContext; import javafx.scene.input.KeyEvent; import javafx.scene.layout.BorderPane; import javafx.stage.Stage; import javafx.util.Duration; import javafx.scene.paint.Color; public class Breakout extends Application{ public static void main(String[] args) throws Exception { launch(); } //キャンバスの幅と高さ final int WIDTH = 1000 / 2; final int HEIGHT = 800 / 2; //入力キーを保持するリスト ArrayList<String> input = new ArrayList<>(); //ボール Ball ball; //パドル Paddle paddle; @Override public void start(Stage stage) throws Exception { //ウィンドウのタイトルをセット stage.setTitle("Breakout"); //親ノードをボーダーパネルで生成 BorderPane root = new BorderPane(); //親ノードを引数としてシーンを生成 Scene scene = new Scene(root); //描画するためのキャンバスを生成 Canvas canvas = new Canvas(WIDTH, HEIGHT); //キャンバスに描画するGraphicsContextを生成 GraphicsContext gc = canvas.getGraphicsContext2D(); //キャンバスをボーダーパネルの中央に配置 root.setCenter(canvas); //シーンをステージにセット stage.setScene(scene); //ステージを表示 stage.show(); //ボールをインスタンス化 ball = new Ball(WIDTH / 2, HEIGHT / 2, 5, 1, 1); //パドルをインスタンス化 paddle = new Paddle(WIDTH / 2, (int)(HEIGHT * 0.9), 40, 10); //キーが押されたときの処理 scene.setOnKeyPressed( new EventHandler<KeyEvent>(){ public void handle(KeyEvent e){ //ここにキーが押されたときの処理を記述 String key = e.getCode().toString(); if(!input.contains(key)){ input.add(key); } } } ); //キーが離されたときの処理 scene.setOnKeyReleased( new EventHandler<KeyEvent>(){ public void handle(KeyEvent e){ //ここにキーが離されたときの処理を記述 String key = e.getCode().toString(); input.remove(key); } } ); Timeline timeline = new Timeline(); KeyFrame keyframe = new KeyFrame(Duration.seconds(0), new EventHandler<ActionEvent>() { public void handle(ActionEvent e){ //ここに処理を記述 //左移動 if(input.contains("A")){ paddle.move(-1, 0, WIDTH, HEIGHT); } //右移動 if(input.contains("D")){ paddle.move(1, 0, WIDTH, HEIGHT); } //上移動 if(input.contains("W")){ paddle.move(0, -1, WIDTH, HEIGHT); } //上移動 if(input.contains("S")){ paddle.move(0, 1, WIDTH, HEIGHT); } //ボールを移動 ball.update(WIDTH, HEIGHT, paddle); //描画メソッドを呼び出す draw(gc); } }); timeline.getKeyFrames().addAll(keyframe, new KeyFrame(Duration.seconds(0.01))); //1フレームの間隔 timeline.setCycleCount(Timeline.INDEFINITE); timeline.play(); } //描画メソッド public void draw(GraphicsContext gc){ //背景を白で塗りつぶす gc.setFill(Color.WHITE); gc.fillRect(0, 0, WIDTH, HEIGHT); //ボールの描画メソッドを呼び出す ball.draw(gc); //パドルの描画メソッドを呼び出す paddle.draw(gc); } }
import javafx.scene.canvas.GraphicsContext; import javafx.scene.paint.Color; public class Ball { //方向定数 static final int TOP = 1; static final int BOTTOM = 2; static final int RIGHT = 3; static final int LEFT = 4; //ボールの中心座標 int x; int y; //ボールの半径 int r; //ボールの速度 int vx; int vy; //コンストラクタ public Ball(int x, int y, int r, int vx, int vy){ //初期値を代入 this.x = x; this.y = y; this.r = r; this.vx = vx; this.vy = vy; } //ボールを動かすメソッド public void update(int width, int height, Paddle paddle){ int result = isCollideWithPaddle(paddle); switch(result){ case TOP: vy = -Math.abs(vy); break; case BOTTOM: vy = Math.abs(vy); break; case LEFT: vx = -Math.abs(vx); break; case RIGHT: vx = Math.abs(vx); break; } //ボールが画面端の左右に衝突していないか判定 if(x - r < 0 || x + r > width){ //速度を反転 vx = -vx; } //ボールが画面端の上下に衝突していないか判定 if(y - r < 0 || y + r > height){ //速度を反転 vy = -vy; } //座標に速度を足して動かす x += vx; y += vy; } //ボールとパドルの衝突判定 public int isCollideWithPaddle(Paddle paddle){ //パドルの座標と幅高さ int px = paddle.x; int py = paddle.y; int pw = paddle.w; int ph = paddle.h; //パドルの上側衝突判定 if(px < x && x < px + pw && y - r < py && py < y + r){ return TOP; } //パドルの下側衝突判定 if(px < x && x < px + pw && y - r < py + ph && py + ph < y + r){ return BOTTOM; } //パドルの左側衝突判定 if(py < y && y < py + ph && x - r < px && px < x + r){ return LEFT; } //パドルの右側衝突判定 if(py < y && y < py + ph && x - r < px + pw && px + pw < x + r){ return RIGHT; } //衝突していないときは0を返す return 0; } //描画するメソッド public void draw(GraphicsContext gc){ //赤色にする gc.setFill(Color.RED); //座標を指定して円を描く gc.fillOval(x - r, y - r, r * 2, r * 2); } }
import javafx.scene.canvas.GraphicsContext; import javafx.scene.paint.Color; public class Paddle{ //パドルの左上の座標 int x; int y; //パドルの幅と高さ int w; int h; //コンストラクタ public Paddle(int x, int y, int w, int h){ //初期値を代入 this.x = x; this.y = y; this.w = w; this.h = h; } //移動するメソッド(移動量と画面サイズを引数で受け取る) public void move(int vx, int vy, int width, int height){ //パドルが左右に画面外に行かないとき左右に移動する if(x + vx > 0 && x + vx + w < width){ x += vx; } //パドルが上下に画面外に行かないとき上下に移動する if(y + vy > 0 && y + vy + h < height){ y += vy; } } //描画メソッド public void draw(GraphicsContext gc){ //青色 gc.setFill(Color.BLUE); //長方形を描画 gc.fillRect(x, y, w, h); } }
*1:以前にインターネットから引用したコードですが、ソースが見つけられなかったので、見つけ次第出典を記します。
Javaでブロック崩し(解説)⑴ボールを動かす
①はじめに
Javaで定番のブロック崩しを作っていきます。描画ライブラリはJavaFXを使いますが、awtなどを使う場合でも、描画処理以外はやることは同じなので参考になると思います。
②描画の下準備
まずは描画するためのウィンドウを作ります。JavaFXの描画の仕組みは、ウィンドウに当たるStage、ウィンドウ内の描画範囲に当たるScene、描画する各オブジェクト(図形やキャンバスなど)をノードとしてツリー構造にしています。そのため、それらを最初に生成する必要があります。
import javafx.application.Application; import javafx.scene.Scene; import javafx.scene.canvas.Canvas; import javafx.scene.canvas.GraphicsContext; import javafx.scene.layout.BorderPane; import javafx.stage.Stage; import javafx.scene.paint.Color; public class Breakout extends Application{ public static void main(String[] args) throws Exception { launch(); } @Override public void start(Stage stage) throws Exception { //ウィンドウのタイトルをセット stage.setTitle("Breakout"); //親ノードをボーダーパネルで生成 BorderPane root = new BorderPane(); //親ノードを引数としてシーンを生成 Scene scene = new Scene(root); //描画するためのキャンバスを生成 Canvas canvas = new Canvas(1000, 800); //キャンバスに描画するGraphicsContextを生成 GraphicsContext gc = canvas.getGraphicsContext2D(); //キャンバスをボーダーパネルの中央に配置 root.setCenter(canvas); //シーンをステージにセット stage.setScene(scene); //ステージを表示 stage.show(); } }
1000×800の真っ白なウィンドウが表示されます。 試しに、黒い四角を描画してみます。 「stage.show();」のあとにコードを追加します。
stage.show(); //黒色にセット gc.setFill(Color.BLACK); //(0, 0)から(300, 300)までの長方形を描画 gc.fillRect(0, 0, 300, 300);
左上に黒い四角が描画されます。
次に、1フレームごとに描画を更新する処理を書いていきます。Timelilneを用いて、KeyFrameを挿入することで、描画することができます。 適宜、必要なものをインポートしていきながら、書いていきます。
Timeline timeline = new Timeline(); KeyFrame keyframe = new KeyFrame(Duration.seconds(0), new EventHandler<ActionEvent>() { public void handle(ActionEvent e){ //ここに処理を記述 } }); timeline.getKeyFrames().addAll(keyframe, new KeyFrame(Duration.seconds(0.1))); //1フレームの間隔 timeline.setCycleCount(Timeline.INDEFINITE); timeline.play();
drawメソッドを作り、そこでキャンバスへの描画を行います。キャンバスのサイズをfinalで宣言して定数にしておきます。
import javafx.animation.KeyFrame; import javafx.animation.Timeline; import javafx.application.Application; import javafx.event.ActionEvent; import javafx.event.EventHandler; import javafx.scene.Scene; import javafx.scene.canvas.Canvas; import javafx.scene.canvas.GraphicsContext; import javafx.scene.layout.BorderPane; import javafx.stage.Stage; import javafx.util.Duration; import javafx.scene.paint.Color; public class Breakout extends Application{ public static void main(String[] args) throws Exception { launch(); } //キャンバスの幅と高さ final int WIDTH = 1000; final int HEIGHT = 800; @Override public void start(Stage stage) throws Exception { //ウィンドウのタイトルをセット stage.setTitle("Breakout"); //親ノードをボーダーパネルで生成 BorderPane root = new BorderPane(); //親ノードを引数としてシーンを生成 Scene scene = new Scene(root); //描画するためのキャンバスを生成 Canvas canvas = new Canvas(WIDTH, HEIGHT); //キャンバスに描画するGraphicsContextを生成 GraphicsContext gc = canvas.getGraphicsContext2D(); //キャンバスをボーダーパネルの中央に配置 root.setCenter(canvas); //シーンをステージにセット stage.setScene(scene); //ステージを表示 stage.show(); Timeline timeline = new Timeline(); KeyFrame keyframe = new KeyFrame(Duration.seconds(0), new EventHandler<ActionEvent>() { public void handle(ActionEvent e){ //ここに処理を記述 draw(gc); } }); timeline.getKeyFrames().addAll(keyframe, new KeyFrame(Duration.seconds(0.1))); //1フレームの間隔 timeline.setCycleCount(Timeline.INDEFINITE); timeline.play(); } //描画メソッド public void draw(GraphicsContext gc){ //背景を白で塗りつぶす gc.setFill(Color.WHITE); gc.fillRect(0, 0, WIDTH, HEIGHT); } }
実行すると白で塗りつぶされたウィンドウが生成されます。これで、描画の下準備は完了です。次に、ボールクラスを作成します。
③ボールクラスの作成
まず、ボールのメンバ変数として必要なのは、座標・半径・速度です。これがあれば、ボールの動きを描画できます。必要なメソッドは、初期値を代入するコンストラクタ、描画を行うメソッド、ボールを動かすメソッドの3つです。
円を描く際、fillOvalを使いますが、引数に注意が必要です。fillOval(円の左上のx座標、円の左上のy座標、円の横幅、円の縦幅)と指定するので、ボールの中心座標であるx,yをそのまま代入してはいけません。
import javafx.scene.canvas.GraphicsContext; import javafx.scene.paint.Color; public class Ball { //ボールの中心座標 int x; int y; //ボールの半径 int r; //ボールの速度 int vx; int vy; //コンストラクタ public Ball(int x, int y, int r, int vx, int vy){ //初期値を代入 this.x = x; this.y = y; this.r = r; this.vx = vx; this.vy = vy; } //ボールを動かすメソッド public void update(){ //座標に速度を足して動かす x += vx; y += vy; } //描画するメソッド public void draw(GraphicsContext gc){ //赤色にする gc.setFill(Color.RED); //座標を指定して円を描く gc.fillOval(x - r, y - r, r * 2, r * 2); } }
Ballクラスを作ったので、インスタンスを生成します。やることは次の4つです。
・Breakoutクラスのメンバ変数にballを宣言
・startメソッドでballをインスタンス化 (ballの初期値は座標をキャンバス中央、半径5、x速度1、y速度1)
・1フレームごとに行う処理にボールの移動を追加
・描画メソッドにballの描画を追加
※1フレームの間隔を0.1秒から0.01秒に変更しました。
import javafx.animation.KeyFrame; import javafx.animation.Timeline; import javafx.application.Application; import javafx.event.ActionEvent; import javafx.event.EventHandler; import javafx.scene.Scene; import javafx.scene.canvas.Canvas; import javafx.scene.canvas.GraphicsContext; import javafx.scene.layout.BorderPane; import javafx.stage.Stage; import javafx.util.Duration; import javafx.scene.paint.Color; public class Breakout extends Application{ public static void main(String[] args) throws Exception { launch(); } //キャンバスの幅と高さ final int WIDTH = 1000; final int HEIGHT = 800; //ボール Ball ball; @Override public void start(Stage stage) throws Exception { //ウィンドウのタイトルをセット stage.setTitle("Breakout"); //親ノードをボーダーパネルで生成 BorderPane root = new BorderPane(); //親ノードを引数としてシーンを生成 Scene scene = new Scene(root); //描画するためのキャンバスを生成 Canvas canvas = new Canvas(WIDTH, HEIGHT); //キャンバスに描画するGraphicsContextを生成 GraphicsContext gc = canvas.getGraphicsContext2D(); //キャンバスをボーダーパネルの中央に配置 root.setCenter(canvas); //シーンをステージにセット stage.setScene(scene); //ステージを表示 stage.show(); //ボールをインスタンス化 ball = new Ball(WIDTH / 2, HEIGHT / 2, 5, 1, 1); Timeline timeline = new Timeline(); KeyFrame keyframe = new KeyFrame(Duration.seconds(0), new EventHandler<ActionEvent>() { public void handle(ActionEvent e){ //ここに処理を記述 //ボールを移動 ball.update(); //描画メソッドを呼び出す draw(gc); } }); timeline.getKeyFrames().addAll(keyframe, new KeyFrame(Duration.seconds(0.01))); //1フレームの間隔 timeline.setCycleCount(Timeline.INDEFINITE); timeline.play(); } //描画メソッド public void draw(GraphicsContext gc){ //背景を白で塗りつぶす gc.setFill(Color.WHITE); gc.fillRect(0, 0, WIDTH, HEIGHT); //ボールの描画メソッドを呼び出す ball.draw(gc); } }
実行すると、画面の真ん中にボールが出現し、右下に移動していきます。しかし、ボールは反射することなく、そのまま画面外に消えて行ってしまいます。 ボールクラスのupdateメソッドを変更して、画面端に到達したら速度を反転させる必要があります。画面の大きさが分からないと画面端に到達したかどうかわからないので、updateメソッドの引数で画面の幅と高さを受け取ります。
//ボールを動かすメソッド public void update(int width, int height){ //ボールが画面端の左右に衝突していないか判定 if(x - r < 0 || x + r > width){ //速度を反転 vx = -vx; } //ボールが画面端の上下に衝突していないか判定 if(y - r < 0 || y + r > height){ //速度を反転 vy = -vy; } //座標に速度を足して動かす x += vx; y += vy; }
ボールの端はボールの中心座標から半径を(引いた、もしくは足した)値になります。updateメソッドを呼び出すときは、画面の幅と高さを渡すので、そこも軽く書き換えます。
//ここに処理を記述 //ボールを移動 ball.update(WIDTH, HEIGHT); //描画メソッドを呼び出す draw(gc);
実行すると、ちゃんと跳ね返ってくれています。これで今回の目標は達成です。
次回は、ボールを跳ね返すパドルを作ります。最後に、ソースコードを貼っておきます。
import javafx.animation.KeyFrame; import javafx.animation.Timeline; import javafx.application.Application; import javafx.event.ActionEvent; import javafx.event.EventHandler; import javafx.scene.Scene; import javafx.scene.canvas.Canvas; import javafx.scene.canvas.GraphicsContext; import javafx.scene.layout.BorderPane; import javafx.stage.Stage; import javafx.util.Duration; import javafx.scene.paint.Color; public class Breakout extends Application{ public static void main(String[] args) throws Exception { launch(); } //キャンバスの幅と高さ final int WIDTH = 1000; final int HEIGHT = 800; //ボール Ball ball; @Override public void start(Stage stage) throws Exception { //ウィンドウのタイトルをセット stage.setTitle("Breakout"); //親ノードをボーダーパネルで生成 BorderPane root = new BorderPane(); //親ノードを引数としてシーンを生成 Scene scene = new Scene(root); //描画するためのキャンバスを生成 Canvas canvas = new Canvas(WIDTH, HEIGHT); //キャンバスに描画するGraphicsContextを生成 GraphicsContext gc = canvas.getGraphicsContext2D(); //キャンバスをボーダーパネルの中央に配置 root.setCenter(canvas); //シーンをステージにセット stage.setScene(scene); //ステージを表示 stage.show(); //ボールをインスタンス化 ball = new Ball(WIDTH / 2, HEIGHT / 2, 5, 1, 1); Timeline timeline = new Timeline(); KeyFrame keyframe = new KeyFrame(Duration.seconds(0), new EventHandler<ActionEvent>() { public void handle(ActionEvent e){ //ここに処理を記述 //ボールを移動 ball.update(WIDTH, HEIGHT); //描画メソッドを呼び出す draw(gc); } }); timeline.getKeyFrames().addAll(keyframe, new KeyFrame(Duration.seconds(0.01))); //1フレームの間隔 timeline.setCycleCount(Timeline.INDEFINITE); timeline.play(); } //描画メソッド public void draw(GraphicsContext gc){ //背景を白で塗りつぶす gc.setFill(Color.WHITE); gc.fillRect(0, 0, WIDTH, HEIGHT); //ボールの描画メソッドを呼び出す ball.draw(gc); } }
import javafx.scene.canvas.GraphicsContext; import javafx.scene.paint.Color; public class Ball { //ボールの中心座標 int x; int y; //ボールの半径 int r; //ボールの速度 int vx; int vy; //コンストラクタ public Ball(int x, int y, int r, int vx, int vy){ //初期値を代入 this.x = x; this.y = y; this.r = r; this.vx = vx; this.vy = vy; } //ボールを動かすメソッド public void update(int width, int height){ //ボールが画面端の左右に衝突していないか判定 if(x - r < 0 || x + r > width){ //速度を反転 vx = -vx; } //ボールが画面端の上下に衝突していないか判定 if(y - r < 0 || y + r > height){ //速度を反転 vy = -vy; } //座標に速度を足して動かす x += vx; y += vy; } //描画するメソッド public void draw(GraphicsContext gc){ //赤色にする gc.setFill(Color.RED); //座標を指定して円を描く gc.fillOval(x - r, y - r, r * 2, r * 2); } }
プライバシーポリシー
1.当サイトに掲載されている広告について
当サイトでは、第三者配信の広告サービス(Googleアドセンス)
を利用しています。 このような広告配信事業者は、ユーザーの興味に応じた商品やサービスの広告を表示するため、当サイトや他サイトへのアクセスに関する情報 『Cookie』(氏名、住所、メール アドレス、電話番号は含まれません) を使用することがあります。 またGoogleアドセンスに関して、このプロセスの詳細やこのような情報が広告配信事業者に使用されないようにする方法については、こちらをクリックしてください。
2.当サイトが使用しているアクセス解析ツールについて
当サイトでは、Googleによるアクセス解析ツール「Googleアナリティクス」を利用しています。 このGoogleアナリティクスはトラフィックデータの収集のためにCookieを使用しています。 このトラフィックデータは匿名で収集されており、個人を特定するものではありません。
この機能はCookieを無効にすることで収集を拒否することが出来ますので、お使いのブラウザの設定をご確認ください。 この規約に関して、詳しくはこちら、またはこちらをクリックしてください。
3.当サイトへのコメントについて
当サイトでは、スパム・荒らしへの対応として、コメントの際に使用されたIPアドレスを記録しています。
これはブログの標準機能としてサポートされている機能で、スパム・荒らしへの対応以外にこのIPアドレスを使用することはありません。
また、メールアドレスとURLの入力に関しては、任意となっております。 全てのコメントは管理人であるteramaguroが事前にその内容を確認し、承認した上での掲載となりますことをあらかじめご了承下さい。
加えて、次の各号に掲げる内容を含むコメントは管理人の裁量によって承認せず、削除する事があります。
特定の自然人または法人を誹謗し、中傷するもの。
極度にわいせつな内容を含むもの。
- 禁制品の取引に関するものや、他者を害する行為の依頼など、法律によって禁止されている物品、行為の依頼や斡旋などに関するもの。
- その他、公序良俗に反し、または管理人によって承認すべきでないと認められるもの。
4.免責事項
当サイトで掲載している画像の著作権・肖像権等は各権利所有者に帰属致します。権利を侵害する目的ではございません。記事の内容や掲載画像等に問題がございましたら、各権利所有者様本人が直接メールでご連絡下さい。確認後、対応させて頂きます。
当サイトからリンクやバナーなどによって他のサイトに移動された場合、移動先サイトで提供される情報、サービス等について一切の責任を負いません。
当サイトのコンテンツ・情報につきまして、可能な限り正確な情報を掲載するよう努めておりますが、誤情報が入り込んだり、情報が古くなっていることもございます。
当サイトに掲載された内容によって生じた損害等の一切の責任を負いかねますのでご了承ください。
5.プライバシーポリシーの変更について
当サイトは、個人情報に関して適用される日本の法令を遵守するとともに、本ポリシーの内容を適宜見直しその改善に努めます。
修正された最新のプライバシーポリシーは常に本ページにて開示されます。
管理人:teramaguro