7月13暑期培训

本文详细解读了Java AWT中Game2048游戏面板的修改,包括Graphics.fillRoundRect方法、游戏状态切换、瓷砖渲染与移动逻辑。通过关键方法如startGame、drawGrid和move函数,展示了游戏界面的绘制与用户交互过程。
摘要由CSDN通过智能技术生成

对昨天的程序进行修改:

void java.awt.Graphics.fillRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight)

Parameters:

x the x coordinate of the rectangle to be filled.

y the y coordinate of the rectangle to be filled.

width the width of the rectangle to be filled.

height the height of the rectangle to be filled.

arcWidth the horizontal diameter of the arc at the four corners.

arcHeight the vertical diameter of the arc at the four corners.

package game2048;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.Random;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

public class Game2048 extends JPanel 
{

    /**
     * 2048游戏
     */
    private static final long serialVersionUID = 1L;
    enum State //1.四种状态
    {
        start,win,running,over
    }
    final Color[] colorTable= 
    {
        new Color(0x701710), new Color(0xFFE4C3), new Color(0xfff4d3),
        new Color(0xffdac3), new Color(0xe7b08e), new Color(0xe7bf8e),
        new Color(0xffc4c3), new Color(0xE7948e), new Color(0xbe7e56),
        new Color(0xbe5e56), new Color(0x9c3931), new Color(0x701710)
     };
    final static int target=2048;
    static int highest,score;
    private Color gridColor= new Color(0xbbada0);//整体颜色
    private Color emptyColor= new Color(0xcdc1b4);
    private Color startColor= new Color(0xfffbcd);
    private Random random=new Random();
    private Tile[][] tiles;
    private int side=4;
    private State gamestate=State.start ;
    private boolean checkingAvailableMoves;
    
    public Game2048() //2.构造方法
    {
        setPreferredSize(new Dimension(900, 700));
        setBackground(new Color(0xfaf8ef));
        setFont(new Font("SansSerif",Font.BOLD,48));
        setFocusable(true);
        addMouseListener(new MouseAdapter() 
        {
            public void mousePressed(MouseEvent e) {
            startGame();
            repaint();
            }
        });
        addKeyListener(new KeyAdapter() {
            @Override
            public void keyPressed(KeyEvent e) {
                switch (e.getKeyCode()) 
                {
                case KeyEvent.VK_UP:
                    moveUp();
                    break;
                case KeyEvent.VK_DOWN:
                    moveDown();
                    break;
                case KeyEvent.VK_LEFT:
                    moveLeft();
                    break;
                case KeyEvent.VK_RIGHT:
                    moveRight();
                    break;
                }    
                repaint();
            }                
        });
    }
    
    @Override
    protected void paintComponent(Graphics gg) //3.渲染
    {
        super.paintComponent(gg);
        Graphics2D g =(Graphics2D)gg;
        g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
        drawGrid(g);//画表格
    }
     void startGame() //开始游戏
        {
            if (gamestate != State.running) 
            {
                score=0;
                highest=0;
                gamestate=State.running;
                tiles=new Tile[side][side];
                addRandomTile();//产生一个2
                addRandomTile();//产生一个2        
            }
            
        }

     void drawGrid(Graphics2D g) //4.游戏状态,出现游戏相应界面
     {
        g.setColor(gridColor);        
        g.fillRoundRect(200, 100, 499,499,15,15);//整个表格的大小499*499
        if (gamestate == State.running)//开始后的状态,里面有两个随机数
        {
         for(int r = 0; r < side; r++)//循环,找到随机数的位置
             for(int c = 0; c < side; c++)
                 if (tiles[r][c]==null)
                 {
                     g.setColor(emptyColor);
                     g.fillRoundRect(215+c*121,115+r*121,106 ,106, 7,7);//空格子大小为106*106
                 }
                 else drawTile(g,r,c);//找到随机数的位置,创建随机数格子及颜色
        }
        else //开始前的游戏界面、结束后游戏界面
        {
        g.setColor(startColor);    //开始界面颜色
        g.fillRoundRect(215, 115, 469, 469, 7, 7);//开始界面的大小 469*469,与原来画面499*499叠加,会形成一种边框的错觉
        g.setColor(gridColor.darker());//设置游戏界面字体颜色"2048",.darker()会加深原来的颜色    
        //g.setColor(gridColor); //与上面颜色的区别就是“浅”
        g.setFont(new Font("SansSerif",Font.BOLD,128));
        g.drawString("2048", 310, 270);
        g.setFont(new Font("SansSerif",Font.BOLD,20));
        if (gamestate==State.win) g.drawString("Sucess!", 390, 350);
        else if (gamestate==State.over) g.drawString("game over", 400, 350);
        g.setColor(gridColor);    
        g.drawString("restart", 400, 350);
        g.drawString("use arrow keys to move tiles", 400, 350);
        }
        
     }

    private void drawTile(Graphics2D g, int r, int c)//5.根据上面找到的随机数位置,渲染随机数格子
    {
        int value=tiles[r][c].getValue();//读取当前格子的值,判断是否可以合并
        g.setColor(colorTable[(int)(Math.log(value )/Math .log(2))+1]);//设置颜色
        g.fillRoundRect(215+c*121,115+r*121,106,106,7,7);//106*106大小
        String string=String.valueOf(value);
        g.setColor(value<128?colorTable[0]:colorTable[1]);
        FontMetrics fm = g.getFontMetrics();
        int asc=fm.getAscent();
        int dec=fm.getDescent();
        int x=215+c*121+(106-fm.stringWidth(string))/2;
        int y=115+r*121+(asc+(106-(asc+dec))/2);
       g.drawString(string, x, y);
    }
    private void addRandomTile() //6.放东西
    {
        int pos=random.nextInt(side*side);
        int row,col;
        do {
            pos=(pos+1)%(side*side);
            row=pos/side;
            col=pos%side;                    
        } while (tiles[row][col]!=null);
        int val=random.nextInt(10)==0?4:2;
        tiles[row][col]=new Tile(val);//只要一移动就添加一个
    }
    private boolean move(int countDownFrom,int yIncr,int xIncr)//7.控制键盘的移动键动作
    {
        boolean moved =false;
        for(int i=0;i<side*side;i++)
        {
            int j=Math.abs(countDownFrom-i);
            int r=j/side;
            int c=j%side;
            if (tiles[r][c]==null) continue;
            int nextR=r+yIncr;
            int nextC=c+xIncr;
            while (nextR >= 0 && nextR < side && nextC >= 0 && nextC < side)
            {
                Tile next=tiles[nextR][nextC];//合并后
                Tile curr=tiles[r][c];//合并前
                if (next==null)
                {
                    if (checkingAvailableMoves) 
                        return true;
                    tiles[nextR][nextC]=curr;
                    tiles[r][c]=null;
                    r=nextR;//新的值
                    c=nextC;
                    nextR+=yIncr;
                    nextC+=xIncr;
                    moved=true;
                }
                else if (next.canMergeWith(curr)) 
                {
                    if (checkingAvailableMoves) 
                        return true;
                    int value=next.mergeWith(curr);
                    if (value>highest) 
                        highest=value;
                    score+=value ;
                    tiles[r][c]=null;
                    moved=true;
                    break;
                }else
                    break;
                
            }
            
        }
         if (moved) {
                if (highest < target) {
                    clearMerged();
                    addRandomTile();
                    if (!movesAvailable()) {
                        gamestate = State.over;
                    }
                } else if (highest == target)
                    gamestate = State.win;
            }
            return moved;
    }
    boolean moveRight() 
    {
        return move(side*side-1,0,1);        
    }
    boolean moveLeft() 
    {
        return move(0,0,-1);        
    }

    boolean moveDown() 
    {
        return move(side*side-1,1,0);        
    }

    boolean moveUp() 
    {
        return move(0,-1,0);        
    }
    void clearMerged()
    {
        for(Tile[] row:tiles)
            for(Tile tile:row)
                if(tile!=null) tile.setMerged(false);
    }
   boolean movesAvailable() 
   {
       checkingAvailableMoves=true;
       boolean hasMoves= moveUp() || moveDown() || moveLeft() || moveRight();
       checkingAvailableMoves=false;
       return hasMoves;
   }
    

    public static void main(String[] args) //入口
    {
        SwingUtilities.invokeLater(()->{
            JFrame f =new JFrame();
            f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            f.setTitle("2048");
            f.setResizable(true);
            f.add(new Game2048(),BorderLayout.CENTER);
            f.pack();
            f.setLocationRelativeTo(null);
            f.setVisible(true);
        });
        

    }
    

}
class Tile  //在随机数时被使用,看能不能被合并
{
    private boolean merged;
    private  int value;
    Tile(int val) 
    {
     value=val;
    }
    int getValue()
    {
    return    value;
    }
    void setMerged(boolean m) 
    {
        merged = m;
    }
        
    boolean canMergeWith(Tile other)
    {
        return !merged && other != null && !other.merged && value == other.getValue();
    }
    
    
    int mergeWith(Tile other)
    {
        if (canMergeWith(other))
        {
            value*=2;
            merged=true;
            return value;
        }
        return -1;
    }
}
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值