简介
初学了点Java语法,尝试着做了第一个项目----2048小游戏。耗时大概三天左右。一共638行代码。开发工具是IDEA。程序几秒钟就可以跑出来了,换了一台电脑就是不一样,还得是华硕adol办公性价比首选!!
主类
public class Main { public static void main(String[] args) { GameFrame frame = new GameFrame(); GamePanel panel = new GamePanel(frame); frame.add(panel); frame.setVisible(true); } }
GameFrame类
import javax.swing.*; import java.awt.*; public class GameFrame extends JFrame{ public GameFrame(){ setTitle("2048");//设置标题 setSize(370,420);//设置大小 getContentPane().setBackground(new Color(153, 156, 206));//设置背景颜色 setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//关闭进程后退出 setLocationRelativeTo(null);//设置居中 setResizable(false);//设置不可以动态改变窗体 } }
GamePanel类
import javax.swing.*; import javax.swing.plaf.FontUIResource; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.util.Random; public class GamePanel extends JPanel implements ActionListener {//画布 private static final int ROWS = 4; private static final int COLS = 4; private JFrame frame = null; private GamePanel panel = null; private Card[][] cards = new Card[ROWS][COLS]; private String gameFlag="start"; public GamePanel(JFrame frame){ this.setLayout(null);//设置布局 this.setOpaque(false);//设置透明 this.frame=frame; this.panel=this;//this是new出来的实例对象 createMenu();//创建菜单 //创建卡片 initCard(); //随机创建一个卡片 createRandomNum(); //创建键盘监听 createKeyListener(); } //创建键盘监听 private void createKeyListener() { KeyAdapter keyAdapter = new KeyAdapter() { @Override public void keyPressed(KeyEvent e) { if(!"start".equals(gameFlag)){ return ; } int key =e.getKeyCode(); switch (key){ //向上 case KeyEvent.VK_UP: case KeyEvent.VK_W: moveCard(1); break; //向右 case KeyEvent.VK_RIGHT: case KeyEvent.VK_D: moveCard(2); break; //向下 case KeyEvent.VK_DOWN: case KeyEvent.VK_S: moveCard(3); break; //向左 case KeyEvent.VK_LEFT: case KeyEvent.VK_A: moveCard(4); break; } } }; frame.addKeyListener(keyAdapter); } //按方向移动卡片 private void moveCard(int dir) { //清理卡片的合并标记 clearCard(); if(dir==1){ moveCardTop(true); }else if(dir==2){ moveCardRight(true); }else if(dir==3){ moveCardBottom(true); }else if(dir==4){ moveCardLeft(true); } //每一次移动后新创建卡片 createRandomNum(); //重绘画布 repaint(); //判断游戏是否结束 gameOverOrNot(); } //判断游戏是否结束 private void gameOverOrNot() { /*结束条件 * 1.位置已满 * 2.4个方向都没有可以合并的卡片*/ if(isWin()){ gameWin(); }else if(!cardIsFull()){ if(moveCardTop(false)|| moveCardRight(false)|| moveCardBottom(false)|| moveCardLeft(false)){//只要有一个方向可以移动或者合并,就表示没结束 return; } }else{ gameOver(); } } private void gameOver() { gameFlag="end"; //弹出结束提示 UIManager.put("OptionPane.buttonFont", new FontUIResource(new Font("思源宋体",Font.ITALIC,18))); UIManager.put("OptionPane.messageFont", new FontUIResource(new Font("思源宋体",Font.ITALIC,18))); JOptionPane.showMessageDialog(frame,"失败了!再接再厉!"); } private void gameWin() { gameFlag="end"; //弹出结束提示 UIManager.put("OptionPane.buttonFont", new FontUIResource(new Font("思源宋体",Font.ITALIC,18))); UIManager.put("OptionPane.messageFont", new FontUIResource(new Font("思源宋体",Font.ITALIC,18))); JOptionPane.showMessageDialog(frame,"你成功啦!太棒啦!"); } //是否获得了胜利 private boolean isWin() { Card card; for(int i=0;i<ROWS;i++) { for (int j = 0; j < COLS; j++) { card = cards[i][j]; if(card.getNum()==2048){ return true; } } } return false; } //清理卡片的合并标记 private void clearCard() { Card card; for(int i=0;i<ROWS;i++) { for (int j = 0; j < COLS; j++) { card = cards[i][j]; card.setMerge(false); } } } private boolean moveCardTop(boolean b) { Card card; boolean res=false; for(int i=1;i<ROWS;i++){ for(int j=0;j<COLS;j++){ card=cards[i][j]; if(card.getNum()!=0){//只要不是空白卡片就要移动 if(card.moveTop(cards,b)){ res=true; } } } } return res; } private boolean moveCardRight(boolean b) { Card card; boolean res=false; for(int i=0;i<ROWS;i++){ for(int j=COLS-2;j>=0;j--){ card=cards[i][j]; if(card.getNum()!=0){//只要不是空白卡片就要移动 if(card.moveRight(cards,b)){ res=true; } } } } return res; } private boolean moveCardBottom(boolean b) { Card card; boolean res=false; for(int i=ROWS-2;i>=0;i--){ for(int j=0;j<COLS;j++){ card=cards[i][j]; if(card.getNum()!=0){//只要不是空白卡片就要移动 if(card.moveBottom(cards,b)){ res=true; } } } } return res; } private boolean moveCardLeft(boolean b) { Card card; boolean res=false; for(int i=0;i<ROWS;i++) { for (int j = 1; j <COLS; j++) { card = cards[i][j]; if (card.getNum() != 0) {//只要不是空白卡片就要移动 if(card.moveLeft(cards,b)){ res=true; } } } } return res; } private void initCard() { Card card; for(int i=0;i<ROWS;i++){ for(int j=0;j<COLS;j++){ card=new Card(i,j);//创建实例对象 cards[i][j]=card;//用二维数组存储 } } } @Override//重写 public void paint(Graphics g){//画笔和绘制方法 super.paint(g); //绘制卡片 drawCard(g); } private void createRandomNum() { //随机显示数字是2或4 int num=0; Random random = new Random(); int n=random.nextInt(5)+1;//随机取出1-5 if(n==1){ num=4; } else num=2; //如果各自满了,则不需要再取 if(cardIsFull()){ return ; } //取到卡片 Card card=getRandomCard(random); //设置卡片数字 if(card!=null){ card.setNum(num); } } //判断卡片是否已满 private boolean cardIsFull() { Card card; for (int i = 0; i < ROWS; i++) { for (int j = 0; j < COLS; j++) { card = cards[i][j]; if (card.getNum() == 0) { return false; } } } return true; } //创建随机卡片的方法 private Card getRandomCard(Random random) { int i = random.nextInt(ROWS); int j = random.nextInt(COLS); Card card=cards[i][j]; if(card.getNum()==0){//如果是空白的卡片,直接返回 return card; } //没找到,则递归继续找 else{ return getRandomCard(random); } } private void drawCard(Graphics g) { Card card; for(int i=0;i<ROWS;i++){ for(int j=0;j<COLS;j++){ card=cards[i][j]; card.draw(g); } } } //创建字体方法 private Font createFont(){ return new Font("思源宋体",Font.BOLD,18); } //创建菜单 private void createMenu() { //创建字体 Font tFont=createFont(); //创建JMenuBar JMenuBar jmb =new JMenuBar(); JMenu jMenu1 = new JMenu("游戏"); jMenu1.setFont(tFont); JMenu jMenu2 = new JMenu("帮助"); jMenu2.setFont(tFont); //创建子项 JMenuItem jmi1 = new JMenuItem("新游戏"); jmi1.setFont(tFont); JMenuItem jmi2 = new JMenuItem("退出"); jmi2.setFont(tFont); JMenuItem jmi3 = new JMenuItem("操作帮助"); jmi3.setFont(tFont); JMenuItem jmi4 = new JMenuItem("胜利条件"); jmi4.setFont(tFont); jmb.add(jMenu1); jmb.add(jMenu2); //添加子项 jMenu1.add(jmi1); jMenu1.add(jmi2); jMenu2.add(jmi3); jMenu2.add(jmi4); frame.setJMenuBar(jmb); //为每个子项添加事件监听 jmi1.addActionListener(this); jmi2.addActionListener(this); jmi3.addActionListener(this); jmi4.addActionListener(this); //设置指令 jmi1.setActionCommand("restart"); jmi2.setActionCommand("exit"); jmi3.setActionCommand("help"); jmi4.setActionCommand("win"); } @Override public void actionPerformed(ActionEvent e) { String command = e.getActionCommand(); if("restart".equals(command)){ System.out.println("新游戏"); restart(); } else if("exit".equals(command)){ System.out.println("退出"); Object[] options = {"确定","取消"}; int res=JOptionPane.showOptionDialog(this,"你确定退出游戏吗?", "",JOptionPane.YES_OPTION,JOptionPane.QUESTION_MESSAGE, null, options,options[0]); if(res==0){//确认退出 System.exit(0); } } else if("help".equals(command)){ System.out.println("帮助"); JOptionPane.showMessageDialog(null,"通过键盘的移动来实现上下。", "提示!",JOptionPane.INFORMATION_MESSAGE); } else if("win".equals(command)){ System.out.println("胜利条件"); JOptionPane.showMessageDialog(null,"得到数字2024即可胜利!", "提示!", JOptionPane.INFORMATION_MESSAGE); } } //新游戏 private void restart() { } }
Card类
import java.awt.*; public class Card { private int x=0;//x坐标 private int y=0;//y坐标 private int w=80;//宽 private int h=80;//高 private int i=0;//下标i private int j=0;//下标j private int start = 10; //偏移量 private int num=0;//数字 private boolean merge = false; //是否合并,如果合并则不能再合并 public Card(int i,int j){ this.i=i; this.j=j; cal(); } //计算坐标 private void cal(){ this.x=start+j*w+ j*5 ; this.y=start+i*h+ i*5 ; } //卡片绘制 public void draw(Graphics g) { //根据数字获取对应颜色 Color color =getColor(); Color oColor=g.getColor(); //设置新颜色 g.setColor(color); g.fillRoundRect(x,y,w,h,4,4); //绘制数字 if(num!=0){ g.setColor(new Color(125, 78, 51)); Font font = new Font("思源宋体",Font.BOLD,35); g.setFont(font); String text = num+""; int textLen =getWordWidth(font,text,g); int tx = x + (w-textLen)/2; int ty = y+50; g.drawString(text,tx,ty); } //还原颜色 g.setColor(oColor); } public static int getWordWidth(Font font,String content,Graphics g){ FontMetrics metrics = g.getFontMetrics(font); int width = 0; for(int i=0;i<content.length();i++){ width+=metrics.charWidth(content.charAt(i)); } return width; } //获取颜色 private Color getColor(){ Color color = null; switch(num){ case 2: color = new Color(238,244,234); break; case 4: color = new Color(222,236,200); break; case 8: color = new Color(174,213,130); break; case 16: color = new Color(142,201,75); break; case 32: color = new Color(111,148,48); break; case 64: color = new Color(76,174,124); break; case 128: color = new Color(60,180,144); break; case 256: color = new Color(45,130,120); break; case 512: color = new Color(9,97,26); break; case 1024: color = new Color(242,177,121); break; case 2048: color = new Color(223,185,0); break; default: color = new Color(92,151,117); break; } return color; } public void setNum(int num) { this.num=num; } public int getNum() { return this.num; } //向上移动的方法 public boolean moveTop(Card[][] cards,boolean b) { //设定递归的退出条件 if(i==0){ return false; } //上一个卡片 Card prev = cards[i-1][j]; if(prev.getNum()==0){//交换上去 if(b){ prev.num=this.num; this.num=0; prev.moveTop(cards,b); } return true; }else if(prev.getNum()==num && !prev.merge){//合并 if(b){ prev.merge=true; prev.num=this.num*2; this.num=0; } return true; // prev.moveTop(cards); }else{ return false; } } public void setMerge(boolean b) { this.merge=b; } public boolean moveRight(Card[][] cards,boolean b) { //设定递归的退出条件 if(j==3){ return false; } //右一个卡片 Card prev = cards[i][j+1]; if(prev.getNum()==0){//交换过去 if(b){ prev.num=this.num; this.num=0; prev.moveRight(cards,b); } return true; }else if(prev.getNum()==num && !prev.merge){//合并 if(b){ prev.merge=true; prev.num=this.num*2; this.num=0; } return true; // prev.moveRight(cards); }else{ return false; } } public boolean moveBottom(Card[][] cards,boolean b) { //设定递归的退出条件 if(i==3){ return false; } //下一个卡片 Card prev = cards[i+1][j]; if(prev.getNum()==0){//交换上去 if(b){ prev.num=this.num; this.num=0; prev.moveBottom(cards,b); } return true; }else if(prev.getNum()==num && !prev.merge){//合并 if(b){ prev.merge=true; prev.num=this.num*2; this.num=0; } return true; }else{ return false; } } public boolean moveLeft(Card[][] cards,boolean b) { //设定递归的退出条件 if(j==0){ return false; } //左一个卡片 Card prev = cards[i][j-1]; if(prev.getNum()==0){//交换过去 if(b){ prev.num=this.num; this.num=0; prev.moveLeft(cards,b); } return true; }else if(prev.getNum()==num && !prev.merge){//合并 if(b){ prev.merge=true; prev.num=this.num*2; this.num=0; } return true; }else{ return false; } } }