说是4096,其实和2048是一样的,数字并没什么意义,不过只是一个结束判定条件而已,所以如果不加结束判定条件的话,可以改成无限版。由于时间限制,三天写出了这个玩意儿,后来有空把方向按钮响应事件的算法重新优化了一下。不足之处是木有计分功能,不过如果不是无限版的话,计分功能也木有啥意义。待有时间再改为无限版加入计分功能。
先来说下实现的思路吧:游戏的底层是一个二维数组,初始值为0,每次按方向键的时候,在响应事件中改变的是底层二维数组的值,然后在面板中根据二维数组的值描绘面板。
底层的二维数组是一个类的静态成员,之所以这样写是为了能将该数组作为参数传入方法中再通过方法进行改变。
定义底层二维数组/
class pub{
public static int a[][]={{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0}};
static boolean move=false;//用于判断数组是否发生改变
}
整个游戏代码写在了两个文件中,controller类主要负责逻辑的运算,比如4个方向的响应事件以及新数字的生成。fzns类主要用于面板的绘制。游戏开始先在任意两个位置生成随机的2或者4
pub.a[new Random().nextInt(4)][new Random().nextInt(4)]=2;
pub.a[new Random().nextInt(4)][new Random().nextInt(4)]=4;
为每个数字组件匹配对应的图片
class TzfeComponent extends JComponent{
public TzfeComponent(int i){
this.setPreferredSize(new Dimension(49, 36));
try{
if(i==0)
{image=ImageIO.read(new File("src//0.jpg"));}
if(i==2)
{image=ImageIO.read(new File("src//2.png"));}
if(i==4)
{image=ImageIO.read(new File("src//4.png"));}
if(i==8)
{image=ImageIO.read(new File("src//8.png"));}
if(i==16)
{image=ImageIO.read(new File("src//16.png"));}
if(i==32)
{image=ImageIO.read(new File("src//32.png"));}
if(i==64)
{image=ImageIO.read(new File("src//64.png"));}
if(i==128)
{image=ImageIO.read(new File("src//128.png"));}
if(i==256)
{image=ImageIO.read(new File("src//256.png"));}
if(i==512)
{image=ImageIO.read(new File("src//512.png"));}
if(i==1024)
{image=ImageIO.read(new File("src//1024.png"));}
if(i==2048)
{image=ImageIO.read(new File("src//2048.png"));}
}catch(IOException e){
e.printStackTrace();
}
}
public void paintComponent(Graphics g){
if(image==null) return;
g.drawImage(image, 0, 0, null);
}
private Image image;
}
游戏的面板底层是一个JFrame框架,嵌入一个JPanel面板,再将JPanel面板的布局设置为new GridLayout(4,4),嵌入16个JComponent。每次按下方向键,更改完数组后,更新的其实就是JPanel面板。为JFrame添加方向键监听事件,监控键盘按钮的方向键。比如up键:
if(e.getKeyCode() ==KeyEvent.VK_UP){
controller.up(pub.a);
jframe.remove(tzfepanel);
jframe.add(tzfepanel=new TzfePanel(),FlowLayout.LEFT);
jframe.invalidate();
jframe.repaint();
jframe.setVisible(true);
if(controller.contains(pub.a, 4096)){
jframe.remove(tzfepanel);
jframe.add(new EndPanel(),FlowLayout.LEFT);
jframe.invalidate();
jframe.repaint();
jframe.setVisible(true);
jframe.removeKeyListener(this);
}
定义游戏结束面板,每次更改完数组都检测数组中的元素,如果检测到4096元素,就将游戏面板更改为结束面板并且移除JFrame的键盘监听功能。
class EndPanel extends JPanel{
public EndPanel(){
this.setVisible(true);
ImageIcon bg = new ImageIcon("src//end.jpg"); //游戏结束图片
JLabel label = new JLabel(bg);
label.setBounds(0,0,bg.getIconWidth(),bg.getIconHeight());
this.add(label,new Integer(Integer.MIN_VALUE));
this.setOpaque(false);
}
}
最后附上两个文件的全部代码:
fzns类:
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.GridLayout;
import java.awt.Image;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.Random;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class fzns {
public static void main(String[] args) throws InterruptedException, InvocationTargetException {
pub.a[new Random().nextInt(4)][new Random().nextInt(4)]=2;
pub.a[new Random().nextInt(4)][new Random().nextInt(4)]=4;
EventQueue.invokeAndWait(new Runnable(){
public void run(){
new TzfeFrame();
}
});
}
}
/
class TzfeFrame {
JFrame jframe;
TzfePanel tzfepanel=new TzfePanel();
public TzfeFrame(){
jframe=new JFrame();
jframe.setLayout(new FlowLayout());
jframe.setTitle("2048");
jframe.setPreferredSize(new Dimension(360, 260));
jframe.setVisible(true);
ImageIcon bg = new ImageIcon("E://1.jpg"); //背景图片
JLabel label = new JLabel(bg);
label.setBounds(0,0,bg.getIconWidth(),bg.getIconHeight());
jframe.getLayeredPane().add(label,new Integer(Integer.MIN_VALUE));
JPanel jp=(JPanel)jframe.getContentPane(); jp.setOpaque(false);
jframe.add(tzfepanel,FlowLayout.LEFT);
jframe.addKeyListener(new KeyListener(){
public void keyTyped(KeyEvent e) {
}
public void keyPressed(KeyEvent e) {
if(e.getKeyCode() ==KeyEvent.VK_UP){
controller.up(pub.a);
jframe.remove(tzfepanel);
jframe.add(tzfepanel=new TzfePanel(),FlowLayout.LEFT);
jframe.invalidate();
jframe.repaint();
jframe.setVisible(true);
if(controller.contains(pub.a, 4096)){
jframe.remove(tzfepanel);
jframe.add(new EndPanel(),FlowLayout.LEFT);
jframe.invalidate();
jframe.repaint();
jframe.setVisible(true);
jframe.removeKeyListener(this);
}
}else if(e.getKeyCode() == KeyEvent.VK_DOWN){
controller.down(pub.a);
jframe.remove(tzfepanel);
jframe.add(tzfepanel=new TzfePanel(),FlowLayout.LEFT);
jframe.invalidate();
jframe.repaint();
jframe.setVisible(true);
if(controller.contains(pub.a, 4096)){
jframe.remove(tzfepanel);
jframe.add(new EndPanel(),FlowLayout.LEFT);
jframe.invalidate();
jframe.repaint();
jframe.setVisible(true);
jframe.removeKeyListener(this);
}
}else if(e.getKeyCode() == KeyEvent.VK_LEFT){
controller.left(pub.a);
jframe.remove(tzfepanel);
jframe.add(tzfepanel=new TzfePanel(),FlowLayout.LEFT);
jframe.invalidate();
jframe.repaint();
jframe.setVisible(true);
if(controller.contains(pub.a, 4096)){
jframe.remove(tzfepanel);
jframe.add(new EndPanel(),FlowLayout.LEFT);
jframe.invalidate();
jframe.repaint();
jframe.setVisible(true);
jframe.removeKeyListener(this);
}
}else if(e.getKeyCode() == KeyEvent.VK_RIGHT){
controller.right(pub.a);
jframe.remove(tzfepanel);
jframe.add(tzfepanel=new TzfePanel(),FlowLayout.LEFT);
jframe.invalidate();
jframe.repaint();
jframe.setVisible(true);
if(controller.contains(pub.a, 4096)){
jframe.remove(tzfepanel);
jframe.add(new EndPanel(),FlowLayout.LEFT);
jframe.invalidate();
jframe.repaint();
jframe.setVisible(true);
jframe.removeKeyListener(this);
}
}
}
public void keyReleased(KeyEvent e) {
}
}
);
jframe.pack();
jframe.setResizable(false);
}
}
@SuppressWarnings("serial")
/
class TzfePanel extends JPanel{
public TzfePanel(){
setLayout(new GridLayout(4,4));
TzfeComponent tzfecomponent1=new TzfeComponent(pub.a[0][0]);
add(tzfecomponent1);
TzfeComponent tzfecomponent2=new TzfeComponent(pub.a[0][1]);
add(tzfecomponent2);
TzfeComponent tzfecomponent3=new TzfeComponent(pub.a[0][2]);
add(tzfecomponent3);
TzfeComponent tzfecomponent4=new TzfeComponent(pub.a[0][3]);
add(tzfecomponent4);
TzfeComponent tzfecomponent5=new TzfeComponent(pub.a[1][0]);
add(tzfecomponent5);
TzfeComponent tzfecomponent6=new TzfeComponent(pub.a[1][1]);
add(tzfecomponent6);
TzfeComponent tzfecomponent7=new TzfeComponent(pub.a[1][2]);
add(tzfecomponent7);
TzfeComponent tzfecomponent8=new TzfeComponent(pub.a[1][3]);
add(tzfecomponent8);
TzfeComponent tzfecomponent9=new TzfeComponent(pub.a[2][0]);
add(tzfecomponent9);
TzfeComponent tzfecomponent10=new TzfeComponent(pub.a[2][1]);
add(tzfecomponent10);
TzfeComponent tzfecomponent11=new TzfeComponent(pub.a[2][2]);
add(tzfecomponent11);
TzfeComponent tzfecomponent12=new TzfeComponent(pub.a[2][3]);
add(tzfecomponent12);
TzfeComponent tzfecomponent13=new TzfeComponent(pub.a[3][0]);
add(tzfecomponent13);
TzfeComponent tzfecomponent14=new TzfeComponent(pub.a[3][1]);
add(tzfecomponent14);
TzfeComponent tzfecomponent15=new TzfeComponent(pub.a[3][2]);
add(tzfecomponent15);
TzfeComponent tzfecomponent16=new TzfeComponent(pub.a[3][3]);
add(tzfecomponent16);
setVisible(true);
this.setVisible(true);
} }
定义每个数字组件/
@SuppressWarnings("serial")
class TzfeComponent extends JComponent{
public TzfeComponent(int i){
this.setPreferredSize(new Dimension(49, 36));
try{
if(i==0)
{image=ImageIO.read(new File("src//0.jpg"));}
if(i==2)
{image=ImageIO.read(new File("src//2.png"));}
if(i==4)
{image=ImageIO.read(new File("src//4.png"));}
if(i==8)
{image=ImageIO.read(new File("src//8.png"));}
if(i==16)
{image=ImageIO.read(new File("src//16.png"));}
if(i==32)
{image=ImageIO.read(new File("src//32.png"));}
if(i==64)
{image=ImageIO.read(new File("src//64.png"));}
if(i==128)
{image=ImageIO.read(new File("src//128.png"));}
if(i==256)
{image=ImageIO.read(new File("src//256.png"));}
if(i==512)
{image=ImageIO.read(new File("src//512.png"));}
if(i==1024)
{image=ImageIO.read(new File("src//1024.png"));}
if(i==2048)
{image=ImageIO.read(new File("src//2048.png"));}
}catch(IOException e){
e.printStackTrace();
}
}
public void paintComponent(Graphics g){
if(image==null) return;
g.drawImage(image, 0, 0, null);
}
private Image image;
}
定义游戏结束画面/
@SuppressWarnings("serial")
class EndPanel extends JPanel{
public EndPanel(){
this.setVisible(true);
ImageIcon bg = new ImageIcon("src//end.jpg"); //游戏结束图片
JLabel label = new JLabel(bg);
label.setBounds(0,0,bg.getIconWidth(),bg.getIconHeight());
this.add(label,new Integer(Integer.MIN_VALUE));
this.setOpaque(false);
}
}
定义底层二维数组/
class pub{
public static int a[][]={{2048,0,0,0},{2048,0,0,0},{0,0,0,0},{0,0,0,0}};
static boolean move=false;
}
controller类:
import java.util.Random;
public class controller {
public static void get(int a[][]){
for(int i=0;i<1000;i++){
int x=new Random().nextInt(4);
int y=new Random().nextInt(4);
if(a[x][y]!=0) continue;
if(a[x][y]==0){
if(new Random().nextInt(10)%2==0) {a[x][y]=2;break;}//随机生成方块“2”
else if(new Random().nextInt(10)%2==1){a[x][y]=4;break;}//随机生成方块“4”
}
}
}
public static void up(int a[][]){
for(int i=0;i<4;i++)
{
//后四个数判断
if(a[0][i]==0&&(a[1][i]!=0||a[2][i]!=0||a[3][i]!=0)){
while(a[0][i]==0){
a[0][i]=a[1][i];a[1][i]=a[2][i];a[2][i]=a[3][i];a[3][i]=0;
}
pub.move=true;
}
//后三个数判断
if(a[1][i]==0&&(a[2][i]!=0||a[3][i]!=0)){
while(a[1][i]==0){
a[1][i]=a[2][i];a[2][i]=a[3][i];a[3][i]=0;
}
pub.move=true;
}
//后两个数判断
if(a[2][i]==0&&a[3][i]!=0){
a[2][i]=a[3][i];a[3][i]=0;
pub.move=true;
}
//合并前两个数
if(a[0][i]==a[1][i]&&a[0][i]!=0){
a[0][i]*=2;a[1][i]=a[2][i];a[2][i]=a[3][i];a[3][i]=0;
if(a[1][i]==0&&a[2][i]!=0){
a[1][i]=a[2][i];a[2][i]=0;
}
pub.move=true;
}
//合并中间两个数
if(a[1][i]==a[2][i]&&a[1][i]!=0){
a[1][i]*=2;a[2][i]=a[3][i];a[3][i]=0;
pub.move=true;
}
//合并后面两个数
if(a[2][i]==a[3][i]&&a[2][i]!=0){
a[2][i]*=2;
a[3][i]=0;
pub.move=true;
}
}
if(pub.move==true){get(a);pub.move=false;}
}
public static void down(int a[][]){
for(int i=0;i<4;i++)
{
//前四个数判断
if((a[0][i]!=0||a[1][i]!=0||a[2][i]!=0)&&a[3][i]==0){
while(a[3][i]==0){
a[3][i]=a[2][i];a[2][i]=a[1][i];a[1][i]=a[0][i];a[0][i]=0;
}
pub.move=true;
}
//前三个数判断
if((a[0][i]!=0||a[1][i]!=0)&&a[2][i]==0){
while(a[2][i]==0){
a[2][i]=a[1][i];a[1][i]=a[0][i];a[0][i]=0;
}
pub.move=true;
}
//前两个数判断
if(a[0][i]!=0&&a[1][i]==0){
a[1][i]=a[0][i];a[0][i]=0;
pub.move=true;
}
//合并后面两个数
if(a[2][i]==a[3][i]&&a[3][i]!=0){
a[3][i]*=2;a[2][i]=a[1][i];a[1][i]=a[0][i];a[0][i]=0;
if(a[2][i]==0&&a[1][i]!=0){
a[2][i]=a[1][i];a[1][i]=0;
}
pub.move=true;
}
//合并中间两个数
if(a[1][i]==a[2][i]&&a[2][i]!=0){
a[2][i]*=2;a[1][i]=a[0][i];a[0][i]=0;
pub.move=true;
}
//合并前两个数
if(a[0][i]==a[1][i]&&a[1][i]!=0){
a[1][i]*=2;a[0][i]=0;
pub.move=true;
}
}
if(pub.move==true){get(a);pub.move=false;}
}
public static void left(int a[][]){
for(int i=0;i<4;i++)
{
//左四个数判断
if(a[i][0]==0&&(a[i][1]!=0||a[i][2]!=0||a[i][3]!=0)){
while(a[i][0]==0){
a[i][0]=a[i][1];a[i][1]=a[i][2];a[i][2]=a[i][3];a[i][3]=0;
}
pub.move=true;
}
//右三个数判断
if(a[i][1]==0&&(a[i][2]!=0||a[i][3]!=0)){
while(a[i][1]==0){
a[i][1]=a[i][2];a[i][2]=a[i][3];a[i][3]=0;
}
pub.move=true;
}
//右两个数判断
if(a[i][2]==0&&a[i][3]!=0){
a[i][2]=a[i][3];a[i][3]=0;
pub.move=true;
}
//合并左两个数
if(a[i][0]==a[i][1]&&a[i][0]!=0){
a[i][0]*=2;a[i][1]=a[i][2];a[i][2]=a[i][3];a[i][3]=0;
if(a[i][1]==0&&a[i][2]!=0){
a[i][1]=a[i][2];a[i][2]=0;
}
pub.move=true;
}
//合并中间两个数
if(a[i][1]==a[i][2]&&a[i][1]!=0){
a[i][1]*=2;a[i][2]=a[i][3];a[i][3]=0;
pub.move=true;
}
//合并后面两个数
if(a[i][2]==a[i][3]&&a[i][2]!=0){
a[i][2]*=2;
a[i][3]=0;
pub.move=true;
}
}
if(pub.move==true){get(a);pub.move=false;}
}
public static void right(int a[][]){
for(int i=0;i<4;i++)
{
//右四个数判断
if((a[i][0]!=0||a[i][1]!=0||a[i][2]!=0)&&a[i][3]==0){
while(a[i][3]==0){
a[i][3]=a[i][2];a[i][2]=a[i][1];a[i][1]=a[i][0];a[i][0]=0;
}
pub.move=true;
}
//左三个数判断
if((a[i][0]!=0||a[i][1]!=0)&&a[i][2]==0){
while(a[i][2]==0){
a[i][2]=a[i][1];a[i][1]=a[i][0];a[i][0]=0;
}
pub.move=true;
}
//左两个数判断
if(a[i][0]!=0&&a[i][1]==0){
a[i][1]=a[i][0];a[i][0]=0;
pub.move=true;
}
//合并右两个数
if(a[i][2]==a[i][3]&&a[i][3]!=0){
a[i][3]*=2;a[i][2]=a[i][1];a[i][1]=a[i][0];a[i][0]=0;
if(a[i][1]!=0&&a[i][2]==0){
a[i][2]=a[i][1];a[i][1]=0;
}
pub.move=true;
}
//合并中间两个数
if(a[i][1]==a[i][2]&&a[i][2]!=0){
a[i][2]*=2;a[i][1]=a[i][0];a[i][0]=0;
pub.move=true;
}
//合并左两个数
if(a[i][0]==a[i][1]&&a[i][1]!=0){
a[i][1]*=2;
a[i][0]=0;
pub.move=true;
}
}
if(pub.move==true){get(a);pub.move=false;}
}
public static int[][] reset(int a[][]){
for(int i=0;i<4;i++){
for(int j=0;j<4;j++){
a[i][j]=0;
}
}
return a;
}
public static boolean contains(int[][]a,int b){
for(int c[]:a){
for(int d:c){
if(d==b) {return true;}
}
}
return false;
}
}
ps一下:本demo木有像手机端那样玩的时候有过渡动画,归根到底的原因就是:我不会弄,说不定下次加功能的时候会把这个加上。。。期待。。。
最后上游戏运行的截图:(运行中)
(赢了~)
此demo是用Eclipse写的,导出的项目文件的网盘地址:
http://pan.baidu.com/s/1sjHdbPV