じゃんけんゲームを作ってみよう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サイズの自動調整
を組み込む予定です。

ご質問、リクエスト等がございましたら、遠慮なくメールフォームからご連絡ください。
コメントも歓迎します。

この記事へのコメントはこちら

メールアドレスは公開されませんのでご安心ください。
また、* が付いている欄は必須項目となりますので、必ずご記入をお願いします。

内容に問題なければ、下記の「コメント送信」ボタンを押してください。

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)