⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 model.java

📁 java版的连连看游戏
💻 JAVA
📖 第 1 页 / 共 3 页
字号:
package model;

import java.awt.Point;
import java.util.ArrayList;
import java.util.Observable;
import java.util.Random;

import javax.swing.JOptionPane;

import login.*;

/**
 * 这个类实现了该游戏的核心算法,这是游戏的最重要的部分,就是判断图像的信息,在满足设定好的条件下相消.
 * 
 * @author : 李强,何明,何晓飞
 * @version : 2.0
 */
public class Model extends Observable {
	/* 要导进游戏界面的图片的对数 */
	public static final int CARD_NUMBERS = 70;

	/* 要导进游戏界面的每一类图片的总数 */
	private int PICTURE_NUMBERS ;

	/* 关数 */
	private int level;
	/*分数*/
    private int score;
    /* 剩余时间*/
	private int timeLeft;
	/* 将摆置图片的panel设置成12行20列,共240个格子 */
	private int rows = 12, cols = 20;// 改过

	/* 建立一个数组,用于记录每个格子的信息 */
	private int[][] data;

	/* 每个图片的导进去的位置信息存放在一个Point对象中,sltMatrix就是当前选中的图片Point */
	private Point sltMatrix;

	/* 纪录拐弯时的图片所对应的点的信息 */
	private Point corner1, corner2;

	/* 游戏的开始时间 */
	public long startTime;
	/*暂停时的时间*/
   public long pauseTime; 
   /*总共暂停了的时间*/
   public int pauseDuration=0;
	/* 剩余的图片数量 */
	private int cardLeft;

	/* 历史纪录 */
	private int historyRecord;

	/* 该线程用于定时的对界面进行更新功能 */
	private Thread t;

	/* 该线程用于示范功能 */
	private Thread demoThread;

	/* 是否处在演示模式的标志 */
	private boolean bdemo = false;

	/* 用于暂停的时候,作为是否处于暂停状态的标志 */
	public boolean bPlaying = true;

	/* 所选图片种类的文件夹名字 */
	private static String pictureFile;

	/* 已提示次数 */
	private int count;
	
	/*记录游戏开始时已使用的提示次数*/
	private int initCount;

	/* 所选音乐种类的文件夹名字 */
	private String musicFile;

	/* 点击声音 */
	private Sound clickSound;

	/* 连时声音 */
	private Sound linkSound;
	/*过关声音*/
	private Sound passSound;

	/* 纪录窗体位置 */
	private Point frameLocation;

	/**
	 * Model (构造函数)
	 */
	public Model() {
  
		pictureFile = "fruit"; // 设置游戏界面所用图片
		PICTURE_NUMBERS = 30;//设置游戏界面所用图片数量
		clickSound = new Sound(1);// 建立点击声音的对象
		linkSound = new Sound(2);// 建立连时声音的对象
		passSound=new Sound(3);//建立过关时声音的对象
		level = 1;//设置关数
		score =0;//设置分数
		timeLeft = 350;// 初始化剩余时间
		loadSet();
		// 建立了一个新的线程用于刷新游戏界面下面的状态栏,包括时间,所剩图片数量
		t = new Thread(new Runnable() {
			public void run() {
				while (true) {

					synchronized (t) {
						// 每隔一秒刷一次屏
						try {
							t.wait(500);//
						} catch (InterruptedException e) {
							e.printStackTrace();
						}
						if (bPlaying == true) {
							notifyTimer();
						}
					}
					// 假如时间超过剩余时间的话,重新开始或者退出游戏
					if (getTimeLeft()==getSeconds()) {
						int response = JOptionPane.showConfirmDialog(null,
								"你已经超过规定时间,是否重新开始游戏 ?\n点否直接退出游戏!",
								"  友情提示", JOptionPane.YES_NO_OPTION,
								JOptionPane.QUESTION_MESSAGE);
						if (response == JOptionPane.YES_OPTION) {
							restartGame();
						} else if(response==JOptionPane.NO_OPTION){
							System.exit(0);
						}
					}
				}
			}
		});
		t.start();// 线程开始
		gameStart();// 游戏开始
	}

	/**
	 * Model (构造函数) 无参构造函数,只用于构造一个简单的Model对象以调用它的loadSet方法初始化窗体的位置
	 */
	//public Model() {
		// 初始化frameLocation
	
//	}

	/**
	 * 设置图片种类
	 * 
	 * @param pFile
	 *            所选图片种类的文件夹名字
	 */
	public int setCount(int count) {

		this.count = count;
		return this.count;
	}

	/**
	 * 
	 * @return 提示次数
	 */
	public int getCount() {
		return count;
	}
	/**
	 * 
	 * @return 游戏开始时使用过的提示次数
	 */
   public int getInitCount(){
	   return initCount;
   } 
	/**
	 * 设置图片种类
	 * 
	 * @param pFile
	 *            所选图片种类的文件夹名字
	 */
	public void setPictureFile(String pFile) {
		pictureFile = pFile;
	}

	/**
	 * 得到图片种类
	 * 
	 * @return 所选图片种类的文件夹名字
	 */
	public String getPictureFile() {
		return pictureFile;
	}

	/**
	 * 设置音乐种类
	 * 
	 * @param pFile
	 *            所选音乐种类的文件夹名字
	 */
	public void setMusicFile(String mFile) {
		musicFile = mFile;
	}

	/**
	 * 得到音乐种类
	 *
	 * 
	 * @return 所选音乐种类的文件夹名字
	 */
	public String getMusicFile() {
		return musicFile;
	}

	/**
	 * 设置级数
	 * 
	 * @param i
	 *            关数
	 */
	public void setLevel(int i) {
		level = i;
	}

	/**
	 * 得到关数
	 * 
	 * @return 关数
	 */
	public int getLevel() {
		return level;
	}
	public int getScore(){
		return score;
	}
	public void setScore(int s){
		score=s;
	}
	/**
	 * 
	 * @return 图片数量
	 */
	public int getPictureNumber(){
		return PICTURE_NUMBERS;
	}
    /**
     * 
     * @param pn 图片数量
     */
    public void setPictureNumber(int pn){
    	PICTURE_NUMBERS=pn;
    } 
	/**
	 * 设置窗体的位置信息
	 */
	private void loadSet() {
		frameLocation = LoadAndSave.loadLocation();
	}

	/**
	 * 假如取消单击右键的话,调用此方法已取消当前的选择
	 */
	public void cancelSelect() {
		sltMatrix = null;
		updateAll();
	}

	/**
	 * 判断两个图片是否能连
	 * 
	 * @param Point,
	 *            Point 每个图片位置信息由一个Point存放 p1, p2
	 * @return boolean 返回一个boolean值说明是否可消
	 */
	private boolean canDelete(Point p1, Point p2) {
		// 初级的判断是否可连(包括位置一样的不能连,位置上的图片不一样,位置上的图片为空)
		// 这些是最基本的判断,要不满足就直接返回False
		if (p1.equals(p2) || data[p1.x][p1.y] != data[p2.x][p2.y]
				|| data[p1.x][p1.y] == 0 || data[p2.x][p2.y] == 0)
			return false;
		corner1 = null;//
		corner2 = null;//
		// 高级的判断是否可连(包括直线连,有一个弯连,有两个弯连)
		// 可连的判断
		if (noCorner(p1, p2) || oneCorner(p1, p2) || twoCorner(p1, p2))
			return true;
		else
			return false;
	}

	/**
	 * 当监听MouseEvent事件的话,进行各种情况的判断以知道是否可连
	 * 
	 * @param p
	 *            所点的图片对应的Point对象
	 */
	public void clickMatrix(Point p) {
		// 初级的判断(包括越界,是否在游戏中和所点位置是否有图片,即data数组中队应的0点)
		if (p.x < 0 || p.y < 0 || p.x >= rows || p.y >= cols)
			return;
		// 假如图片为空,退出
		if (isEmpty(p))
			return;
		// 根据前后两次点的进行可消性判断
		if (null == sltMatrix) {// 看在点击此图片的时候,前面是否已经点了一个图片了,如果没有那么就把刚点的这个图赋给纪录前一次点击图片的点
			sltMatrix = p;
			clickSound.play(1);// 这要加上音乐
		} else if (canDelete(sltMatrix, p)) {
			delete(sltMatrix, p, true);// 如果前面已经点了一个图片的话,那么就进行可消性判断
			sltMatrix = null;// 如果能消了就复原
		} else {
			sltMatrix = p;// 如果消不了的话,将当前所点的图片换成第一次所点的图片
			clickSound.play(1);// 加上音乐
		}
		// 假如所剩余的图片的为0个,进行相应的处理
		if (cardLeft == 0) {
			LoadAndSave.saveRecord(getSeconds(),getLevel());// 纪录时间
			if (getSeconds() < historyRecord) {// 判断是否你打破了纪录,如果你打破了纪录,将会让你只知道,并将这个新的纪录写入文件
				notifyBreakRecord();
				historyRecord = getSeconds();
			}
			if (!bdemo) {// 只让它演示本关
				passSound.play(1);	
				level++;
			}
			notifyLevel();// 刷新关数
			gameStart();// 重新开始
		}
		// 判断是否有解,无解自动刷新
		if (solutionCount() == 0) {
			refresh();
		}
		updateAll();// 刷新
	}

	/**
	 * 这里特别说明一下,我们用的是java设计模式-监听模式,来搭起整个程序的大的框架
	 */
	private void notifyBreakRecord() {
		setChanged();// 设置一个内部标志位注明数据发生了变化
		notifyObservers("breakrecord");// 调用一个列表中所有的Observer的update()方法,通知它们数据发生了变化
	}

	/**
	 * 假如无解则自动调用Observer的update()方法,传参"nosolution"
	 */
	private void notifyNoSolution() {
		setChanged();
		notifyObservers("nosolution");
	}

	/**
	 * 假如结束则自动调用Observer的update()方法,传参"demofinished"
	 */
	private void notifyDemoFinished() {
		setChanged();
		notifyObservers("demofinished");
	}

	/**
	 * 假如过关则自动调用Observer的update()方法,传参"level"
	 */
	public void notifyLevel() {
		setChanged();
		notifyObservers("level");
	}

	/**
	 * 消一个图片
	 * 
	 * @param Point
	 *            要消的图片
	 */
	private void delete(Point p) {
		data[p.x][p.y] = 0;
		cardLeft--;
		timeLeft++;//消一张图片奖励1秒
		score+=5;
		linkSound.play(1);// 连时加上声音
		updateAll();// 更新整个
	}

	/**
	 * 相消
	 * 
	 * @param Point,Point,boolean
	 *            p1, p2前后所点的两个点,第三个参数能表明是相消还是提示
	 */
	private void delete(Point p1, final Point p2, boolean bDelete) {
		// 建立一个ArrayList将showpath()方法的所需参数加进去
		ArrayList<Point> points = new ArrayList<Point>();
		// 没有拐弯,就是直线连,直接将两个图片加紧去就行了
		if (corner1 == null) {

			points.add(p1);
			points.add(p2);

		} else if (corner2 == null) {// 拐了一个弯,除了要将两个要连的图片加进去,还要将第一个拐弯点加进去

			points.add(p1);
			points.add(corner1);
			points.add(p2);

		} else {// 拐两个弯的情况,将拐弯点和所连的信息全加进去

			if (p1.x != corner1.x && p1.y != corner1.y) {
				Point pt = corner1;
				corner1 = corner2;
				corner2 = pt;
			}
			points.add(p1);
			points.add(corner1);
			points.add(corner2);
			points.add(p2);

		}
		notifyEffect(points);
		// bDelete其实就是判断它是在给你提示,还是你要真正的连
		if (bDelete) {
			delete(p1);
			delete(p2);
			// 根据level来判断连完图片后其他图片应该做怎样的调整,下面是那4关的调用
			switch (level) {
			case 1:
				level1();
				break;
			case 2:
				level2(p1, p2);
				break;
			case 3:
				level3(p1, p2);
				break;
			case 4:
				level4(p1, p2);
				break;
			case 5:
				level5(p1,p2);
				break;
			default:
				break;
			}
		}
	}

	public int getCols() {
		return cols;
	}

	/**
	 * 垂直的寻找,返回一个路径(包括这个路径上的所有的点)
	 * 
	 * @param p
	 *            原点
	 * @return 纵向空白点(包括与原点等值的点)
	 */
	private ArrayList<Point> getHSpaces(Point p, Point pg) {
		ArrayList<Point> ps = new ArrayList<Point>();
		// left
		for (int dif = 1;; dif++) {
			int col = p.y - dif;
			int row = p.x;
			// 向左走,如果左边的不为0且它与p2不相等,则下面if中的条件为真,退出,否则加进数祖
			if (col < 0
					|| (data[row][col] != 0 && !pg.equals(new Point(row, col))))
				break;
			ps.add(new Point(row, col));
		}
		// right
		for (int dif = 1;; dif++) {
			int col = p.y + dif;
			int row = p.x;
			// 向右走,如果右边的不为0且它与p2不相等,则下面if中的条件为真,退出,否则加进数祖
			if (col >= cols
					|| (data[row][col] != 0 && !pg.equals(new Point(row, col))))
				break;
			ps.add(new Point(row, col));
		}
		return ps;
	}

	/**
	 * @return 返回纪录图片的数组信息
	 */
	public int[][] getMaps() {
		return data;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -