总结——2048
第一次做成的小游戏
1.实现2048游戏界面,需要使用哪些组件?
JButton
JFrame
FlowLayout
Graphics
Color
Font
2.绘制2048游戏界面
游戏界面要一直存在
将绘制2048游戏界面的代码放在窗体的paint方法中
3.点击按钮,在界面上绘制两个数字
事件
事件源:开始按钮
监听器方法:addActionListener(ActionListener l);
事件接口:ActionListener
绘制两个数字
传递Graphics参数
生成2,4的数据
生成2,4放置的位置
4.任务:
1.绘制出界面,能随机两个数
2.每点击一次开始游戏,要重新生成两个数
3.让数据一直保持在界面上(除非点击了开始游戏)
4.按下键盘的上下左右键时,移动数字。
界面
/**
* 2048游戏主界面
* @author HOU
*
*/
public class Game2048 extends JFrame {
/**
* @param args
*/
public static void main(String[] args) {
Game2048 game = new Game2048();
game.initUI();
}
//定义一个数组对象,用来储存数据
private int [][] numbers = new int[4][4] ;
/**
* 初始化界面的方法
*/
public void initUI(){
this.setSize(550, 580);
this.setTitle("2048");
this.setDefaultCloseOperation(3);
this.setLocationRelativeTo(null);//居中设置
this.setResizable(false);
this.setLayout(new FlowLayout());
JLabel jl = new JLabel("Score");
jl.setPreferredSize(new Dimension(100,50));
JButton jb= new JButton("开始游戏");
//让按钮得不到焦点
jb.setFocusable(false);
this.add(jb);
this.add(jl);
this.setVisible(true);
//创建事件处理类StartListener的对象sl
StartListener sl = new StartListener(this,numbers, jl);
//给事件源jb按钮添加动作监听器方法,指定事件接口的对象sl
jb.addActionListener(sl);
//给事件源Game2048窗体添加键盘监听器方法,指定事件处理对象sl
this.addKeyListener(sl);
}
/**
* 重写窗体的paint方法
*/
public void paint(Graphics g){
super.paint(g);//调用父类的方法
//绘制大的背景框
g.setColor(Color.LIGHT_GRAY);
g.fillRoundRect(50, 80, 450, 450,15,15);
//绘制小矩形框颜色
g.setColor(new Color(234,232,232));
//绘制小的格子大小
for(int i=0;i<4;i++){
for(int j=0;j<4;j++){
g.fillRoundRect(60+i*110, 90+j*110, 100, 100,15,15);
}
}
g.setFont(new Font("行书",Font.BOLD,42));
//循环数组,判断相应位置是否存在数组,若有,则重绘,若无,则储存
for(int i=0;i<4;i++){
for(int j=0;j<4;j++){
if(numbers[i][j]!=0){
//绘制每个数字的框的颜色
if(numbers[i][j]==2 ){
//绘制数字2的框的颜色和大小
g.setColor(Color.pink);
g.fillRoundRect(60+j*110, 90+i*110, 100, 100,15,15);
//绘制数字颜色和大小
g.setColor(Color.black);
g.drawString(numbers[i][j]+"", 60+j*110+35, 90+i*110+60);
}
if(numbers[i][j]==4 ){
//绘制数字4的框的颜色和大小
g.setColor(Color.magenta);
g.fillRoundRect(60+j*110, 90+i*110, 100, 100,15,15);
//绘制数字
g.setColor(Color.black);
g.drawString(numbers[i][j]+"", 60+j*110+35, 90+i*110+60);
}
else if(numbers[i][j]==8 ){
//绘制数字8的框的颜色和大小
g.setColor(Color.CYAN);
g.fillRoundRect(60+j*110, 90+i*110, 100, 100,15,15);
//绘制数字
g.setColor(Color.white);
g.drawString(numbers[i][j]+"", 60+j*110+35, 90+i*110+60);
}
else if(numbers[i][j]==16){
//绘制数字16的框的颜色和大小
g.setColor(Color.green);
g.fillRoundRect(60+j*110, 90+i*110, 100, 100,15,15);
g.setColor(Color.white);
g.drawString(numbers[i][j]+"", 60+j*110+25, 90+i*110+65);
}
else if(numbers[i][j]==32){
//绘制数字32的框的颜色和大小
g.setColor(Color.yellow);
g.fillRoundRect(60+j*110, 90+i*110, 100, 100,15,15);
//绘制数字大小和颜色
g.setColor(Color.white);
g.drawString(numbers[i][j]+"", 60+j*110+25, 90+i*110+65);
}
else if(numbers[i][j]==64){
//绘制数字64的框的颜色和大小
g.setColor(new Color(55,145,43));
g.fillRoundRect(60+j*110, 90+i*110, 100, 100,15,15);
//绘制数字大小和颜色
g.setColor(Color.white);
g.drawString(numbers[i][j]+"", 60+j*110+25, 90+i*110+65);
}
else if (numbers[i][j]==128){
//绘制数字128的框的颜色和大小
g.setColor(Color.orange);
g.fillRoundRect(60+j*110, 90+i*110, 100, 100,15,15);
//绘制数字大小和颜色
g.setColor(Color.white);
g.drawString(numbers[i][j]+"", 60+j*110+15, 90+i*110+70);
}
else if (numbers[i][j]==256){
//绘制数字256的框的颜色和大小
g.setColor(new Color(157,141,30));
g.fillRoundRect(60+j*110, 90+i*110, 100, 100,15,15);
//绘制数字大小和颜色
g.setColor(Color.white);
g.drawString(numbers[i][j]+"", 60+j*110+15, 90+i*110+70);
}
else if (numbers[i][j]==512){
//绘制数字512的框的颜色和大小
g.setColor(new Color(159,61,28));
g.fillRoundRect(60+j*110, 90+i*110, 100, 100,15,15);
//绘制数字大小和颜色
g.setColor(Color.white);
g.drawString(numbers[i][j]+"", 60+j*110+15, 90+i*110+70);
}
else if (numbers[i][j]==1024) {
//绘制数字1024的框的颜色和大小
g.setColor(new Color(184,3,3));
g.fillRoundRect(60+j*110, 90+i*110, 100, 100,15,15);
//绘制数字大小和颜色
g.setColor(Color.white);
g.drawString(numbers[i][j]+"", 60+j*110+7, 90+i*110+75);
}
else if (numbers[i][j]==2048) {
//绘制数字2048的框的颜色和大小
g.setColor(Color.RED);
g.fillRoundRect(60+j*110, 90+i*110, 100, 100,15,15);
//绘制数字大小和颜色
g.setColor(Color.white);
g.drawString(numbers[i][j]+"", 60+j*110+7, 90+i*110+75);
}
}
}
}
}
}
界面效果图
监听器
/**
* 点击开始游戏按钮的事件处理类,该类实现ActionListener接口
* @author HOU
*
*/
public class StartListener extends KeyAdapter implements ActionListener {
private Graphics g;//声明一个Graphics对象名
private int r1,c1,r2,c2;//声明四个int属性,用来存储数字要绘制的位置
private Random rand = new Random();//创建一个随机数类的对象
private Game2048 game ;//声明game
private int[] [] numbers;//声明数组
private boolean flag;//声明布尔函数
private JLabel jl;
private int score ;
/**
* 构造方法
* game界面类的对象
* numbers储存数据的数组
*/
public StartListener(Game2048 game, int[] [] numbers,JLabel jl){
this.game=game;
this.numbers=numbers;
this.jl = jl;
}
/**
* 重写接口中的方法,作为事件处理类
*/
@Override
public void actionPerformed(ActionEvent e){
//清除数组中所有的数据
for(int i=0;i<4;i++){
for(int j=0;j<4;j++){
numbers[i][j]=0;
}
}
flag = true;//初始化flag
score = 0; //初始化score
//生成随机数组的行和列
r1 = rand.nextInt(4);
c1 = rand.nextInt(4);
r2 = rand.nextInt(4);
c2 = rand.nextInt(4);
while(r1==r2 && c1 == c2){
//防止出现在同一个位置
r2 = rand.nextInt(4);
c2 = rand.nextInt(4);
}
//生成两个2或者4
int value1 =rand.nextInt(2)*2+2;
int value2 =rand.nextInt(2)*2+2;
//将数组储存到对应的数组中
numbers[r1][c1] = value1;
numbers[r2][c2] = value1;
//调用paint方法将数字进行重绘
game.paint(game.getGraphics());
}
/*
* 键盘的释放事件处理方法
*/
public void keyReleased(KeyEvent e) {
int count = 0; //计数器,如果计数器不为0,则表示有移动数据
// System.out.println(" "+e.getKeyCode());
switch(e.getKeyCode()){
case 37://左
//循环数组
for(int i=0;i<4;i++){
for(int j=0;j<4;j++){
if(numbers[i][j]!=0){//判断该位置不为0
int temp = numbers[i][j];//存储该位置的数据
int c =j-1;
while(c>=0 && numbers[i][c]==0){
numbers[i][c]=temp;
numbers[i][c+1]=0;
c--;
count++;//计数器加1,表示移动了一次数据
}
}
}
}
for(int i=0;i<4;i++){
for(int j=0;j<4;j++){
//排除数组都是0的情况 (在没有数组时,默认是0)
if(j+1<4 && numbers[i][j]== numbers[i][j+1] && numbers[i][j]!=0){
numbers[i][j]=numbers[i][j]+numbers[i][j+1];
numbers[i][j+1]=0;
count++;
score+= numbers[i][j];//设置得分为两数相加
}
}
}
//加完之后要在运行一下移动 否则会出现bug
for(int i=0;i<4;i++){
for(int j=0;j<4;j++){
if(numbers[i][j]!=0){//判断该位置不为0
int temp = numbers[i][j];//存储该位置的数据
int c =j-1;
while(c>=0 && numbers[i][c]==0){
numbers[i][c]=temp;
numbers[i][c+1]=0;
c--;
count++;
}
}
}
}
break;
case 39://右
//循环数组
for(int i=0;i<4;i++){
for(int j=2;j>=0;j--){
if(numbers[i][j]!=0){//判断该位置不为0
int temp = numbers[i][j];//存储该位置的数据
int c =j+1;
while(c<4 && numbers[i][c]==0){
numbers[i][c]=temp;
numbers[i][c-1]=0;
c++;
count++;
}
}
}
}
for(int i=0;i<4;i++){
for(int j=3;j>=0;j--){
if(j-1>=0 && numbers[i][j]== numbers[i][j-1] && numbers[i][j]!=0){
numbers[i][j]=numbers[i][j]+numbers[i][j-1];
numbers[i][j-1]=0;
count++;
score+= numbers[i][j];
}
}
}
for(int i=0;i<4;i++){
for(int j=2;j>=0;j--){
if(numbers[i][j]!=0){//判断该位置不为0
int temp = numbers[i][j];//存储该位置的数据
int c =j+1;
while(c<4 && numbers[i][c]==0){
numbers[i][c]=temp;
numbers[i][c-1]=0;
c++;
count++;
}
}
}
}
break;
case 38://上
//循环数组
for(int i=0;i<4;i++){
for(int j=0;j<4;j++){
if(numbers[i][j]!=0){//判断该位置不为0
int temp = numbers[i][j];//存储该位置的数据
int r =i-1;
while(r>=0 && numbers[r][j]==0){
numbers[r][j]=temp;
numbers[r+1][j]=0;
r--;
count++;
}
}
}
}
for(int i=0;i<4;i++){
for(int j=0;j<4;j++){
if(i+1<4 && numbers[i][j]== numbers[i+1][j] && numbers[i][j]!=0){
numbers[i][j]=numbers[i][j]+numbers[i+1][j];
numbers[i+1][j]=0;
count++;
score+= numbers[i][j];
}
}
}
for(int i=0;i<4;i++){
for(int j=0;j<4;j++){
if(numbers[i][j]!=0){//判断该位置不为0
int temp = numbers[i][j];//存储该位置的数据
int r =i-1;
while(r>=0 && numbers[r][j]==0){
numbers[r][j]=temp;
numbers[r+1][j]=0;
r--;
count++;
}
}
}
}
break;
case 40://下
//循环数组
for(int i=2 ;i>=0;i--){
for(int j=0;j<4;j++){
if(numbers[i][j]!=0){//判断该位置不为0
int temp = numbers[i][j];//存储该位置的数据
int r =i+1;
while(r<4 && numbers[r][j]==0){
numbers[r][j]=temp;
numbers[r-1][j]=0;
r++;
count++;
}
}
}
}
for(int i=0;i<4;i++){
for(int j=0;j<4;j++){
if(i-1>=0 && numbers[i][j]== numbers[i-1][j] && numbers[i][j]!=0){
numbers[i][j]=numbers[i][j]+numbers[i-1][j];
numbers[i-1][j]=0;
count++;
score+= numbers[i][j];
}
}
}
for(int i=2 ;i>=0;i--){
for(int j=0;j<4;j++){
if(numbers[i][j]!=0){//判断该位置不为0
int temp = numbers[i][j];//存储该位置的数据
int r =i+1;
while(r<4 && numbers[r][j]==0){
numbers[r][j]=temp;
numbers[r-1][j]=0;
r++;
count++;
}
}
}
}
break;
}
int numbercount =0;//计数 数组的个数(0——16)
int numbercount2=0;//计数 有数组相同的时候
for(int i=0 ;i<3 ;i++){
for(int j=0;j<3;j++){//考虑16个格左上角的9个格
if(numbers[i][j]==numbers[i][j+1] && numbers[i][j]!=0){
numbercount2++;
}
if(numbers[i][j]==numbers[i+1][j] && numbers[i][j]!=0){
numbercount2++;
}
//考虑剩下的格
if(numbers[3][j]==numbers[3][j+1] && numbers[3][j]!=0){
numbercount2++;
}
if(numbers[i][3]==numbers[i+1][3] && numbers[i][3]!=0){
numbercount2++;
}
}
}
for(int i=0 ;i<4 ;i++){
for(int j=0;j<4;j++){
if(flag && numbers[i][j]==2048){
//输出框
JOptionPane.showMessageDialog(null, "win!");
//在2048之后还可以运行
flag = false;
}
if (numbers[i][j]!=0 ){
numbercount++;
//数组全部布满 并且没有相等的时候
if(numbercount==16 && numbercount2==0){
JOptionPane.showMessageDialog(null, "lose!");
}
}
}
}
if(count>0){//有移动数据的时候
jl.setText("Score:"+score);
//生成单元格所在的行和列
r1 = rand.nextInt(4);
c1 = rand.nextInt(4);
while(numbers[r1][c1]!=0){
//防止该位置已经存在值了
r1 = rand.nextInt(4);
c1 = rand.nextInt(4);
}
//生成1个2或者4
int value1 =rand.nextInt(2)*2+2;
//将数组储存到对应的数组中
numbers[r1][c1] = value1;
//调用paint方法将数字进行重绘数字
game.paint(game.getGraphics());
}
}
}
测试结果
失败的时候
P.s:
代码还不完善,当两个1024出现在一起并且合并的时候,在合并之前就会显示你赢了,而不是生成2048的时候显示