じゃんけんゲームを作ってみよう7
ボタンなどに登録するActionListenerは、ボタン等が押された時に
呼ばれます。(当然といえば当然なのですね。)
毎度、管理人イガジーです。
Listener がいつ呼びだされるか、は操作する人次第なので、
押されたら「今どういう状態なのか?」を把握した上で
処理を分けなければならない事がよくあります。
そのために、フィールド変数(例えば int stat)に、状態を示す値
(例えば、開始待ち=0、実行中=1 など)をセットしておき
それによって処理を分けるようにします。
今回のじゃんけんゲームでは、ゲーム開始前、あるいは
じゃんけんの勝敗判定直後には stat=0;(IDLE) にして、
MouseListener でクリック待ちにして、
クリックされたら stat=1;(PLAYING) にして、MouseListener では
何もしない(=待たない)ようにしてみます。
MouseListenerは、Canvas (MyCanvas)に登録して、描画した
ボタンの位置がクリックされたら待ちから抜けるようにします。
class MyCanvas extends Canvas{
private static final long serialVersionUID = 1L;
MyCanvas(){
this.addMouseListener(new ClickWait());
}
@Override
public void paint(Graphics g0){
g0.drawImage(bb, 0, 0, f);
}
}
class ClickWait extends MouseAdapter {
@Override
public void mouseClicked(MouseEvent e) {
int px=e.getX();
int py=e.getY();
if (stat==IDLE){
if ((px>133)&&(px<332)&&(py>307)&&(py<342)) {
stat=PLAYING;
btnctrl(true);
cls();
dispmsg(MSGJANKEN, 20,130);
cv.repaint();
}
}
}
}
ここで
if ((px>133)&&(px<332)&&(py>307)&&(py<342))
は、描画したボタンのおおまかな位置チェックです。
また、btnctrl(false)は
void btnctrl(boolean enable){
for (int i=0;i<3;++i){
bj[i].setEnabled(enable);
}
}
で、MouseListenerで待っている間はボタンを無効にします。
MouseListenerで、抜ける時(stat=PLAYINGにする時)には、btnctrl(true);で
ボタンを有効にします。
全体のプログラムは次のような感じになります。
import java.awt.BorderLayout;
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.Random;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class Janken4 {
final int CVWIDTH=360, CVHEIGHT=360;
final int ICONSZ=60;
final int MSGJANKEN=0, MSGDRAW=1, MSGYOUWIN=2,MSGPCWIN=3,MSGYOU=7,MSGPC=8;
final int GBTNSTART=4, GBTNAGAIN=5;
final int IDLE=0,PLAYING=1;
int stat=IDLE;
int pck=0;
int ywin,pwin,draw;
Random rnd=new Random();
JFrame f=new JFrame("じゃんけん");
MyCanvas cv=new MyCanvas();
JLabel resl=new JLabel(" ");
BufferedImage bb=new BufferedImage(CVWIDTH, CVHEIGHT,BufferedImage.TYPE_INT_RGB);
Graphics g,g2;
JButton []bj=new JButton [4];
BufferedImage []bi = new BufferedImage[3];
Image imc=null;
Janken4(){
String picname="janken.png";
try {
imc=ImageIO.read(new File(picname));
} catch (IOException e) {
System.out.println(picname + " read error!");
System.exit(1);
}
ywin=pwin=draw=0;
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
resl.setFont(new Font(Font.MONOSPACED,Font.PLAIN,14));
JPanel bp=new JPanel();
g=bb.getGraphics();
cls();
f.add(resl,BorderLayout.NORTH);
f.add(cv,BorderLayout.CENTER);
f.add(bp,BorderLayout.SOUTH);
g.setColor(Color.BLACK);
dispmsg(MSGJANKEN,50,60);
g.drawImage(imc, 10, 140, 310, 240, 0, 0, 300, 100, f);
dispmsg(GBTNSTART,130,300);
for (int i=0;i<3;++i) {
bi[i]=new BufferedImage(ICONSZ,ICONSZ,BufferedImage.TYPE_INT_ARGB);
g2=bi[i].getGraphics();
g2.drawImage(imc, 0, 0, ICONSZ, ICONSZ, 100*i, 0, 100*i+100, 100, f);
g2.dispose();
bj[i]=new JButton(new ImageIcon(bi[i]));
bj[i].addActionListener(new Pon(i));
bp.add(bj[i]);
}
stat=IDLE;
btnctrl(false);
f.setSize(CVWIDTH+4,CVHEIGHT+ICONSZ+100);
f.setVisible(true);
}// constructor
public static void main(String[] args) {
new Janken4();
}
void cls(){
g.setColor(Color.WHITE);
g.fillRect(0, 0, CVWIDTH, CVHEIGHT);
}
void dispmsg(int msgn, int x, int y){
int gy=msgn*50+100;
int gx=12;
int gw=260,gh=50;
switch (msgn) {
//case 4: // 始めるボタン
case GBTNSTART:
gw=120;break;
// case 5: // もう一度ボタン
case GBTNAGAIN:
gw=220; break;
// case 7: // あなた
case MSGYOU:
gy=200; gw=100;
break;
// case 8: // PC
case MSGPC:
gy=250; gw=70;
break;
case 10: // グー // 10
gx=gy=0; gw=gh=100;
break;
case 11: // チョキ
gx=100;gy=0; gw=gh=100;
break;
case 12: // パー
gx=200; gy=0; gw=gh=100;
break;
}
g.drawImage(imc, x, y, x+gw, y+gh, gx, gy, gx+gw, gy+gh, f);
}
void btnctrl(boolean enable){
for (int i=0;i<3;++i){
bj[i].setEnabled(enable);
}
}
class Pon implements ActionListener {
final int DRAWDRAW=0, PC_WIN=1, YOU_WIN=2;
int yk; // 0=グー, 1=チョキ, 2=パー
Pon(int kk) {
yk=kk;
}// constructor
@Override
public void actionPerformed(ActionEvent arg0) {
if (stat==PLAYING) {
pck=rnd.nextInt(3);
cls();
dispmsg(MSGPC,0,0); //PC
dispmsg(10+pck,80,20); // PCの手
dispmsg(MSGYOU,0,160); // あなた
dispmsg(10+yk,100,180); // 人の手
// 勝敗判定
int winlose=DRAWDRAW; // assume draw
if (pck!=yk) {
if ((yk==(pck+1))||(yk==(pck-2))) winlose=PC_WIN;
else winlose=YOU_WIN;
} // end else
int msgnn=MSGDRAW;
switch (winlose){
case YOU_WIN:
++ywin;
msgnn=MSGYOUWIN;
break;
case PC_WIN:
++pwin;
msgnn=MSGPCWIN;
break;
// case DRAWDRAW:
default:
++draw;
break;
}
dispmsg(msgnn,80,130);
dispmsg(GBTNAGAIN,130,300);
int round=ywin+pwin+draw;
resl.setText(String.format("%d戦 あなたの %d勝 %d敗 %d分け",
round,ywin,pwin,draw));
cv.repaint();
stat=IDLE;
btnctrl(false);
}// end if playing
}// actionPerformed
}// class Pon
class MyCanvas extends Canvas{
private static final long serialVersionUID = 1L;
MyCanvas(){
this.addMouseListener(new ClickWait());
}
@Override
public void paint(Graphics g0){
g0.drawImage(bb, 0, 0, f);
}
}
class ClickWait extends MouseAdapter {
@Override
public void mouseClicked(MouseEvent e) {
int px=e.getX();
int py=e.getY();
if (stat==IDLE){
if ((px>133)&&(px<332)&&(py>307)&&(py<342)) {
stat=PLAYING;
btnctrl(true);
cls();
dispmsg(MSGJANKEN, 20,130);
cv.repaint();
}
}
}
}
}
これで概ね完成ですが、次回は少々ブラッシュアップをします。
具体的には、
・勝敗の%表示,
・画像(janken.png)をjar化の際に取り込める様にURL化,
・JFrameサイズの自動調整
を組み込む予定です。
ご質問、リクエスト等がございましたら、遠慮なくメールフォームからご連絡ください。
コメントも歓迎します。
この記事へのコメントはこちら