2048游戏的实现
需要使用的知识点:
1.JFrame界面的绘制,组件的添加
2、数组
3、事件
4、在界面上绘制数据。
实现过程:
1、游戏界面的绘制
(1)JFrame界面:大小、标题、能改变太大小、是否可见等。
(2)往界面上添加组件:按钮(开始游戏),标签(记录分数)。
(3)在界面上绘制一个大方格
(4)在大方格中绘制16个小方格(循环)
为了使绘制的矩形框一直存在,方法:使用重绘的方法。
实现重绘的方法:
(1)使用类继承组件
(2)在类中重写组件的paint(Graphics g)方法
(3)在piant中绘制你要绘制的图形。
paint方法是用来绘制图形界面的方法。
2、随机生成两个数据到图形界面上
1、点击按钮
事件源:按钮
事件监听器:addActionListener(ActionListener l)
事件接口:定义一个类实现ActionListener,每次点击按钮的时候,就会生成两个数据。
2、绘制数据
(1) 随机生成两个位置
(2)随机产生两个数字2或者4
(3)将随机生成的两个数绘制到那两个位置上。
如果最小化窗体后,数字没有了:
解决方法:
(1)把数字保存在数组中
(2)在重绘方法中绘制这些数据:
*使用NewListener类的构造方法传递一个Game2048类的对象
*在绘制数字之前调用Game2048窗体类的paint(Graphics g)方法。
3、移动数据
事件
事件源:Game2048窗体
事件监听器方法:addKeyListener(Keylistener l);
事件接口:按下键盘上、下、左、右键时,数据向上、下、左、右移动。
4、实现数据的相加
5、分数的计算
计算的结果要在界面上显示 jscore.setText("score"+" "+score);
jscore是定义的标签的对象
6、判断输赢
赢:出现了2048
输:界面上没有空位,且不能与旁边的数相加。
附:代码
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.event.KeyListener;
import javax.swing.JFrame;
import javax.swing.JLabel;
public class Game2048 extends JFrame{
int number[][]=new int[4][4];//定义一个数组来保存书数据
//绘制frame界面
public void initIU(){
this.setSize(450, 550) ;//设置界面的大小
this.setTitle("2048");//设置界面的标题
this.setLocationRelativeTo(null);//使界面处于中间的位置
this.setDefaultCloseOperation(3);
FlowLayout fl=new FlowLayout();//
this.setLayout(fl);//设置整体的布局为流失布局
javax.swing.JButton jb=new javax.swing.JButton("开始游戏");
javax.swing.JLabel jscore=new javax.swing.JLabel("score");//添加显示分数的标签
jscore.setPreferredSize(new Dimension(80,30));//设置除了jframe以外的组件的大小
this.add(jscore);
this.add(jb);
this.setVisible(true);//设置界面可见
Graphics g =this.getGraphics();
MyGame l=new MyGame(this, number,jscore);//
jb.addActionListener(l);//在事件上添加事件发生器
jb.setFocusable(false);
//this.addKeyListener(l);
this.addKeyListener(l);
} //重写paint方法绘制自己图形
public void paint(Graphics g){
super.paint(g);
g.setColor(new Color(103,103,103));//设置矩形的颜色
g.fillRoundRect(30, 70, 390, 400, 10 ,10);//画出一个大矩形
for(int i=0;i<4;i++)//绘制出16个小矩形
{
for(int j=0;j<4;j++){
g.setColor(new Color(210,210,210));
g.fillRoundRect(50+90*i, 90+90*j, 80, 80, 10 ,10);
}
}
g.setFont(new Font("宋体",Font.BOLD,40));//设置字体的格式
for(int i=0;i<4;i++)//根据数字的不同来设置数字的颜色
{
for(int j=0;j<4;j++){
if(number[i][j]!=0){
switch(number[i][j]){
case 2:
g.setColor(new Color(255,255,255));
g.fillRoundRect(50+90*j, 90+90*i, 80, 80, 10 ,10);
g.setColor(new Color(151,133,171));//设置的是字体的color还是 背景框的color
g.drawString(number[i][j]+"", 80+90*j, 140+90*i);
break;
case 4:
g.setColor(new Color(232,232,104));
g.fillRoundRect(50+90*j, 90+90*i, 80, 80, 10 ,10);
g.setColor(new Color(48,48,253));
g.drawString(number[i][j]+"", 80+90*j, 140+90*i);
break;
case 8:
g.setColor(new Color(209,216,252));
g.fillRoundRect(50+90*j, 90+90*i, 80, 80, 10 ,10);
g.setColor(new Color(250,0,128));
g.drawString(number[i][j]+"", 80+90*j, 140+90*i);
break;
case 16:
g.setColor(new Color(255,255,193));
g.fillRoundRect(50+90*j, 90+90*i, 80, 80, 10 ,10);
g.setColor(new Color(125,125,0));
g.drawString(number[i][j]+"", 70+90*j, 140+90*i);
break;
case 32:
g.setColor(new Color(190,237,239));
g.fillRoundRect(50+90*j, 90+90*i, 80, 80, 10 ,10);
g.setColor(new Color(189,85,219));
g.drawString(number[i][j]+"", 70+90*j, 140+90*i);
break;
case 64:
g.setColor(new Color(255,125,125));
g.fillRoundRect(50+90*j, 90+90*i, 80, 80, 10 ,10);
g.setColor(new Color(0,255,64));
g.drawString(number[i][j]+"", 70+90*j, 140+90*i);
break;
case 128:
g.setColor(new Color(192,233,230));
g.fillRoundRect(50+90*j, 90+90*i, 80, 80, 10 ,10);
g.setColor(new Color(255,230,230));
g.drawString(number[i][j]+"", 50+90*j, 140+90*i);
break;
case 256:
g.setColor(new Color(40,157,146));
g.fillRoundRect(50+90*j, 90+90*i, 80, 80, 10 ,10);
g.setColor(new Color(209,216,252));
g.drawString(number[i][j]+"", 50+90*j, 140+90*i);
break;
case 512:
g.setColor(new Color(192,109,101));
g.fillRoundRect(50+90*j, 90+90*i, 80, 80, 10 ,10);
g.setColor(new Color(255,255,193));
g.drawString(number[i][j]+"", 50+90*j, 140+90*i);
break;
case 1024:
g.setColor(new Color(259,89,81));
g.fillRoundRect(50+90*j, 90+90*i, 80, 80, 10 ,10);
g.setColor(new Color(167,63,233));
g.drawString(number[i][j]+"", 30+90*j, 140+90*i);
break;
}
}
}
}
}
public static void main(String[] args) {
Game2048 ga=new Game2048();
ga.initIU();
}
}
-------------------------------------------------------事件处理接口----------------------------------------------------
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import javax.swing.JOptionPane;
public class MyGame extends KeyAdapter implements ActionListener{
//private Graphics g;//传入画笔
private Game2048 Game;//为了获取窗体里面的paint方法
private int[][]number;//定义一个二维数组用来存储数据
private java.util.Random rand=new java.util.Random();
javax.swing.JLabel jscore;
int score=0;
int first=0;
public MyGame (Game2048 Game,int number[][],javax.swing.JLabel jscore){ //构造函数
this.Game=Game;
this.number=number;
this.jscore=jscore;
}
public void actionPerformed(ActionEvent e){
//1.清除数组中所有的数据
for(int i=0;i<4;i++)
{
for(int j=0;j<4;j++){
number[i][j]=0;
}
}
score=0;
int r1,r2,l1,l2;//随机生成两个位置
r1=rand.nextInt(4);
l1=rand.nextInt(4);
r2=rand.nextInt(4);
l2=rand.nextInt(4);
while(r1==r2&&l1==l2)//避免随机生成的两个位置相同
{
r2=rand.nextInt(4);
l2=rand.nextInt(4);
}
int num1= (rand.nextInt(2)+1)*2;//生成两个数据
int num2= (rand.nextInt(2)+1)*2;
number[r1][l1]=num1; //把数据存储在数组中
number[r2][l2]=num2;
//3.调用重绘方法 ,使得每次按开始游戏按钮时只有两个数据
Game.paint(Game.getGraphics());
}
public void keyReleased(KeyEvent e) {
int count=0;
// System.out.print("->"+e.getKeyCode());
switch(e.getKeyCode()){
case 37://左键
for(int i=0;i<4;i++)
{
for(int j=1;j<4;j++){ //是数据向左移动
if(number[i][j]!=0)
{ int temp=number[i][j];
int c=j-1;
while(c>=0&&number[i][c]==0)
{
number[i][c]=temp;
number[i][c+1]=0;
c--;
count++;
}
while(c>=0&&number[i][c]==number[i][c+1]){ //与左边的数据相加
number[i][c]=number[i][c]+number[i][c+1];
number[i][c+1]=0;
count++;
score+=number[i][c];
}
}
}
}
break;
case 38://上键
for(int i=1;i<4;i++)
{
for(int j=0;j<4;j++){
if(number[i][j]!=0)
{ int temp=number[i][j];
int c=i-1;
while(c>=0&&number[c][j]==0)
{
number[c][j]=temp;
number[c+1][j]=0;
c--;
count++;
}
while(c>=0&&number[c][j]==number[c+1][j]){
number[c][j]=number[c][j]+number[c+1][j];
number[c+1][j]=0;
count++;
score+=number[c][j];
}
}
}
}
break;
case 39://右键
for(int i=0;i<4;i++)
{
for(int j=2;j>=0;j--){
if(number[i][j]!=0)
{ int temp=number[i][j];
int c=j+1;
while(c<4&&number[i][c]==0)
{
number[i][c]=temp;
number[i][c-1]=0;
c++;
count++;
}
while(c<4&&number[i][c]==number[i][c-1]){
number[i][c]=number[i][c]+number[i][c-1];
number[i][c-1]=0;
count++;
score+=number[i][c];
}
}
}
}
break;
case 40://下键
for(int i=2;i>=0;i--)
{
for(int j=0;j<4;j++){
if(number[i][j]!=0)
{int temp=number[i][j];
int c=i+1;
while(c<4&&number[c][j]==0)
{
number[c][j]=temp;
number[c-1][j]=0;
c++;
count++;
}
while(c<4&&number[c][j]==number[c-1][j]){
number[c][j]=number[c][j]+number[c-1][j];
number[c-1][j]=0;
count++;
score+=number[c][j];
}
}
}
}
break;
}
if(count>0) { //如果发生了数据的一定或者有相加的行为,则在界面上随机生成一个数
int r=rand.nextInt(4);
int l=rand.nextInt(4);
while(number[r][l]!=0){
r=rand.nextInt(4);
l=rand.nextInt(4);
}
int value=(rand.nextInt(2)+1)*2;
number[r][l]=value;
Game.paint(Game.getGraphics());
jscore.setText("score"+" "+score);
panduan();//调用判断输赢的方法
}
}
public void panduan(){
int a=0;int ccount=0;
for(int i=0;i<4;i++)
{
for(int j=0;j<4;j++){
if(number[i][j]==1024&&first==0){//判断是否出现了2014
JOptionPane.showMessageDialog(null, "你赢了!");
first=1;
}
if(number[i][j]!=0){
a++;
}
}
}
for(int i=0;i<3;i++){
for(int j=0;j<3;j++){
if(number[i][j]==number[i][j+1]&&number[i][j]!=0){//判断左右是否相等
ccount++;
}
if(number[i][j]==number[i+1][j]&&number[i][j]!=0){//判断上下是否相等
ccount++;
}
if(number[3][j]==number[3][j+1]&&number[3][j]!=0){//判断第四列上下是否相等
ccount++;
}
if(number[i][3]==number[i+1][3]&&number[i][3]!=0){//判断上下第四行是否相等
ccount++;
}
}
}
if(a==16&&ccount==0){
JOptionPane.showMessageDialog(null, "你输了!");//判断是否输了:1.所有表格不为0;2.没有能相加的数
}
}
}
2048游戏的实现
需要使用的知识点:
1.JFrame界面的绘制,组件的添加
2、数组
3、事件
4、在界面上绘制数据。
实现过程:
1、游戏界面的绘制
(1)JFrame界面:大小、标题、能改变太大小、是否可见等。
(2)往界面上添加组件:按钮(开始游戏),标签(记录分数)。
(3)在界面上绘制一个大方格
(4)在大方格中绘制16个小方格(循环)
********为了使绘制的矩形框一直存在,方法:使用重绘的方法。********
实现重绘的方法:
(1)使用类继承组件
(2)在类中重写组件的paint(Graphics g)方法
(3)在piant中绘制你要绘制的图形。
paint方法是用来绘制图形界面的方法。
2、随机生成两个数据到图形界面上
1、点击按钮
事件源:按钮
事件监听器:addActionListener(ActionListener l)
事件接口:定义一个类实现ActionListener,每次点击按钮的时候,就会生成两个数据。
2、绘制数据
(1) 随机生成两个位置
(2)随机产生两个数字2或者4
(3)将随机生成的两个数绘制到那两个位置上。
如果最小化窗体后,数字没有了:
解决方法:
(1)把数字保存在数组中
(2)在重绘方法中绘制这些数据:
*使用NewListener类的构造方法传递一个Game2048类的对象
*在绘制数字之前调用Game2048窗体类的paint(Graphics g)方法。
3、移动数据
事件
事件源:Game2048窗体
事件监听器方法:addKeyListener(Keylistener l);
事件接口:按下键盘上、下、左、右键时,数据向上、下、左、右移动。
4、实现数据的相加
5、分数的计算
计算的结果要在界面上显示 jscore.setText("score"+" "+score);
jscore是定义的标签的对象
6、判断输赢
赢:出现了2048
输:界面上没有空位,且不能与旁边的数相加。
-------------------------------------------------------------------------------------------------------
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.event.KeyListener;
import javax.swing.JFrame;
import javax.swing.JLabel;
public class Game2048 extends JFrame{
int number[][]=new int[4][4];//定义一个数组来保存书数据
//绘制frame界面
public void initIU(){
this.setSize(450, 550) ;//设置界面的大小
this.setTitle("2048");//设置界面的标题
this.setLocationRelativeTo(null);//使界面处于中间的位置
this.setDefaultCloseOperation(3);
FlowLayout fl=new FlowLayout();//
this.setLayout(fl);//设置整体的布局为流失布局
javax.swing.JButton jb=new javax.swing.JButton("开始游戏");
javax.swing.JLabel jscore=new javax.swing.JLabel("score");//添加显示分数的标签
jscore.setPreferredSize(new Dimension(80,30));//设置除了jframe以外的组件的大小
this.add(jscore);
this.add(jb);
this.setVisible(true);//设置界面可见
Graphics g =this.getGraphics();
MyGame l=new MyGame(this, number,jscore);//
jb.addActionListener(l);//在事件上添加事件发生器
jb.setFocusable(false);
//this.addKeyListener(l);
this.addKeyListener(l);
} //重写paint方法绘制自己图形
public void paint(Graphics g){
super.paint(g);
g.setColor(new Color(103,103,103));//设置矩形的颜色
g.fillRoundRect(30, 70, 390, 400, 10 ,10);//画出一个大矩形
for(int i=0;i<4;i++)//绘制出16个小矩形
{
for(int j=0;j<4;j++){
g.setColor(new Color(210,210,210));
g.fillRoundRect(50+90*i, 90+90*j, 80, 80, 10 ,10);
}
}
g.setFont(new Font("宋体",Font.BOLD,40));//设置字体的格式
for(int i=0;i<4;i++)//根据数字的不同来设置数字的颜色
{
for(int j=0;j<4;j++){
if(number[i][j]!=0){
switch(number[i][j]){
case 2:
g.setColor(new Color(255,255,255));
g.fillRoundRect(50+90*j, 90+90*i, 80, 80, 10 ,10);
g.setColor(new Color(151,133,171));//设置的是字体的color还是 背景框的color
g.drawString(number[i][j]+"", 80+90*j, 140+90*i);
break;
case 4:
g.setColor(new Color(232,232,104));
g.fillRoundRect(50+90*j, 90+90*i, 80, 80, 10 ,10);
g.setColor(new Color(48,48,253));
g.drawString(number[i][j]+"", 80+90*j, 140+90*i);
break;
case 8:
g.setColor(new Color(209,216,252));
g.fillRoundRect(50+90*j, 90+90*i, 80, 80, 10 ,10);
g.setColor(new Color(250,0,128));
g.drawString(number[i][j]+"", 80+90*j, 140+90*i);
break;
case 16:
g.setColor(new Color(255,255,193));
g.fillRoundRect(50+90*j, 90+90*i, 80, 80, 10 ,10);
g.setColor(new Color(125,125,0));
g.drawString(number[i][j]+"", 70+90*j, 140+90*i);
break;
case 32:
g.setColor(new Color(190,237,239));
g.fillRoundRect(50+90*j, 90+90*i, 80, 80, 10 ,10);
g.setColor(new Color(189,85,219));
g.drawString(number[i][j]+"", 70+90*j, 140+90*i);
break;
case 64:
g.setColor(new Color(255,125,125));
g.fillRoundRect(50+90*j, 90+90*i, 80, 80, 10 ,10);
g.setColor(new Color(0,255,64));
g.drawString(number[i][j]+"", 70+90*j, 140+90*i);
break;
case 128:
g.setColor(new Color(192,233,230));
g.fillRoundRect(50+90*j, 90+90*i, 80, 80, 10 ,10);
g.setColor(new Color(255,230,230));
g.drawString(number[i][j]+"", 50+90*j, 140+90*i);
break;
case 256:
g.setColor(new Color(40,157,146));
g.fillRoundRect(50+90*j, 90+90*i, 80, 80, 10 ,10);
g.setColor(new Color(209,216,252));
g.drawString(number[i][j]+"", 50+90*j, 140+90*i);
break;
case 512:
g.setColor(new Color(192,109,101));
g.fillRoundRect(50+90*j, 90+90*i, 80, 80, 10 ,10);
g.setColor(new Color(255,255,193));
g.drawString(number[i][j]+"", 50+90*j, 140+90*i);
break;
case 1024:
g.setColor(new Color(259,89,81));
g.fillRoundRect(50+90*j, 90+90*i, 80, 80, 10 ,10);
g.setColor(new Color(167,63,233));
g.drawString(number[i][j]+"", 30+90*j, 140+90*i);
break;
}
}
}
}
}
public static void main(String[] args) {
Game2048 ga=new Game2048();
ga.initIU();
}
}
-------------------------------------------------------事件处理接口----------------------------------------------------
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import javax.swing.JOptionPane;
public class MyGame extends KeyAdapter implements ActionListener{
//private Graphics g;//传入画笔
private Game2048 Game;//为了获取窗体里面的paint方法
private int[][]number;//定义一个二维数组用来存储数据
private java.util.Random rand=new java.util.Random();
javax.swing.JLabel jscore;
int score=0;
int first=0;
public MyGame (Game2048 Game,int number[][],javax.swing.JLabel jscore){ //构造函数
this.Game=Game;
this.number=number;
this.jscore=jscore;
}
public void actionPerformed(ActionEvent e){
//1.清除数组中所有的数据
for(int i=0;i<4;i++)
{
for(int j=0;j<4;j++){
number[i][j]=0;
}
}
score=0;
int r1,r2,l1,l2;//随机生成两个位置
r1=rand.nextInt(4);
l1=rand.nextInt(4);
r2=rand.nextInt(4);
l2=rand.nextInt(4);
while(r1==r2&&l1==l2)//避免随机生成的两个位置相同
{
r2=rand.nextInt(4);
l2=rand.nextInt(4);
}
int num1= (rand.nextInt(2)+1)*2;//生成两个数据
int num2= (rand.nextInt(2)+1)*2;
number[r1][l1]=num1; //把数据存储在数组中
number[r2][l2]=num2;
//3.调用重绘方法 ,使得每次按开始游戏按钮时只有两个数据
Game.paint(Game.getGraphics());
}
public void keyReleased(KeyEvent e) {
int count=0;
// System.out.print("->"+e.getKeyCode());
switch(e.getKeyCode()){
case 37://左键
for(int i=0;i<4;i++)
{
for(int j=1;j<4;j++){ //是数据向左移动
if(number[i][j]!=0)
{ int temp=number[i][j];
int c=j-1;
while(c>=0&&number[i][c]==0)
{
number[i][c]=temp;
number[i][c+1]=0;
c--;
count++;
}
while(c>=0&&number[i][c]==number[i][c+1]){ //与左边的数据相加
number[i][c]=number[i][c]+number[i][c+1];
number[i][c+1]=0;
count++;
score+=number[i][c];
}
}
}
}
break;
case 38://上键
for(int i=1;i<4;i++)
{
for(int j=0;j<4;j++){
if(number[i][j]!=0)
{ int temp=number[i][j];
int c=i-1;
while(c>=0&&number[c][j]==0)
{
number[c][j]=temp;
number[c+1][j]=0;
c--;
count++;
}
while(c>=0&&number[c][j]==number[c+1][j]){
number[c][j]=number[c][j]+number[c+1][j];
number[c+1][j]=0;
count++;
score+=number[c][j];
}
}
}
}
break;
case 39://右键
for(int i=0;i<4;i++)
{
for(int j=2;j>=0;j--){
if(number[i][j]!=0)
{ int temp=number[i][j];
int c=j+1;
while(c<4&&number[i][c]==0)
{
number[i][c]=temp;
number[i][c-1]=0;
c++;
count++;
}
while(c<4&&number[i][c]==number[i][c-1]){
number[i][c]=number[i][c]+number[i][c-1];
number[i][c-1]=0;
count++;
score+=number[i][c];
}
}
}
}
break;
case 40://下键
for(int i=2;i>=0;i--)
{
for(int j=0;j<4;j++){
if(number[i][j]!=0)
{int temp=number[i][j];
int c=i+1;
while(c<4&&number[c][j]==0)
{
number[c][j]=temp;
number[c-1][j]=0;
c++;
count++;
}
while(c<4&&number[c][j]==number[c-1][j]){
number[c][j]=number[c][j]+number[c-1][j];
number[c-1][j]=0;
count++;
score+=number[c][j];
}
}
}
}
break;
}
if(count>0) { //如果发生了数据的一定或者有相加的行为,则在界面上随机生成一个数
int r=rand.nextInt(4);
int l=rand.nextInt(4);
while(number[r][l]!=0){
r=rand.nextInt(4);
l=rand.nextInt(4);
}
int value=(rand.nextInt(2)+1)*2;
number[r][l]=value;
Game.paint(Game.getGraphics());
jscore.setText("score"+" "+score);
panduan();//调用判断输赢的方法
}
}
public void panduan(){
int a=0;int ccount=0;
for(int i=0;i<4;i++)
{
for(int j=0;j<4;j++){
if(number[i][j]==1024&&first==0){//判断是否出现了2014
JOptionPane.showMessageDialog(null, "你赢了!");
first=1;
}
if(number[i][j]!=0){
a++;
}
}
}
for(int i=0;i<3;i++){
for(int j=0;j<3;j++){
if(number[i][j]==number[i][j+1]&&number[i][j]!=0){//判断左右是否相等
ccount++;
}
if(number[i][j]==number[i+1][j]&&number[i][j]!=0){//判断上下是否相等
ccount++;
}
if(number[3][j]==number[3][j+1]&&number[3][j]!=0){//判断第四列上下是否相等
ccount++;
}
if(number[i][3]==number[i+1][3]&&number[i][3]!=0){//判断上下第四行是否相等
ccount++;
}
}
}
if(a==16&&ccount==0){
JOptionPane.showMessageDialog(null, "你输了!");//判断是否输了:1.所有表格不为0;2.没有能相加的数
}
}
}