JAVAで小さなゲームを書くことを教える
先週の授業で、先生からJavaでアプレットを書くように言われました。私は古典的な飛行機ゲームを書きたかったのですが、ふと思い立ってこんなものを書いてみました。
I. 全体的な感想
- フォームクラスを継承し、フォームの更新をオーバーライドする
- キーストローク・リスナーを追加する
- ゲームオーバー画面
- キングスクラスとホットドッククラスの移動軌跡計算
- 衝突の判定 音楽の再生
- フォームの常時更新 処理内容
II. コーディング
1. 画像
まず、Baiduで画像を検索し、それをpsでカットし、背景画像を検索して完了です。
画像を読み込むためのツールクラスも必要です。getResourceを使って画像のURLパスを取得し、java独自のツールクラスImageIOを使って画像を読み込むことができます。
public class GameUtil {
public static Image getImage(String path){
URL url=GameUtil.class.getClassLoader().getResource(path);
BufferedImage img=null;
try {
img = ImageIO.read(url);
} catch (IOException e) {
e.printStackTrace();
}
return img;
}
}
2. フォーム
フォームを継承するクラスを作成し、フォームの幅、高さ、位置、閉じる設定、スケーラビリティを設定します。
updateメソッドとdrawメソッドをオーバーライドして、SiCとhotdogの描画と衝突判定のロジックを記述します。
ボタンリスナーを追加し、Satoshiを動かすためのボタンのクリックとリリースを処理する。
public void launchFrame(){
setSize(width,height);
setResizable(false);
setLocation(200,20);
setVisible(true);
addKeyListener(new KeyMoniter());
addWindowListener(new WindowAdapter(){
@Override
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
}
@Override
public void paint(Graphics graphics) {}
@Override
public void update(Graphics g){}
class KeyMoniter extends KeyAdapter{
@Override
public void keyPressed(KeyEvent e) {
//Key pressed
}
@Override
public void keyReleased(KeyEvent e) {
//Key lifted
}
}
3. SiCとホットドッグ
には、位置を計算し、絵を描くという、実は絶え間ない作業が必要なのです。
SiCのプロパティを定義し、コンストラクタで初期化します。
boolean left,right,down,up;
public int x,y,width,height;
Image img ;
public Plane(String img_path,int x, int y){
this.img = GameUtil.getImage(img_path);
this.x = x;
this.y = y;
width = img.getWidth(null);
height = img.getWidth(null);
live = true;
}
にSiCを描画します。
public void draw(Graphics g){
if(live){
g.drawImage(img, x, y, null);
move();
}
}
次に重要なのは、サトシの位置計算ですが、なぜサトシの描画方法に位置計算を書き込むのでしょうか。一番の理由は、メソッド計算をキーの押し引きに書いてしまうと、サトシの位置を動かそうと思ったらキーボードをめちゃくちゃ押さないといけないし、キーの長押しで移動の有無を制御しようと思ったら、サトシの描画メソッドに移動メソッドを書かないといけないからだそうです。
移動の際に考慮すべき境界線もあります
public void move(){
if(left&&x>=10){
x -= 10;
}
if(up&&y>=30){
y -= 10;
}
if(right&&x<=FeiJiGame.width-60){
x += 10;
}
if(down&&y<=FeiJiGame.height -60){
y += 10;
}
}
public void KeyPressedControlDirection(KeyEvent e){
int key_code = e.getKeyCode();
if(key_code == 37){
left = true;
}
if(key_code == 38){
up = true;
}
if(key_code == 39){
right = true;
}
if(key_code == 40){
down = true;
}
}
public void KeyRelasedControlDirection(KeyEvent e){
int key_code = e.getKeyCode();
if(key_code == 37){
left = false;
}
if(key_code == 38){
up =false;
}
if(key_code == 39){
right = false;
}
if(key_code == 40){
down = false;
}
}
最後に、SiCの生存期間を書き換えるための2つのメソッドが提供されています。
hotdogクラスは、常時動作させ、キーイベントに反応しないようにするのが簡単です。
いくつかのプロパティを定義し、コンストラクタで初期化します。
double speed=15;
double degree;
public double x,y;
public int width,height;
Image img;
public Bullet(String img_path){
img = GameUtil.getImage(img_path);
degree = Math.random()*Math.PI*2;
x=FeiJiGame.width/2;
y = FeiJiGame.height/2;
width = 10;
height = 10;
}
ランダム度の目的は、最初は異なる向きにすることで、sin関数とcos関数を使って、ホットドッグの動きを制御しつつ、境界を意識することです
public void draw(Graphics g){
g.drawImage(img, (int)x, (int)y, null);
x += speed*Math.cos(degree);
y += speed*Math.sin(degree);
if(x>FeiJiGame.width-width||x<width){
degree=Math.PI-degree;
}
if(y>FeiJiGame.height-height||y<height){
degree=-degree;
}
}
4. 衝突判定と音楽再生
javaのawtに矩形クラスがあり、2つの矩形が重なる部分があるかどうかを判断し、重なる部分があれば衝突するようになっている
Rectangle bulletRectangle = new Rectangle((int)bullet.x,(int)bullet.y,bullet.width,bullet.height);
Rectangle planeRectangle = new Rectangle(plane.x,plane.y,plane.width,plane.height);
boolean collide= bulletRectangle.intersects(planeRectangle);
音楽はサードパーティーのライブラリ、jl-1.0.1.jarを使って再生することができますが、ホットドッグを食べ続ける可能性があるので、マルチスレッドにする必要があります
class MusicPlayer implements Runnable{
@Override
public void run() {
try {
new Player(new FileInputStream(FeiJiGame.class.getClassLoader().getResource("raw/music.mp3").getPath().substring(1)))).play ();
} catch (Exception e) {
e.printStackTrace();
}
}
}
5. 仕上げ
あとはフォームを更新するだけですが、これはスレッド
class PaintThread extends Thread {
@Override
public void run() {
while(!Thread.currentThread().isInterrupted()){
repaint();
try {
Thread.sleep(40);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
}
右上に現在のゲーム時間を表示し、最後にはテキスト情報も表示する必要があり、ツールクラスを書きました
fontでフォントを制御し、graphics.setFontでフォントを設定し、drawStringで描画します。
public void printInfo(Graphics g,String message,int size,int x,int y){
g.setColor(Color.white);
Font f = new Font("宋体",Font.BOLD,size);
g.setFont(f);
g.drawString(message, x,y);
}
ゲーム終了時に情報を表示し、時間に応じてレベルを表示します。
private void gameOver(Graphics graphics) {
printInfo(graphics,"GAME OVER",80,270,300);
int survivalTime = (int)(endTime.getTime()-starTime.getTime())/1000;
printInfo(graphics,"Time to eat hot dog: "+survivalTime+"seconds",40,300,400);
switch(survivalTime/10){
case 1:
printInfo(graphics,"Doktor",50,350,500);
break;
case 2:
printInfo(graphics,"Ascend",50,350,500);
break;
case 3:
printInfo(graphics,"little success",50,350,500);
break;
default:
printInfo(graphics,"First time in the world",50,350,500);
break;
}
paintThread.interrupt();
}
フォームの初期化時にホットドッグを追加して再描画スレッドを開始するには、タイマーを起動します。
for(int i=0;i<15;i++){
Bullet bullet = new Bullet("images/hotdog.png");
bulletList.add(bullet);
}
starTime = new Date();
endTime = new Date();
paintThread = new PaintThread();
paintThread.start();
塗り分けと更新の重複
@Override
public void paint(Graphics graphics graphics) {
graphics.drawImage(bg, 0, 0, null);
plane.draw(graphics);
endTime = new Date();
if(gameState){
for(int i=0;i<bulletList.size();i++){
Bullet bullet=bulletList.get(i);
bullet.draw(graphics);
Rectangle bulletRectangle = new Rectangle((int)bullet.x,(int)bullet.y,bullet.width,bullet.height);
Rectangle planeRectangle = new Rectangle(plane.x,plane.y,plane.width,plane.height);
boolean collide= bulletRectangle.intersects(planeRectangle);
if(collide){
if (bulletList.size()! =0){
executorService.execute(musicPlayer);
bulletList.remove(i);
if (bulletList.size()==0){
gameState = false;
}
}
}
}
}else {
endTime = new Date();
gameOver(graphics);
paintThread.interrupt();
}
int count_time = (int)(endTime.getTime() - starTime.getTime())/1000;
printInfo(graphics,"You've eaten"+count_time+"seconds",20,750,50);
}
Image ImageBuffer = null;
Graphics GraImage = null;
@Override
public void update(Graphics g){
ImageBuffer = createImage(this.getWidth(), this.getHeight());
GraImage = ImageBuffer.getGraphics();
paint(GraImage);
GraImage.dispose();
g.drawImage(ImageBuffer, 0, 0, this);
}
キーリスナー内部で SiS のキープレスとリリースのメソッドを呼び出す
class KeyMoniter extends KeyAdapter{
@Override
public void keyPressed(KeyEvent e) {
plane.KeyPressedControlDirection(e);
}
@Override
public void keyReleased(KeyEvent e) {
plane.KeyRelasedControlDirection(e);
}
}
いよいよゲームスタート
public static void main(String[] args) {
FeiJiGame game = new FeiJiGame();
game.loadGame();
}
<イグ
github https://github.com/s15603333319/SiCongEatHotDog
csdn. https://download.csdn.net/download/qq_37482202/11084561
関連
-
undefined[sonar] sonar:デフォルトのスキャンルール
-
Solve モジュールのビルドに失敗しました。Error: ENOENT: no such file or directory エラー
-
CertificateException: XXXに一致するサブジェクトの代替DNS名が見つかりません 解決策
-
X11 DISPLAY変数が設定されていない」問題の解決方法
-
Junitのユニットテストエラー
-
eclipse 実行 Java、エラー: 選択を起動できず、レシーバーもありません。
-
Spring Bootは、Tomcatの組み込みのmaxPostSizeの値を設定します。
-
Prologでは、コンテンツは許可されていません。
-
Intellij IDEAの実行でCommand lineが長すぎるという報告がある 解決方法
-
日付 EEE MMM dd HH:mm:ss Z yyyy "の元の書式を指定された書式に変換するJava。
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
Eclipse の問題 アクセス制限。タイプ 'jfxrt' はAPI解決されていません。
-
Javaクラスが "Error occurred during initialization of boot layer "というエラーで実行される。
-
List list = new ArrayList(); Error: ArrayList は型に解決できません。
-
Java基礎 - マッピングとQ/A
-
Java学習5_Java NIOでjava.nio.charset.MalformedInputExceptionが報告されています。入力の長さ = 1 の例外
-
静的でない内部クラスをインスタンス化するには、デフォルトの無引数コンストラクタを使用する必要があります。
-
svn: 既にロックされているディレクトリをロックしようとした例外の解決法
-
コレクション - LinkedListソースコード解析
-
Neo4jにアクセスする spring-data-neo4j 入門編 (I)
-
docker 内から 127.0.0.1 経由でホストにアクセスするとエラーが発生します。接続が拒否されました