阅读更多

1顶
0踩

编程语言


                  
         这是一款意外蹿红的小游戏,简单、益智,符合当代年轻人的气息,无须学习复杂的规则便可以得心

应手,并且愈玩愈烈。简单介绍后,接下来就分析一下该游戏的界面实现和功能实现。
        在界面的实现方面,我们需要考虑会用到哪些API类,分别如下:
布局:FlowLayout,BorderLayout;组件:JFrame,JPanel,JButton,JTextField;绘图:Graphics

,Color,Image;事件接口:KeyListener,KeyEvent,ActionListener,ActionEvent;组件大小:

Dimension;菜单:JMenuBar,JMenu,JMenuItem。首先,我们需要创建一个窗体,并且设置大小、题

目、位置、可见等。然后整个界面应采用边框布局,分别是北边、南边和中间,而北边面板应采用流

式布局来安排得分和最高分。北边面板需添加两个文本框以显示分数,并设置成不可更改的形式。南

边面板添加一个开始按钮使得游戏失败后还可以继续玩。中间面板需要一个四乘四的格子,我采用画

矩形的方法,先画一个背景深粉色矩形,再在上面通过画笔类用双层循环画出16个小矩形,然后需要

在格子上绘制图片,我们采用Image抽象类来添加并显示图片。接着我们可以添加一个简单的菜单以及

子菜单。最后我们需要在事件源文本框、按钮、中间面板分别添加监听器,使得可以监听动作的发生

和键盘的按下或释放。这样子一个2048游戏界面就大概实现了。顺便为自己提些注意事项:第一,界

面Game2048类继承了JPanel类,所以在写北边和南边面板方法的时候应该将JFrame作为参数。ps:其

实我还是没懂为什么要继承JPanel类,有没有大神回复一下;第二,JTextField应该定义为全局变量

,以便在设置分数的时候可以传递参数到功能实现的类里边;第三,创建画笔对象应该在窗体可见之

后;第四,由于游戏主界面是表格形式,所以图片的存放应该设置为二维数组;第五,绘制画图板的

时候,应该调用父类的paint()方法;第六,为了让键盘监听中间面板得以更好的实现,应该将文本框

及按钮的焦点设置为false。

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.GridLayout;
import java.awt.Image;
import java.awt.LayoutManager;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.image.ImageObserver;
import java.text.AttributedCharacterIterator;
import java.util.Random;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JSeparator;
import javax.swing.JTextField;

public class Game2048 extends JPanel {
	int array[][]=new int[4][4];
	private Random rand=new Random();
	private int score;
	private JTextField jte=new JTextField("得分:");
	private JTextField jte1=new JTextField("最高分:");
	private JButton jbu=new JButton("START");
	private boolean flag=true;
	
	public static void main(String[] args) {
		Game2048 game =new Game2048();
		game.initUI();
		
	}
	
	public void initUI(){
		JFrame jf=new JFrame();
		jf.setTitle("那些年我们追过的脸萌");
		jf.setSize(435, 560);
		jf.setDefaultCloseOperation(3);
		jf.setLocationRelativeTo(null);
		jf.setLayout(new BorderLayout());
		initNorth(jf);
		initSouth(jf);
		initMenu(jf);	
		this.setBackground(Color.WHITE);
		jf.add(this,BorderLayout.CENTER);
		jf.setVisible(true);
		this.setFocusable(true);
		Graphics g=this.getGraphics();
		GameListener lis=new GameListener(this,g,array,jte,jte1);
		this.addKeyListener(lis);
		jbu.addActionListener(lis);
	}
	
	private void drawBackground(Graphics g){
		g.setColor(new Color(255,155,255));
		g.fillRoundRect(5, 5,410,410, 15, 15);
		g.setColor(new Color(255,181,255));
		for(int i=0;i<4;i++)
			for(int j=0;j<4;j++)
				g.fillRoundRect(15+j*100,15+i*100,90,90, 15, 15);
				
	}
	
	private void drawRC(){
		int	name1=(rand.nextInt(2)+1)*2;
		int	name2=(rand.nextInt(2)+1)*2;
		int r1=rand.nextInt(4);
		int c1=rand.nextInt(4);
		int r2=rand.nextInt(4);
		int c2=rand.nextInt(4);		
		while(r1==r2&&c1==c2){
		 r2=rand.nextInt(4);
		 c2=rand.nextInt(4);
		}
		array[r1][c1]=name1;
		array[r2][c2]=name2;
		System.out.println(r1 + "   " + c1);
		System.out.println(r2 + "   " + c2);
	}
	
	private void drawImage(Graphics g){
		for(int r=0;r<4;r++){
			for(int c=0;c<4;c++){
				if(array[r][c]!=0){
				Image image=new ImageIcon(this.getClass().getResource(array[r][c]+".jpg")).getImage();
				g.drawImage(image,15+c*100, 15+r*100,90,90, null);
				}
			}
		}
	}
	
	public void paint(Graphics g){
		super.paint(g);
		drawBackground(g);
		if(flag){
			drawRC();
			flag=false;
		}
		drawImage(g);
	}
	
	public void setFlag(boolean flag){
		this.flag=flag;
	}
	
	public void initNorth(JFrame jf){
		JPanel jpanel=new JPanel();
		jpanel.setBackground(new Color(255,155,255));	
		jte.setPreferredSize(new Dimension(100, 30));
		jte.setEditable(false);
		jpanel.add(jte);
		jte.setFocusable(false);
		jte1.setPreferredSize(new Dimension(100, 30));
		jte1.setEditable(false);
		jpanel.add(jte1);
		jte1.setFocusable(false);
		jf.add(jpanel,BorderLayout.NORTH);
	}
	
	public void initSouth(JFrame jf){
		JPanel jpanel=new JPanel();
		jpanel.setBackground(new Color(255,155,255));
		jpanel.add(jbu);
		jbu.setFocusable(false);
		jf.add(jpanel,BorderLayout.SOUTH);
	}
	
	public void initMenu(JFrame jf){
		JMenuBar jme=new JMenuBar();
		String [] array={"文件","编辑","查看","帮助"};
		String [][] arrayItem={{"新建","打开","保存"},{"撤销","重复","剪切"},{"工具箱","颜料盒"},{"帮助主题","关于2048"}};
		for (int i=0;i<array.length;i++){
			JMenu jm=new JMenu(array[i]);
			for(int j=0;j<arrayItem[i].length;j++){
				if(!arrayItem[i][j].equals("")){
					JMenuItem jmenu=new JMenuItem(arrayItem[i][j]);
					jm.add(jmenu);}
					else{
						JSeparator separ = new JSeparator();
						jme.add(separ);
				}
			}
			jme.add(jm);
		}
		jf.setJMenuBar(jme);
	}
}

 

       在功能的实现方面,我们需要考虑事件的监听及游戏实现的算法。事件里的事件源是你的动作发生所

在的组件上,事件监听器的添加方法是add**Listener(**Listener l),事件处理类是接口的子类,因

为接口不能创建对象,并且要实现事件处理类的所有方法,其中需要重写动作监听方法,从而获取开

始按钮信息并设置开始,以及设置分数、显示分数情况。根据简单的游戏规则,也就是1、开始时随机

出现两个分数为2或4的图片2、按下键盘的上下左右键所有的图片随之移动,并且碰到相邻且相同的图

片可以相加形成相应分数的图片,判断如果有相加或者移动就再随机生成一张分数为2或4的图片3、相

加后要设置分数的改变4、判断如果出现分数为2048的图片则跳出文本框提示玩家已经胜利了5、判断

如果所有格子都已经满了,且相邻的所有格子都无法相加,则跳出文本框提示玩家已经输了,可以重

新开始。移动和相加部分是该游戏的精髓,所以进简单分析一下:如果是先移动再相加就会出现一个

问题,就是相加完之后还需要再移动一次,才能保证上下左右键正常工作,所以我们采取先相加再移

动的策略。先判断当前格子是否不为0,如果不为0则判断是否相同再相加,不过这会出现一个问题,

就是相邻的格子为0,但是再下一个格子与之相同,所以应该先判断相邻是否为空,如果为空则循环继

续,如果不为空则判断是否相同,如果相同便可以相加,如果不同则跳出循环;然后是移动问题,移

动主要根据上下左右键,通过循环判断相应的下一个格子是否为空,如果是空的格子则可以移动,也

就是交换格子的内容。最后再提几个注意点:第一,应该写一个构造函数,从而可以传递界面的一些

参数;第二,可以设置标志位boolean flag = false来判断是否有移动或者相加情况,从而选择是否

继续执行一些方法;第三,判断是否失败的方法中,需要判断两种情况,也就是格子是否都满了和是

否不能再移动了,第一种情况中可以通过循环判断每个格子是否都不为0,然后再用一个计数器来累积

判断次数,如果有16次也就是符合情况了,第二种情况中可以判断左上角的9个格子中与右边及下面相

邻的格子是否有相同的,再判断第四列与下面相邻的格子中是否有相同的和第四行中与下面相邻的格

子中是否有相同的,同样给一个计数器,如果最总计数结果为0次,则已经不能再移动,如果两种情况

同时成立,则输了(这是顾大神教我的)。

import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.Random;
import javax.swing.ImageIcon;
import javax.swing.JOptionPane;
import javax.swing.JTextField;

public class GameListener implements KeyListener, ActionListener {
	private Graphics g;
	private int[][] array;
	private Game2048 a;
	private boolean flag = false;
	private JTextField jte,jte1;
	public int count=0;
	private int max_score;
	private Random rand = new Random();
	
	public GameListener(Game2048 a, Graphics g, int[][] array, JTextField jte,JTextField jte1) {
		this.a = a;
		this.g = g;
		this.array = array;
		this.jte = jte;
		this.jte1 = jte1;
	}

	public void actionPerformed(ActionEvent e) {
		if (e.getActionCommand().equals("START")) { // e.getSource()返回的是一个对象(事件源)
			start();
			jte.setText("得分:"+count);
		}
	}

	public void start() {
		for (int i = 0; i < 4; i++) {
			for (int j = 0; j < 4; j++) {
				array[i][j] = 0;
			}
		}
		a.setFlag(true);
		a.paint(g);
	}

	public void keyTyped(KeyEvent e) {
	}

	public void keyPressed(KeyEvent e) {
	}

	private void randomAC() {
		Random rand = new Random();
		int name = (rand.nextInt(2) + 1) * 2;
		int r = rand.nextInt(4);
		int c = rand.nextInt(4);
		while (array[r][c] != 0) {
			r = rand.nextInt(4);
			c = rand.nextInt(4);
		}
		array[r][c] = name;
	}
	
	public void stop(){
		int t=0;
		int p=0;
		for (int i = 0; i < 4; i++) {
			for (int j = 0; j < 4; j++) {
				if(array[i][j]!=0){
					t++;
				}
			}
		}
		for(int r=0;r<3;r++){
			for(int c=0;c<3;c++){
				if(array[r][c]==array[r][c+1]&&array[r][c]!=0){
					p++;}
				if(array[r][c]==array[r+1][c]&&array[r][c]!=0){
				p++	;}
			}
		}
		for(int r=0;r<3;r++){
			if(array[r][3]==array[r+1][3]&&array[r][3]!=0)	{
				p++;}
		}
		for(int c=0;c<3;c++){
			if(array[3][c]==array[3][c+1]&&array[3][c]!=0){
				p++;}
		}
		if(t==16&&p==0){
			JOptionPane.showMessageDialog(a, "您输了");
			if(count>max_score){
				max_score=count;
				count=0;
				jte1.setText("最高分"+max_score);
			}else if(count<max_score){
				count=0;
			}
			for (int r = 0; r < 4; r++) {
				for (int c = 0; c < 4; c++) {
					array[r][c] = 0;
				}
			}
		}
	}
	
	public void keyReleased(KeyEvent e) {
		stop();
		int keyCode = e.getKeyCode();
		switch (keyCode) {
		case 37:// 左键
			relLeft();
			int t=0;
			if (flag) {
				for (int i = 0; i < 4; i++) {
					for (int j = 0; j < 4; j++) {
						if(array[i][j]!=0){
							t++;
						}
					}
				}
				if(t!=16){
					randomAC();
					a.repaint();
				}			
					jte.setText("得分:"+count);		
			}
			break;
		case 38:// 上键
			relUp();
			int b=0;
			if (flag) {
				for (int i = 0; i < 4; i++) {
					for (int j = 0; j < 4; j++) {
						if(array[i][j]!=0){
							b++;
						}
					}
				}
				if(b!=16){
					randomAC();
					a.repaint();
				}	
					jte.setText("得分:"+count);		
			}
			break;
		case 39:// 右键
			relRight();
			int p=0;
			if (flag) {
				for (int i = 0; i < 4; i++) {
					for (int j = 0; j < 4; j++) {
						if(array[i][j]!=0){
							p++;
						}
					}
				}
				if(p!=16){
					randomAC();
					a.repaint();
				}	
					jte.setText("得分:"+count);		
			}
			break;
		case 40:// 下键
			relDown();
			int q=0;
			if (flag) {
				for (int i = 0; i < 4; i++) {
					for (int j = 0; j < 4; j++) {
						if(array[i][j]!=0){
							q++;
						}
					}
				}
				if(q!=16){
					randomAC();
					a.repaint();
				}	
					jte.setText("得分:"+count);		
			}
			break;
		}
		if(count==2048){
			JOptionPane.showMessageDialog(a, "您的分数达到2048,您赢了");
		}
	}
	
	public void relLeft() {
		for (int r = 0; r < 4; r++) {
			for (int c = 0; c < 4; c++) {
				if (array[r][c] != 0) {
					for (int c1 = c + 1; c1 < 4; c1++) {
						if (array[r][c1] == 0) {
							continue;
						} else if (array[r][c] == array[r][c1]) {
							array[r][c] += array[r][c1];
							array[r][c1] = 0;
							count+=array[r][c];
							flag = true;
						} else if (array[r][c] != array[r][c1]) {
							break;
						}
					}
				}
			}
		}
		for (int r = 0; r < 4; r++) {
			for (int c = 0; c < 4; c++) {
				if (array[r][c] == 0) {
					for (int c1 = c + 1; c1 < 4; c1++) {
						if (array[r][c1] != 0) {
							array[r][c] = array[r][c1];
							array[r][c1] = 0;
							c++;
							flag = true;
						}
					}
				}
			}
		}
	}
	
	public void relRight() {
		for (int r = 0; r < 4; r++) {
			for (int c = 3; c >=0; c--) {
				if (array[r][c] != 0) {
					for (int c1 = c - 1; c1 >=0; c1--) {
						if (array[r][c1] == 0) {
							continue;
						} else if (array[r][c] == array[r][c1]) {
							array[r][c] += array[r][c1];
							array[r][c1] = 0;
							count+=array[r][c];
							flag = true;
						} else if (array[r][c] != array[r][c1]) {
							break;
						}
					}
				}
			}
		}
		for (int r = 3; r >= 0; r--) {
			for (int c = 3; c >= 0; c--) {
				if (array[r][c] == 0) {
					for (int c1 = c - 1; c1 >= 0; c1--) {
						if (array[r][c1] != 0) {
							array[r][c] = array[r][c1];
							array[r][c1] = 0;
							c--;
							flag = true;
						}
					}
				}
			}
		}
	}

	public void relDown() {
		for (int c = 0; c <4; c++) {
			for (int r = 3; r >=0; r--) {
				if (array[r][c] != 0) {
					for (int r1 = r - 1; r1 >=0; r1--) {
						if (array[r1][c] == 0) {
							continue;
						} else if (array[r][c] == array[r1][c]) {
							array[r][c] += array[r1][c];
							array[r1][c] = 0;
							count+=array[r][c];
							flag = true;
						} else if (array[r][c] != array[r1][c]) {
							break;
						}
					}
				}
			}
		}
		for (int c = 3; c >= 0; c--) {
			for (int r = 3; r >= 0; r--) {
				if (array[r][c] == 0) {
					for (int r1 = r - 1; r1 >= 0; r1--) {
						if (array[r1][c] != 0) {
							array[r][c] = array[r1][c];
							array[r1][c] = 0;
							r--;
							flag = true;
						}
					}
				}
			}
		}
	}

	public void relUp() {
		for (int c = 0; c <4; c++) {
			for (int r = 0; r <4; r++) {
				if (array[r][c] != 0) {
					for (int r1 = r + 1; r1 <4; r1++) {
						if (array[r1][c] == 0) {
							continue;
						} else if (array[r][c] == array[r1][c]) {
							array[r][c] += array[r1][c];
							array[r1][c] = 0;
							count+=array[r][c];
							flag = true;
						} else if (array[r][c] != array[r1][c]) {
							break;
						}
					}
				}
			}
		}
		for (int c = 0; c < 4; c++) {
			for (int r = 0; r < 4; r++) {
				if (array[r][c] == 0) {
					for (int r1 = r + 1; r1 < 4; r1++) {
						if (array[r1][c] != 0) {
							array[r][c] = array[r1][c];
							array[r1][c] = 0;
							r++;
							flag = true;
						}
					}
				}
			}
		}
	}
}

 

1
0
评论 共 2 条 请登录后发表评论
2 楼 夜神月 2015-04-07 17:58
一点价值都木有
1 楼 dsjt 2015-04-07 10:15
脸盲杀手!!

发表评论

您还没有登录,请您登录后再发表评论

相关推荐

  • 2021年总结:缘起性空,归来不少年——回顾这荆棘的一年

    2021年已经离去,感谢大家的陪伴和帮助,感谢家人的鼓励。转眼,这已是我在CSDN写下的第九篇年终总结,真是岁月如梭。《缘起性空,归来不少年》。是啊,归来不再少年,我已经是而立之年了。当我写下这几个字的时候,...

  • 科研萌新成长记18——我所见到的世界

    开学一个月,其实开学才一个月,但是这漫长的一个...被交警叫停,因为我们在路上犹豫了一下要不要转弯导致车差不多停下来了,交警追着我们的车叫停我们确认我们有驾照;进了好多次医院;警察上门找……经历不要太丰富。

  • 幸存者偏差——讨论死在中国游戏圈的一百万种方式

    然后经过少则几周多则几个月的山寨期,这匹改头换面的黑马便屁股上盖着一“中国心,中国货”的戳儿咴咴地出栏了——这也正是现如今为什么我们偶然间看到日韩的主流热门游戏时,总有种似曾相识之感的原因。...

  • OSChina 周六乱弹 —— 妹子和游戏哪个更好玩

    (萌新好)@ clouddyy (这么行?总感觉那玩意怪脑残的,一阵阵的吧。)@ nnnm (嚎 ,我老觉得会养植物的都怪厉害的。我四叔会养植物。我爹养过小狗,后来跑没了,又养了一只因为不会作揖给送走了。我仔细的...

  • OSChina 周二乱弹 ——追妹子最管用的方式

     : 火车票抢不到,飞机票太贵了,和女朋友两个人回家过个三五天的年成本上万,都不想回家过年了呢,感觉为了过年而过年好没意思呢。 对呀,现在票这么贵了。 本来挣钱不容易, 到了年底,还要被票价宰一...

  • OSChina 周二乱弹 ——在影楼工作的妹子,可追不?

    实际上,除了特别的空间之外,这家全国首个工程师主题咖啡店还提供程序员专属咖啡——Apsara咖啡 Apsara咖啡有着阿里云logo的拉花,相比通常的咖啡更浓缩,同时味道更苦一些。Costa咖啡师表示:“为了定制符合...

  • C++剧情游戏《人类末日·丧尸危机》

    这个游戏有很多坑哦,其他就没什么要注意的啦。 你不要以为你以为的就是对的! 有些关卡不能通关纯属运气!!!最多10次就可以通关啦!!! 代码在哪里? #include #include using namespace std; int x;//判断均用 ...

  • leetcode学习——求职注意事项

    这里记录了求职前和求职时需要注意和了解的一些知识。主要分为三个部分即简历怎么写、大厂面试流程、几个城市互联网公司的介绍(北京、上海、深圳、广州...可以在准备求职前将本章内容过一遍,后面也会增加相应的内容。

  • APP——List

    ', '浙江移动手机营业厅', '王者荣耀攻略助手', '得到', '小小英雄-吃鸡过大年', '宝宝医院', '俄罗斯方块', '史上最坑爹的游戏16', '马蜂窝旅游', '知音漫客-免费漫画', '企鹅FM-听小说', '最美自拍', '平安金管家'...

  • 小萌库 - 精品游戏精彩回顾

    小萌库(www.xiaomengku.com) 精品游戏精彩回顾 《海岛大亨5》中文版 免安装硬盘版《海岛大亨5》是由美国的PopTop Software / FrogCity开发的海岛大亨系列第五部作品。由Gathering of Developers发行。 在继...

  • OSChina 周六乱弹 ——我们能算儿童票么?

    我曾在淘宝写过一段时间代码,2012年在一家百强民企做电商副总,当时在极为艰苦的条件下带队开发了一个B2C网站,走支付宝和银联支付通道,年营业额千万级(当然实在太少了,我只是说这个网站投入了实际的运营)。...

  • 浅谈股价预测模型:全能大明星——神经网络模型

    图一:图片单个特征 但如果我们依然告诉小baby这是一只橘猫,而且可以随机给他看很多橘猫耳朵被遮住和不被遮住的图,小baby或许会明白耳朵是不是尖尖的猫耳朵不重要,关键是这只猫要萌。 好吧,关键是鼻子,嘴巴,...

  • 不思议迷宫c语言基础,不思议迷宫——新手入门所学

    本人玩游戏这个游戏有一段时间了,现在只得爬到到德古拉城堡 ,史莱姆累计今天也只有23个,是个实实在在的新手。不过呢,也因为同是新手,对新手也更有些发言权吧,大家可以互相交流,接下来谈一下我这段时间是怎么...

  • 2021年最新互联网大厂中秋礼盒PK!

    它们来源于心动Slogan“聚匠人心,动玩家情”,也寄托了他们的心意——心动历经十年,不断与人事物相遇,正是这一路的相遇与陪伴支持着他们继续探索这广袤的游戏宇宙。 京东 今年,京东中秋家礼与敦煌博物馆联名,由...

  • 2021年互联网大厂中秋礼盒PK!50多家一口气看完

    中秋节越来越近了,平日里,各大公司拼员工拼技术拼实力;到了节日,则要拼奖金、拼福利、拼假期,还要拼创意。程序猿为大家收集了各大互联网企业的月饼,让我们一起来看看今年的月饼哪家强:阿里巴巴首...

  • 计算机系女学霸男生追,杨紫李现解锁恋爱新姿势:吃最甜的糖,追最燃的梦

    原标题:杨紫李现解锁恋爱新姿势:吃最甜的糖,追最燃的... 该剧改编自墨宝非宝小说《蜜汁炖鱿鱼》,并由原著作者担任编剧,讲述了高智商学霸兼软萌少女佟年(杨紫饰)对热血男青年韩商言(李现饰)一见钟情,两人在不...

  • OSChina 周五乱弹 —— 动弹的起源

    :好几年前了,小区门口新开一小商店,准备追里面一收银小哥哥(贼帅!),每天都要去光顾好多次,每次都去买点不值钱的东西,然后装比拿100元让小哥哥找钱。 过了一段时间,他突然说话了:你是做什么的,天天上我这来...

  • java+sql server项目之科帮网计算机配件报价系统源代码.zip

    sql server+java项目之科帮网计算机配件报价系统源代码

Global site tag (gtag.js) - Google Analytics