简易版2048 (KeyListener需重写所有函数&&JFrame和JLabel设置颜色)

转载请标明出处:http://blog.csdn.net/idealism_xxm/article/details/50284487,本文出自: 【idealism_xxm的博客】

 

根据必要功能按照自己的想法写了一下,可能实现得比较麻烦,但是感觉还不错,暂时没发现其他bug

 

 

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.event.KeyListener;

/*
 * 未设置不同数字的大小
 * 未设置实时显示分数
 * ……总之就是最简易的版本
 */

public class Game extends JFrame {
	private final int LEN=100,MAXN=4;//LEN是一个方块的边长,MAXN是方阵的阶数
	private JLabel[][] jlb=new JLabel[MAXN][MAXN];
	private int num[][]=new int[MAXN][MAXN];
	private int filled,score;
	
	public Game() {
		getContentPane().setBackground(new Color(187,173,160));//【注意】JFrame应该这样改变颜色
		setLayout(new GridLayout(MAXN,MAXN,10,10));
		for(int i=0;i<MAXN;++i) {
			for(int j=0;j<MAXN;++j) {
				num[i][j]=0;
				add(jlb[i][j]=new JLabel());
				jlb[i][j].setBackground(getBkgColor(0));
				jlb[i][j].setForeground(getFrgColor(0));
				jlb[i][j].setOpaque(true);//【注意】JLabel默认情况下是透明,所以只能先将其设成不透明才能显示颜色
				jlb[i][j].setText(null);
				jlb[i][j].setHorizontalAlignment(JLabel.CENTER);//居中显示
			}
		}
		
		addKeyListener(new KeyListener() {
			@Override
			public void keyPressed(KeyEvent e) {
				switch(e.getKeyCode()) {
				
				case KeyEvent.VK_LEFT: {
					if(moveLeft()) {
						next();
						display();
						if(!canMove()) {
							JOptionPane.showMessageDialog(null,"Score:"+score, "Game Over", JOptionPane.PLAIN_MESSAGE, null); 
							reset();
						}
					}
					return;
				}
				case KeyEvent.VK_UP: {
					turnClockwise(3);
					if(moveLeft()) {
						turnClockwise(1);
						next();
						display();
						if(!canMove()) {
							JOptionPane.showMessageDialog(null,"Score:"+score, "Game Over", JOptionPane.PLAIN_MESSAGE, null);
							reset();
						}
					}
					else {
						turnClockwise(1);
					}
					return;
				}
				case KeyEvent.VK_RIGHT: {
					turnClockwise(2);
					if(moveLeft()) {
						turnClockwise(2);
						next();
						display();
						if(!canMove()) {
							JOptionPane.showMessageDialog(null,"Score:"+score, "Game Over", JOptionPane.PLAIN_MESSAGE, null);
							reset();
						}
					}
					else {
						turnClockwise(2);
					}
					return;
				}
				case KeyEvent.VK_DOWN: {
					turnClockwise(1);
					if(moveLeft()) {
						turnClockwise(3);
						next();
						display();
						if(!canMove()) {
							JOptionPane.showMessageDialog(null,"Score:"+score, "Game Over", JOptionPane.PLAIN_MESSAGE, null);
							reset();
						}
					}
					else {
						turnClockwise(3);
					}
					return;
				}
				
				}
			}
			
			@Override
			public void keyReleased(KeyEvent e) {
				
			}
			
			@Override
			public void keyTyped(KeyEvent e) {
				
			}
		});
		reset();
		setTitle(""+2048);
		setSize(LEN*MAXN+10,LEN*MAXN+10);
		setLocationRelativeTo(null);
		setResizable(false);
		setVisible(true);
	}
	
	private void reset() {
		score=filled=0;
		for(int r=0;r<MAXN;++r)
			for(int c=0;c<MAXN;++c)
				num[r][c]=0;
		next();
		next();
		display();
	}
	
	private boolean canMove() {//判断能否继续移动
		if(filled!=MAXN*MAXN)
			return true;
		int ori[][]=new int[4][4],tmp=filled,temp=score;
		myCopy(num,ori);
		if(!moveLeft()) {//无法向左移动
			myCopy(ori,num);
			turnClockwise(3);
			if(!moveLeft()) {//无法向上移动
				myCopy(ori,num);
				turnClockwise(2);
				if(!moveLeft()) {//无法向右移动
					myCopy(ori,num);
					turnClockwise(1);
					if(!moveLeft()) {//无法向下移动
						myCopy(ori,num);
						return false;
					}
				}
			}
		}
		filled=tmp;
		score=temp;
		myCopy(ori,num);
		return true;
	}
	
	private void display() {//将数字与JLabel对应
		for(int i=0;i<MAXN;++i)
			for(int j=0;j<MAXN;++j) {
				jlb[i][j].setText(Integer.toString(num[i][j]));
				jlb[i][j].setBackground(getBkgColor(num[i][j]));
				jlb[i][j].setForeground(getFrgColor(num[i][j]));
			}
	}
	
	private boolean moveLeft() {//按下左箭头时,内部矩阵的计算
		boolean moved=false;
		for(int r=0;r<MAXN;++r)
			if(moveRow(r))
				moved=true;
		return moved;
	}
	
	private boolean moveRow(int r) {//按下左箭头时,内部矩阵第r行的计算
		boolean moved=fillUp(r);
		for(int c=1;c<MAXN;++c) {//合并
			if(num[r][c]==num[r][c-1]&&num[r][c]!=0) {
				--filled;
				moved=true;
				num[r][c-1]<<=1;
				num[r][c]=0;
				score+=num[r][c-1];
			}
		}
		return fillUp(r)||moved;
	}
	
	private boolean fillUp(int r) {//当前行向左移动
		int c=0,t;
		boolean moved=false;
		while(c<MAXN&&num[r][c]!=0)//找到第一个空位
			++c;
		t=c;
		for(;t<MAXN;++t) {//补齐空位
			if(num[r][t]!=0) {
				moved=true;
				num[r][c++]=num[r][t];
			}
		}
		for(;c<MAXN;++c)
			if(num[r][c]!=0) {//若c~MAXN-1存在非0方块,则必定产生移动
				moved=true;
				num[r][c]=0;
			}
		return moved;
	}
	
	private void next() {//填入一个方块2或4
		++filled;
		int r=((int)(Math.random()*MAXN))%MAXN,c=((int)(Math.random()*MAXN))%MAXN,n=((int)(Math.random()*2))%2;
		while(num[r][c]!=0) {
			r=((int)(Math.random()*MAXN))%MAXN;
			c=((int)(Math.random()*MAXN))%MAXN;
		}
		num[r][c]=2<<n;
	}
	
	private void turnClockwise(int times) {//将矩阵顺时针旋转times*90°
		times%=4;
		while((times--)>0) {
			int tmp[][]=new int[MAXN][MAXN],r,c,t;
			myCopy(num,tmp);
			for(r=0;r<MAXN;++r)//顺时针旋转90°
				for(c=0,t=MAXN-1;c<MAXN;++c,--t)
						num[r][c]=tmp[t][r];
		}
	}
	
	private void myCopy(int[][] src,int[][] dest) {
		for(int r=0;r<MAXN;++r)
			for(int c=0;c<MAXN;++c)
				dest[r][c]=src[r][c];
	}
	
	private Color getBkgColor(int num) {
		switch(num) {
		case 0:
			return new Color(205,193,180);
		case 2:
			return new Color(238,228,218);
		case 4:
			return new Color(224,237,200);
		case 8:
			return new Color(242,117,121);
		case 16:
			return new Color(249,149,99);
		case 32:
			return new Color(246,124,95);
		case 64:
			return new Color(246,94,59);
		case 128:
			return new Color(237,217,114);
		case 256:
			return new Color(237,204,97);
		case 512:  
			return new Color(236,176,77);   
		case 1024:  
			return new Color(236,148,55);
		case 2048:  
			return new Color(236,120,33);

		}
		return new Color(236,120,33);
	}
	
	private Color getFrgColor(int num) {
		switch(num) {
		case 0:
			return new Color(205,193,180);
		case 2:
		case 4:
			return new Color(119,110,101);
		case 8:
		case 16:
		case 32:
		case 64:
		case 128:
		case 256:
			return new Color(249,246,242);
		}
		return new Color(0,0,0);
	}
	
	public static void main(String[] argv) {
		new Game();
	}
}


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值