ゲーム実装で身に付くプログラミング 11

タイトル画面をクリックして遷移する

タイトル画面をクリックして遷移する

「MainLoop.kt」ファイルを新規作成します。これまでの連載を見ていただけているならお分かりでしょうが、このColorゲームはクリックだけで操作します。

次のビルドコマンドを実行し「color.jar」を起動すると、タイトル画面が表示されます。タイトル画面をクリックするとJPanelクラスの画面が遷移します。画面はタイトル画面、メインループ画面、ゲームオーバー画面、ステージクリア画面の4つがあります。

・ビルドコマンド

$ kotlinc main.kt Title.kt MainLoop.kt -include-runtime -d color.jar

・サンプルコード「Title.kt」ファイル

import java.awt.Graphics
import java.awt.Graphics2D
import java.awt.event.MouseAdapter
import java.awt.event.MouseEvent
import java.awt.image.BufferedImage
import java.io.File
import java.io.IOException
import javax.imageio.ImageIO
import javax.swing.JFrame
import javax.swing.JPanel

class Title(private val frame: JFrame) : JPanel() {
  private var image: BufferedImage? = null

  init {
    try {
      image = ImageIO.read(File("./images/Title.png"))
    } catch (e: IOException) {
      e.printStackTrace()
    }
    addMouseListener(object : MouseAdapter() {
      override fun mousePressed(e: MouseEvent) {
        frame.contentPane.removeAll()   // 画面を消す
        frame.add(MainLoop(frame))      // メインループ画面追加
        frame.revalidate()              // 更新
        frame.repaint()                 // 再描画
      }
    })
  }

  override fun paintComponent(g: Graphics) {
(中略)
  }
}

【サンプルコードの解説】
「addMouseListener」メソッドでマウスがクリックされたらトリガーし、「JFrame」から画面を消してMainLoopクラスを追加し、更新して真っ白に再描画します。

・サンプルコード「MainLoop.kt」ファイル

import javax.swing.JFrame
import javax.swing.JPanel

class MainLoop(private val frame: JFrame) : JPanel() {
  init {
    // 初期化処理
  }
}

【サンプルコードの解説】
「JPanel」で空のメインループ画面(メインのゲーム画面)を作成します。

色ブロックを表示する

次のビルドコマンドを実行しcolor.jarを起動すると、ゲームらしく色ブロックが表示されます(図3)。「ColorBlock.kt」ファイルを新規作成し、色ブロック1個ずつの設計図を「ColorBlock」クラスとして記述します。

ステージ(面)の数値はゲームウィンドウのタイトル文字をそのまま数値にしたものです。1面(ステージ)ではタイトルが"2"になります。手抜きですが、解説を簡単にするためです。

・ビルドコマンド

$ kotlinc main.kt Title.kt MainLoop.kt ColorBlock.kt -include-runtime -d color.jar
図3:色ブロックの表示

・サンプルコード「ColorBlock.kt」ファイル

import java.awt.image.BufferedImage
import java.io.File
import java.io.IOException
import java.util.Random
import javax.imageio.ImageIO
import java.awt.event.MouseEvent

class ColorBlock(val color: Int) {
  var image: BufferedImage? = null
  val pos = IntArray(2)
  val delta = IntArray(2)

  init {
    val rand = Random()
    try {
      image = ImageIO.read(File("./images/$color.png"))
    } catch (e: IOException) {
      e.printStackTrace()
    }
    repeat(3 * 2) {
      pos[0] = rand.nextInt(1800 - 50)
      pos[1] = rand.nextInt(900 - 50)
      delta[0] = rand.nextInt(7) - 3
      delta[1] = rand.nextInt(7) - 3
    }
  }

  fun update(w: Int, h: Int): Int {
    pos[0] += delta[0]
    pos[1] += delta[1]
    return if (pos[0] < -100 || pos[0] > w || pos[1] < -100 || pos[1] > h) {
      0
    } else {
      1
    }
  }
}

【サンプルコードの解説】
「color」引数には色ブロックの「0(赤)」「1(緑)」「2(青)」が入ります。
色ブロックの(pos[0],pos[1])は(X,Y)座標で、(delta[0],delta[1])は(増分X,増分Y)座標です。それぞれ初期値にはランダムな値を入れます。
「update」メソッドで(X,Y)座標に増分を加算して、色ブロックが画面外に出たら戻り値に0を返し、画面内なら戻り値に1を返します。

・サンプルコード「MainLoop.kt」ファイル

import java.awt.Graphics
import java.awt.Graphics2D
import javax.swing.JFrame
import javax.swing.JPanel
import javax.swing.Timer

class MainLoop(private val frame: JFrame) : JPanel() {
  private val colors = ArrayList<ColorBlock>()
  private val timer: Timer

  init {
    val stage = frame.title.toInt()
    repeat(3 * stage) {
      colors.add(ColorBlock(it % 3))
    }
    timer = Timer(100) {
      // 毎フレームの処理(更新・再描画)
      frame.repaint()
    }
    timer.start()
  }

  override fun paintComponent(g: Graphics) {
    super.paintComponent(g)
    val g2d = g as Graphics2D
    for (c in colors) {
      c.update(width, height)
      c.image?.let { img ->
        g2d.drawImage(img, c.pos[0], c.pos[1], this)
      }
    }
  }
}

【サンプルコードの解説】
「ArrayList」でColorBlockクラスの配列「colors」プロパティを作成し、ステージ番号×3色分だけ追加します。
Timerクラスで100ミリ秒ごと(10FPS)に再描画するよう設定し、「start」で開始します。
ColorBlockクラスのインスタンスをupdateし、「drawImage」メソッドで描画します。

色ブロックをクリックして消す

今度は、色ブロックをクリックしたらそのブロックを消すだけにします。クリックした時のマウス座標と色ブロックの位置との差の絶対値が50より小さければクリック成功です。

・サンプルコード「ColorBlock.kt」ファイル

(前略)
public class ColorBlock {
(中略)

  public ColorBlock(int color) {
(中略)
  }

  public int update(int w,int h) {
(中略)
  }

  fun click(e: MouseEvent): Boolean {
    return (kotlin.math.abs(pos[0] + 50 - e.x) < 50 && kotlin.math.abs(pos[1] + 50 - e.y) < 50)
  }
}

【サンプルコードの解説】
clickメソッドで「-50<(X,Y)座標<50」にマウスクリックがあればクリックが当たったとtrueを戻り値で返します。クリックされてなければfalseを返します。

・サンプルコード「MainLoop.kt」ファイル

import javax.swing.JPanel;
import javax.swing.JFrame;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import javax.swing.Timer;

public class MainLoop extends JPanel {
(中略)

  public MainLoop(JFrame frame) {
(中略)
    addMouseListener(object : MouseAdapter() {
      override fun mousePressed(e: MouseEvent) {
        for (i in colors.indices) {
          if (colors[i].click(e)) {
            colors.removeAt(i)
            break
          }
        }
      }
    })
  }

  @Override
  protected void paintComponent(Graphics g) {
(中略)
  }
}

【サンプルコードの解説】
メインループでイベントリスナーによりマウスがクリックされたらトリガーし、色ブロックをクリックしていたらそのブロックを「remove(取り除く)」します。

【コラム】大阪大学コンピュータクラブ

1998年、大学5回生になってから(苦笑)大阪大学コンピュータクラブに入りました。僕が作ったゲームを部室のパソコンで見せたら驚かれました。何しろみんなと違って、授業にも出ずにプログラミングしていたので当然ですね(苦笑)。

人気記事トップ10

人気記事ランキングをもっと見る

企画広告も役立つ情報バッチリ! Sponsored