J2ME连连看基础功能源代码(含详细注释)
作者:陈跃峰
出自:http://blog.csdn.net/mailbomb
//界面类代码
import javax.microedition.lcdui.Canvas;
import javax.microedition.lcdui.Graphics;
/**
* 连连看游戏界面
*/
public class LinkCanvas extends Canvas implements Runnable{
/**游戏逻辑类*/
GameEngine engine;
/**屏幕宽度*/
int width;
/**屏幕高度*/
int height;
public LinkCanvas(){
//创建对象
engine = new GameEngine();
//获得屏幕的高度和宽度
width = getWidth();
height = getHeight();
//启动线程
Thread t = new Thread(this);
t.start();
}
/**
* 绘制方法
*/
protected void paint(Graphics g) {
//清屏
clearScreen(g);
//绘制地图
engine.paintMap(g);
//绘制选择框
engine.paintSelectArea(g);
//绘制连线
engine.paintLinkLine(g);
}
/**
* 清屏方法
* @param g 画笔
*/
private void clearScreen(Graphics g){
g.setColor(0xffffff);
g.fillRect(0, 0, width, height);
g.setColor(0);
}
public void keyPressed(int keyCode){
int action = getGameAction(keyCode);
switch(action){
case UP:
engine.moveUP();
break;
case DOWN:
engine.moveDown();
break;
case LEFT:
engine.moveLeft();
break;
case RIGHT:
engine.moveRight();
break;
case FIRE:
engine.fire();//选择块
break;
}
}
public void run() {
try{
while(true){
//延时
Thread.sleep(100);
//每次判断逻辑
engine.action();
repaint();
}
}catch(Exception e){
e.printStackTrace();
}
}
}
//逻辑类源代码
import java.util.*;
import javax.microedition.lcdui.*;
/**
* 游戏数据和逻辑类
*/
public class GameEngine {
/**选中块的个数*/
private int selectTileNum = 0;
//第一个选择块的行号和列号
/**行号*/
private int firstRow;
/**列号*/
private int firstCol;
//第二个选择块的行号和列号
/**行号*/
private int secondRow;
/**列号*/
private int secondCol;
//当前选择框,默认在左上角
/**当前选择框的行号*/
private int cRow;
/**当前选择框的列号*/
private int cCol;
/**最大行数*/
private final int MAX_ROW = 10;
/**最大列数*/
private final int MAX_COL = 10;
/**地图数据,0代表空,数据1-10分别代表十种不同的结构*/
private int[][] map = new int[MAX_ROW][MAX_COL];
/**随机数对象*/
private Random ran = new Random();
//地图区域左上角的坐标
private final int LEFTX = 20;
private final int LEFTY = 50;
/**每个单元格的宽度*/
private final int TILE_WIDTH = 20;
/**每个单元格的高度*/
private final int TILE_HEIGHT = 20;
/**连线类型*/
private int linkType;
/**无法连线*/
private final int NO_LINK = 0;
/**水平连线*/
private final int H_LINK = 1;
/**垂直联系*/
private final int V_LINK = 2;
/**一个拐点,先移动x*/
private final int ONE_CORNER_FIRSTX = 3;
/**一个拐点,先移动y*/
private final int ONE_CORNER_FIRSTY = 4;
/**两个拐点,待完善*/
private final int TWO_CORNER = 5;
/**
* 两次拐弯的行号和列号
* 数据格式为:
* 第一个拐点的行号,第一个拐点的列号,第二个拐点的行号,第二个拐点的列号
*/
int[] p = new int[4];
public GameEngine(){
//初始化地图数据
initMap();
}
/**
* 初始化地图数据
*/
private void initMap(){
for(int row = 0;row < map.length;row++){
for(int col = 0;col < map[row].length;col++){
map[row][col] = row + 1;
}
}
//循环打乱10次
int tempRow;
int tempCol;
int temp;
for(int i = 0;i < 10;i++){
for(int row = 0;row < map.length;row++){
for(int col = 0;col < map[row].length;col++){
//随机行号
tempRow = Math.abs(ran.nextInt() % 10);
//随机列号
tempCol = Math.abs(ran.nextInt() % 10);
//如果不是同一个单元格,则交换数据
if(!((tempRow == row) && (tempCol == col))){
temp = map[row][col];
map[row][col] = map[tempRow][tempCol];
map[tempRow][tempCol] = temp;
}
}
}
}
}
/**
* 绘制地图数据
* @param g 画笔
*/
public void paintMap(Graphics g){
for(int row = 0;row < map.length;row++){
for(int col = 0;col < map[row].length;col++){
//如果没有数据,则跳过
if(map[row][col] == 0){
continue;
}else{//绘制方块
//绘制方框
g.drawRect(LEFTX + col * TILE_WIDTH, LEFTY + row * TILE_HEIGHT, TILE_WIDTH, TILE_HEIGHT);
//绘制数字
g.drawString(String.valueOf(map[row][col]), LEFTX + col * TILE_WIDTH + 5,
LEFTY + row * TILE_HEIGHT + 4,
Graphics.TOP | Graphics.LEFT);
}
}
}
}
/**
* 绘制选择框
* @param g 画笔
*/
public void paintSelectArea(Graphics g){
//绘制当前选择框
g.setColor(0xff00);
g.drawRect(LEFTX + cCol * TILE_WIDTH, LEFTY + cRow * TILE_HEIGHT, TILE_WIDTH, TILE_HEIGHT);
g.setColor(0);
//绘制选中项
switch(selectTileNum){
case 1: //选择一个
g.setColor(0xff0000);
g.drawRect(LEFTX + firstCol * TILE_WIDTH, LEFTY + firstRow * TILE_HEIGHT, TILE_WIDTH, TILE_HEIGHT);
g.setColor(0);
break;
case 2: //选中两个
g.setColor(0xff0000);
g.drawRect(LEFTX + firstCol * TILE_WIDTH, LEFTY + firstRow * TILE_HEIGHT, TILE_WIDTH, TILE_HEIGHT);
g.drawRect(LEFTX + secondCol * TILE_WIDTH, LEFTY + secondRow * TILE_HEIGHT, TILE_WIDTH, TILE_HEIGHT);
g.setColor(0);
break;
}
}
/**
* 绘制方块连线
* @param g 画笔
*/
public void paintLinkLine(Graphics g){
//如果无连线,则直接返回
if(linkType == NO_LINK){
return;
}
//根据连线类型实现绘制
//绘制到方块的中心点
switch(linkType){
case H_LINK://水平
case V_LINK://垂直
paintLine(g,firstRow,firstCol,secondRow,secondCol);
break;
case ONE_CORNER_FIRSTX://一个拐弯,先移动X
//水平线
paintLine(g,firstRow,firstCol,firstRow,secondCol);
//垂直线
paintLine(g,firstRow,secondCol,secondRow,secondCol);
break;
case ONE_CORNER_FIRSTY://一个拐弯,先移动Y
//水平线
paintLine(g,firstRow,firstCol,secondRow,firstCol);
//垂直线
paintLine(g,secondRow,firstCol,secondRow,secondCol);
break;
case TWO_CORNER:
//块1到第一个拐点的连线
paintLine(g,firstRow,firstCol,p[0],p[1]);
//两个拐点之间的连线
paintLine(g,p[0],p[1],p[2],p[3]);
//第二个拐点到块2的连线
paintLine(g,p[2],p[3],secondRow,secondCol);
break;
}
//逻辑代码,清除连接类型
linkType = NO_LINK;
}
/**
* 绘制两个方块中心点的连线
* @param g 画笔
* @param r1 方块1的行号
* @param c1 方块1的列号
* @param r2 方块2的行号
* @param c2 方块2的列号
*/
private void paintLine(Graphics g,int r1,int c1,int r2,int c2){
g.drawLine(LEFTX + c1 * TILE_WIDTH + TILE_WIDTH/2,
LEFTY + r1 * TILE_HEIGHT + TILE_HEIGHT/2,
LEFTX + c2 * TILE_WIDTH + TILE_WIDTH/2,
LEFTY + r2 * TILE_HEIGHT + TILE_HEIGHT/2);
}
/**
* 向左移动选择框
*/
public void moveLeft(){
if(cCol > 0){
cCol--;
}
}
/**
* 向右移动选择框
*/
public void moveRight(){
if(cCol < MAX_COL -1){
cCol++;
}
}
/**
* 向上移动选择框
*/
public void moveUP(){
if(cRow > 0){
cRow--;
}
}
/**
* 向下移动选择框
*/
public void moveDown(){
if(cRow < MAX_ROW - 1){
cRow++;
}
}
/**
* 确定键逻辑处理
*/
public void fire(){
//如果选择的块为空,则直接返回
if(map[cRow][cCol] == 0){
return;
}
//选中的块的数量增加1
selectTileNum++;
//判别存储位置
switch(selectTileNum){
case 1: //第一次选择
firstRow = cRow;
firstCol = cCol;
break;
case 2: //第二次选择
//选择同一个块,2个选择块都失去选中
if((firstRow == cRow) && (firstCol == cCol)){
selectTileNum = 0;
return;
}
secondRow = cRow;
secondCol = cCol;
break;
}
}
/**
* 判断(r1,c1)块和(r2,c2)块中间是否为空行
* 不包含这两个块
* @param r1 块1的行号
* @param c1 块1的列号
* @param r2 块2的行号
* @param c2 块2的列号
* @return true代表为空,false代表不为空
*/
private boolean isEmptyRow(int r1,int c1,int r2,int c2){
//判断是否位于同一行
if(r1 != r2){
return false;
}
//判断两个块的相对位置
if(c1 > c2){ //第一块位于右侧
for(int col = c1 - 1;col > c2;col--){
//如果有非空块
if(map[r1][col] != 0){
return false;
}
}
}else{ //第一块位于左侧
for(int col = c2 - 1;col > c1;col--){
//如果有非空块
if(map[r1][col] != 0){
return false;
}
}
}
return true;
}
/**
* 判断块(r1,c1)和块(r2,c2)之间是否是空列
* 不包含这两个块
* @param r1 块1的行号
* @param c1 块1的列号
* @param r2 块2的行号
* @param c2 块2的列号
* @return true代表为空,false代表不为空
*/
private boolean isEmptyCol(int r1,int c1,int r2,int c2){
//判断是否位于同一列
if(c1 != c2){
return false;
}
//判断两个块的相对位置
if(r2 > r1){//第一个块在上方
for(int row = r1 + 1;row < r2;row++){
//如果有非空块
if(map[row][c1] != 0){
return false;
}
}
}else{//第二个块在上方
for(int row = r2 + 1;row < r1;row++){
//如果有非空块
if(map[row][c1] != 0){
return false;
}
}
}
return true;
}
/**
* 判断一个块是否为空
* @param r 块的行号
* @param c 块的列号
* @return true代表为空,false代表不空
*/
private boolean isEmptyCell(int r,int c){
return map[r][c] == 0;
}
/**
* 是否是一次转弯实现连线
* @return NO_LINK代表没有连线,其他值代表对应的连线类型
*/
private int isOneCornerLink(int r1,int c1,int r2,int c2){
//先移动行,再移动列
if(isEmptyCell(r1,c2)){ //转折点为空
if(isEmptyRow(r1,c1,r1,c2) & isEmptyCol(r1,c2,r2,c2)){
return ONE_CORNER_FIRSTX;
}
}
//先移动列,再移动行
if(isEmptyCell(r2,c1)){//转折点为空
if(isEmptyCol(r1,c1,r2,c1) & isEmptyRow(r2,c1,r2,c2)) {
return ONE_CORNER_FIRSTY;
}
}
//无连接
return NO_LINK;
}
/**
* 是否经过2次转折实现连接
* @param r1 块1的行号
* @param c1 块1的列号
* @param r2 块2的行号
* @param c2 块2的列号
* @return true代表可以连接,false代表不能
*/
private boolean isTwoCornerLink(int r1,int c1,int r2,int c2){
int result;
//正常情况,划分成4个方向
//块1向上
for(int row = r1 -1;row >= 0;row--){
//如果有数据不为空,则直接结束该方向的尝试
if(map[row][c1] != 0){
break;
}
//存储第一个拐点的坐标
p[0] = row;
p[1] = c1;
//每次都尝试转折,则变成一个转点的操作
result = isOneCornerLink(row,c1,r2,c2);
//如果可以连接
if(result != NO_LINK){
//存储第二个拐点的位置
switch(result){
case ONE_CORNER_FIRSTX:
p[2] = row;
p[3] = c2;
break;
case ONE_CORNER_FIRSTY:
p[2] = r2;
p[3] = c1;
break;
}
return true;
}
}
//块1向下
for(int row = r1 + 1;row < MAX_ROW;row++){
//如果有数据不为空,则直接结束该方向的尝试
if(map[row][c1] != 0){
break;
}
//存储第一个拐点的坐标
p[0] = row;
p[1] = c1;
//每次都尝试转折,则变成一个转点的操作
result = isOneCornerLink(row,c1,r2,c2);
//如果可以连接
if(result != NO_LINK){
//存储第二个拐点的位置
switch(result){
case ONE_CORNER_FIRSTX:
p[2] = row;
p[3] = c2;
break;
case ONE_CORNER_FIRSTY:
p[2] = r2;
p[3] = c1;
break;
}
return true;
}
}
//块1向左
for(int col = c1 -1;col >= 0;col--){
//如果有数据不为空,则直接结束该方向的尝试
if(map[r1][col] != 0){
break;
}
//存储第一个拐点的坐标
p[0] = r1;
p[1] = col;
//每次都尝试转折,则变成一个转点的操作
result = isOneCornerLink(r1,col,r2,c2);
//如果可以连接
if(result != NO_LINK){
//存储第二个拐点的位置
switch(result){
case ONE_CORNER_FIRSTX:
p[2] = r1;
p[3] = c2;
break;
case ONE_CORNER_FIRSTY:
p[2] = r2;
p[3] = col;
break;
}
return true;
}
}
//块1向右
for(int col = c1 + 1;col < MAX_COL;col++){
//如果有数据不为空,则直接结束该方向的尝试
if(map[r1][col] != 0){
break;
}
//存储第一个拐点的坐标
p[0] = r1;
p[1] = col;
//每次都尝试转折,则变成一个转点的操作
result = isOneCornerLink(r1,col,r2,c2);
//如果可以连接
if(result != NO_LINK){
//存储第二个拐点的位置
switch(result){
case ONE_CORNER_FIRSTX:
p[2] = r1;
p[3] = c2;
break;
case ONE_CORNER_FIRSTY:
p[2] = r2;
p[3] = col;
break;
}
return true;
}
}
//四个特例,也就是超出地图区域的连接
//实现地图区域上侧的连接,也就是到上侧是一个空列
if((isEmptyCol(r1,c1,-1,c1)) & (isEmptyCol(r2,c2,-1,c2))){
p[0] = -1;
p[1] = c1;
p[2] = -1;
p[3] = c2;
return true;
}
//左侧
if((isEmptyRow(r1,c1,r1,-1)) & (isEmptyRow(r2,c2,r2,-1))){
p[0] = r1;
p[1] = -1;
p[2] = r2;
p[3] = -1;
return true;
}
//下侧
if((isEmptyCol(r1,c1,MAX_ROW,c1)) & (isEmptyCol(r2,c2,MAX_ROW,c2))){
p[0] = MAX_ROW;
p[1] = c1;
p[2] = MAX_ROW;
p[3] = c2;
return true;
}
//右侧
if((isEmptyRow(r1,c1,r1,MAX_COL)) & (isEmptyRow(r2,c2,r2,MAX_COL))){
p[0] = r1;
p[1] = MAX_COL;
p[2] = r2;
p[3] = MAX_COL;
return true;
}
return false;
}
/**
* 逻辑判断是否有连线
* @return NO_LINK代表无连线,其它数据代表有连线
*/
private int logic(){
//如果数值不同
if(map[firstRow][firstCol] != map[secondRow][secondCol]){
return NO_LINK;
}
//判断连接方式
if(isEmptyRow(firstRow,firstCol,secondRow,secondCol)){ //水平连线
return H_LINK;
}
if(isEmptyCol(firstRow,firstCol,secondRow,secondCol)){//垂直连线
return V_LINK;
}
//一个转点的连接
int result = isOneCornerLink(firstRow,firstCol,secondRow,secondCol);
if(result != NO_LINK){
return result;
}
//两个转点的连接
if(isTwoCornerLink(firstRow,firstCol,secondRow,secondCol)){
return TWO_CORNER;
}
//返回无连接
return NO_LINK;
}
/**
* 逻辑判别和逻辑处理
*/
public boolean action(){
//判断是否选择两个方块
if(selectTileNum != 2){
return false;
}
boolean b = false;
//判断是否有连线
linkType = logic();
//如果有连线,则消失
if(linkType != NO_LINK){
map[firstRow][firstCol] = 0;
map[secondRow][secondCol] = 0;
b = true;
}
//选择的块数初始化
selectTileNum = 0;
return b;
}
}
分享到:
相关推荐
【J2ME连连看基础功能源代码】涉及的知识点主要集中在Java ME(Java 2 Micro Edition)平台上开发移动设备应用程序,尤其是游戏应用。以下是对源代码的详细解析: 1. **J2ME平台**:J2ME是Java平台的一个子集,用于...
《J2ME手机游戏连连看源代码》是一个关于利用Java ME(J2ME)平台开发经典游戏“连连看”的项目。J2ME是Java的一种微型版本,主要用于移动设备和嵌入式系统的应用开发,如手机、智能电视等。在这个项目中,开发者...
《J2ME连连看游戏开发详解》 J2ME(Java 2 Micro Edition)是Java平台上的一种轻量级应用框架,主要用于开发移动设备和嵌入式设备上的应用程序。本篇文章将深入探讨如何使用J2ME编写一款经典的连连看游戏。 一、...
6. **网络功能**:虽然J2ME的网络功能有限,但源代码可能包含一些简单的联网元素,如排行榜或多人合作模式。 7. **优化技巧**:为了在资源有限的J2ME设备上流畅运行,开发者可能会使用各种优化技术,比如精灵图...
J2ME扫雷源代码J2ME扫雷源代码J2ME扫雷源代码J2ME扫雷源代码J2ME扫雷源代码J2ME扫雷源代码J2ME扫雷源代码J2ME扫雷源代码J2ME扫雷源代码J2ME扫雷源代码J2ME扫雷源代码J2ME扫雷源代码
**J2ME基础知识及源代码** Java 2 Micro Edition(J2ME)是Java平台的一个重要组成部分,专门设计用于资源有限的嵌入式设备和移动设备,如手机、智能手表和家用电器。J2ME提供了在这些设备上运行Java应用程序的能力...
连连看,手机编程源代码,Q版,用于手机开发
通过研究这些小游戏源代码,初学者可以深入理解J2ME的游戏开发流程,提升编程技能,同时也可以为开发更复杂的应用程序奠定基础。对于有经验的开发者来说,这是一个复习基本概念和最佳实践的好资源。无论你是新手还是...
【J2ME连连看代码(含报告)】是关于使用Java Micro Edition(J2ME)开发的一款经典游戏——连连看的源代码与分析报告。J2ME是Java平台的一个子集,专门用于嵌入式设备和移动设备,如手机、智能手表等。这个项目为...
3. **代码编写和调试**:在Eclipse中编写J2ME代码的技巧,使用内置的调试器跟踪和解决问题。 4. **打包和部署**:如何将游戏打包成可执行文件,并将其部署到实际的手机设备或者通过蓝牙或网络进行分发。 通过这些...
【标题】"j2me五子棋网络对战 源代码" 提供的是一个基于Java 2 Micro Edition (J2ME)平台开发的五子棋游戏,支持网络对战的功能。这个项目的核心在于实现玩家之间的实时交互,使得双方可以在同一棋盘上进行对弈,...
一款Java 手机端连连看游戏关键引擎代码!
源代码通常包含了书中讲解的各种功能模块和示例程序,对于学习和提升J2ME编程技能极具价值。 J2ME是Java平台的一个子集,主要用于开发在资源有限的设备上运行的应用程序,如移动电话、智能家电、数字电视等。它由...
J2me 捉鬼游戏源代码,地图数据定义,0-空地 1-障碍 2有鬼房子 3空房子 4-石头。怪物类:0-僵尸 1-幽灵 2-夜叉 3-牛头 4-马面。角色类:角色状态 0-停止 1-走路 2-中招,停止走路时的帧序列,改变精灵的帧序列,dir ...
在这里,我们主要探讨的是使用Java 2 Micro Edition (J2ME) 技术编写的大富翁手机程序的源代码及详细注释。J2ME是一种轻量级的Java平台,主要用于移动设备和嵌入式系统,如手机、PDA等。 首先,源代码是理解任何...
**J2ME 合金弹头S60源代码详解** **一、J2ME简介** J2ME(Java 2 Micro Edition)是Java平台的一个子集,主要用于嵌入式设备和移动设备上的应用程序开发,如手机、智能手表、家用电器等。它提供了一个轻量级的运行...
总的来说,"J2ME蓝牙五子棋游戏源代码"是一个很好的学习资源,它涵盖了J2ME开发中的关键知识点,包括蓝牙通信、GUI编程以及基础的游戏逻辑实现。通过深入研究和实践,开发者不仅可以提升J2ME编程技能,还能增强对...
j2me 扫雷手机版源代码 希望有帮助学习j2me
基于java的开发源码-J2ME冒险游戏CASPER源代码.zip 基于java的开发源码-J2ME冒险游戏CASPER源代码.zip 基于java的开发源码-J2ME冒险游戏CASPER源代码.zip 基于java的开发源码-J2ME冒险游戏CASPER源代码.zip 基于java...
下面我们将详细探讨连连看J2ME源代码中的关键知识点。 1. **游戏逻辑实现**: 连连看的核心在于游戏规则的编程。游戏开始时,随机生成一对对相同的图片,玩家需要找到并消除它们。在J2ME中,这通常通过二维数组来...