📄 mazecanvas.java
字号:
package myGame.main;
import MyGameMIDlet;
import java.util.Enumeration;
import java.util.Random;
import javax.microedition.lcdui.Font;
import javax.microedition.lcdui.Graphics;
import javax.microedition.lcdui.Image;
import javax.microedition.lcdui.game.GameCanvas;
import javax.microedition.m3g.AnimationController;
import javax.microedition.m3g.AnimationTrack;
import javax.microedition.m3g.Appearance;
import javax.microedition.m3g.Background;
import javax.microedition.m3g.Camera;
import javax.microedition.m3g.CompositingMode;
import javax.microedition.m3g.Graphics3D;
import javax.microedition.m3g.Image2D;
import javax.microedition.m3g.KeyframeSequence;
import javax.microedition.m3g.Mesh;
import javax.microedition.m3g.Node;
import javax.microedition.m3g.PolygonMode;
import javax.microedition.m3g.RayIntersection;
import javax.microedition.m3g.Texture2D;
import javax.microedition.m3g.Transform;
import javax.microedition.m3g.World;
// Main class. It setups the 3D scene and does the movements
// and rendering
public class MazeCanvas extends GameCanvas implements Runnable {
private final static float WALL_HEIGHT = 10.f;// 迷宫墙壁的高度
public static float MAZE_SIDE_LENGTH = 250f;// 迷宫的总长
private final static float STEP = 3.0f;// 前进的每个步长
private final static float ANGLE_STEP = 8.0f;// 每次旋转的角度
private final static int MILLIS_PER_TICK = 5;// 每个循环所消耗的最小时间
private float stepz = -STEP, stepx = 0f;// 事先定义x和z方向上的步长
private float locationx = 0f, locationz = 0;// 玩家的位置
private float angley = 0f;// 玩家的旋转角度
private boolean topView = false;// 是否处于俯瞰模式
private volatile boolean playing = true;// 是否线程正在运行
private volatile float fps = 0;// 每秒所能运行的帧数
private volatile long gameStart = 0;// 在迷宫中已经消耗的时间
private volatile long duration = 0;// 走通迷宫所耗费的时间
private boolean finished;// 是否完成游戏
private Graphics3D g3d;// Graphics3D的全局实例
private World world;// 3D场景中的World根节点
private Camera normalCamera, topCamera;// 玩家摄像机和顶部用于俯瞰模式的摄像机
private Background background = null;// 3D场景的背景
private Mesh locationSquare = null;// 定位玩家方位的红色小正方形
private Appearance wallClearAppearance = new Appearance();// 墙壁的透明外观
private Appearance wallAppearance = new Appearance();// 墙壁的正常外观
private Mesh transparentMesh = null;// 指向上一个被透视的Mesh对象
private static Maze maze = null;// new Maze(10, MAZE_SIDE_LENGTH,
// WALL_HEIGHT);// 创建迷宫
private Thread mainThread = null;// 游戏的主线程
public static byte corridorCount = 5;// 迷宫的走廊数
public static int timeLimit = 120;
public static int screen_width = 0, screen_height = 0;
// Construct the Displayable
public MazeCanvas() {
super(true);
// corridorCount = (byte)MyGame.getInt(MyGame.DIFFICULT_SET);
// timeLimit = MyGame.getInt(MyGame.TIMELIMIT_SET);
screen_width = getWidth();
screen_height = getHeight();
loadWeapons();
}
public static void newMaze() {
if (maze != null)
maze = null;
maze = new Maze(corridorCount, MAZE_SIDE_LENGTH, WALL_HEIGHT);// 创建迷宫
}
// (Re)Starts the game
void start() {
this.setFullScreenMode(true);
playing = true;
gameStart = System.currentTimeMillis() - duration;
mainThread = new Thread(this);
mainThread.start();
}
// stops/pauses the game
public void stop() {
duration = System.currentTimeMillis() - gameStart;
playing = false;
}
// switches from top view to normal view and vice versa
void switchView() {
topView = !topView;// 将切换标志位取反
setView();// 根据标志位重新设置游戏视角
// informs the MIDLet since this can be switched internally
// MyGame.switchView();
}
void setView() {
// 根据玩家当前的位置,重新设置定位标志的位置
locationSquare.setTranslation(locationx, 2 * WALL_HEIGHT + 3f,
locationz);
locationSquare.setRenderingEnable(topView);// 这个定位标志置只有俯瞰模式摄像机可见
world.setBackground(topView ? null : background);// 如果是俯瞰模式则背景设置位null
if (topView) {
world.setActiveCamera(topCamera);// 将当前摄像机设置位俯瞰模式摄像机
} else {
world.setActiveCamera(normalCamera);// 将当前摄像机设置位玩家模式摄像机
}
}
// 初始化虚拟世界
void init() {
setFullScreenMode(true);// 设置全屏模式
duration = 0;
g3d = Graphics3D.getInstance();// 获得Graphics3D实例
world = new World();// 创建场景根节点World对象
normalCamera = new Camera();// 创建常规模式下的摄像机
topCamera = new Camera();// 创建用于俯瞰模式的摄像机
world.addChild(normalCamera);// 将常规模式下的摄像机添加到场景中
world.addChild(topCamera);// 将俯瞰模式下的摄像机添加到场景中
float w = (float) getWidth();// 获取游戏画布的宽度
float h = (float) getHeight();// 获取游戏画布的高度
normalCamera.setPerspective(60.f, w / h, 0.1f, 1000.f);// 设置玩家摄像机的透视投影矩阵
topCamera.setPerspective(60.f, w / h, 0.1f, 1000.f);// 设置俯瞰摄像机的透视投影矩阵
Transform topCameraTransform = new Transform();// Transform对象用来定位俯瞰摄像机
topCameraTransform.postRotate(90, -1f, 0f, 0f);// 旋转摄像机,使它朝下
topCameraTransform.postTranslate(0f, 0f, MAZE_SIDE_LENGTH);// 平移摄像机到迷宫的顶部
topCamera.setTransform(topCameraTransform);// 定位摄像机
background = new Background();// 创建场景的背景
Image backgroundImage = MyGameMIDlet.makeImage("/background"
+ String.valueOf(Math.abs(new Random().nextInt())
% Integer.parseInt(MyGameMIDlet.getInstance()
.getAppProperty("CountBackground"))) + ".png");// 随机加载场景的背景图片
if (backgroundImage != null) {
background.setImage(new Image2D(Image2D.RGB, backgroundImage));// 将背景图片添加到背景中
background.setImageMode(Background.REPEAT, Background.REPEAT);// 背景图片设置为重复模式
}
world.setBackground(background);// 将背景添加到场景中去
createFloor();// 构建迷宫的地板
createLocationSquare();// 构建定位玩家方位的标志
setUpMaze();// 构建迷宫的墙壁
createStartEndMarks();// 构建开始结束标志
setView();// 设置游戏视角,可能为玩家模式或者俯瞰模式
locationx = maze.findStartLocationX();// 设置初始方位的X坐标
locationz = maze.findStartLocationZ();// 设置初始方位的Z坐标
angley = -180f;
setupCamera();
start();// 开始游戏线程
}
// creates the labeld at the start and at the end of the maze
private void createStartEndMarks() {
Appearance startMarkAppearance = new Appearance();// 创建开始标志外观属性
Appearance endMarkAppearance = new Appearance();// 创建结束标志外观属性
// 外观属性的融合方式为ALPHA,这样设置是为了使开始标志结束标志只显示字样,其余部分为透明
CompositingMode markCompositeMode = new CompositingMode();
markCompositeMode.setBlending(CompositingMode.ALPHA);
startMarkAppearance.setCompositingMode(markCompositeMode);
endMarkAppearance.setCompositingMode(markCompositeMode);
Texture2D startMarkTexture = null;
Image startMarkTextureImage = MyGameMIDlet
.makeImage("/start_label.png");// 加载纹理图片
if (startMarkTextureImage != null) {
startMarkTexture = new Texture2D(new Image2D(Image2D.RGBA,
startMarkTextureImage));
startMarkTexture.setWrapping(Texture2D.WRAP_CLAMP,
Texture2D.WRAP_CLAMP);// 钳位模式
startMarkTexture.setBlending(Texture2D.FUNC_REPLACE);// 纹理的融合方式
startMarkTexture.setFiltering(Texture2D.FILTER_NEAREST,
Texture2D.FILTER_NEAREST);// 缩放方式
startMarkAppearance.setTexture(0, startMarkTexture);
}
Texture2D endMarkTexture = null;
Image endMarkTextureImage = MyGameMIDlet.makeImage("/end_label.png");// 加载纹理图片
if (endMarkTextureImage != null) {
endMarkTexture = new Texture2D(new Image2D(Image2D.RGBA,
endMarkTextureImage));
endMarkTexture.setWrapping(Texture2D.WRAP_CLAMP,
Texture2D.WRAP_CLAMP);// 钳位模式
endMarkTexture.setBlending(Texture2D.FUNC_REPLACE);// 纹理的融合方式
endMarkTexture.setFiltering(Texture2D.FILTER_NEAREST,
Texture2D.FILTER_NEAREST);// 缩放方式
endMarkAppearance.setTexture(0, endMarkTexture);
}
Plane startMarkPlane = maze.createStartMark();// 调用Maze类的方法来创建Plane对象
Mesh startMarkMesh = startMarkPlane.createMesh();// 用Plane对象创建Mesh对象
startMarkMesh.setAppearance(0, startMarkAppearance);// 将外观属性添加到Mesh对象中
startMarkMesh.setPickingEnable(false);// 不允许对开始标志进行拾取
world.addChild(startMarkMesh);// 将开始标志添加到场景中
Plane endMarkPlane = maze.createEndMark();// 创建一个具有结束位置特性的Plane对象
Mesh endMarkMesh = endMarkPlane.createMesh();// 调用Plane类中方法创建一个结束标志的Mesh对象
endMarkMesh.setAppearance(0, endMarkAppearance);// 将外观属性添加到Mesh对象中
endMarkMesh.setPickingEnable(false);// 不允许对开始标志进行拾取
KeyframeSequence keyframes = new KeyframeSequence(4, 3,
KeyframeSequence.LINEAR);// 创建带有四个关键帧的帧序列,并使用线性插值
keyframes.setDuration(12000);// 设置动画持续时间
keyframes.setRepeatMode(KeyframeSequence.LOOP);// 动画循环动作
float[] trans = new float[4];
endMarkMesh.getOrientation(trans);// 用getOrientation方法获得结束标志的位置
// 创建动画的关键帧,保持x、z轴坐标不变,改变y轴坐标,使它上下运动
keyframes.setKeyframe(0, 0,
new float[] { trans[0], trans[1], trans[2] });
keyframes.setKeyframe(1, 4000, new float[] { trans[0],
trans[1] - WALL_HEIGHT / 4, trans[2] });
keyframes.setKeyframe(2, 8000, new float[] { trans[0],
trans[1] + WALL_HEIGHT / 4, trans[2] });
keyframes.setKeyframe(3, 12000, new float[] { trans[0], trans[1],
trans[2] });
AnimationTrack animationTrack = new AnimationTrack(keyframes,
AnimationTrack.TRANSLATION);
AnimationController anim = new AnimationController();// 创建一个游戏控制器对象anim
animationTrack.setController(anim);// 将anim绑定到动画轨迹中
endMarkMesh.addAnimationTrack(animationTrack);// 将动画轨迹添加到结束标志中去
world.addChild(endMarkMesh);// 将结束标志添加到场景中去
}
// creates the floor
private void createFloor() {
float floorSide = MAZE_SIDE_LENGTH / 2;
Transform floorTransform = new Transform();
floorTransform.postRotate(90.0f, -1.0f, 0.0f, 0.0f);// 从xy平面旋转到xz平面上
floorTransform.postScale(floorSide, floorSide, 1.0f);// 缩放比例
Appearance floorAppearance = new Appearance();
PolygonMode floorPolygonMode = new PolygonMode();
floorPolygonMode.setPerspectiveCorrectionEnable(true);// 启用透视修正
floorAppearance.setPolygonMode(floorPolygonMode);
Texture2D floorTexture = null;
int rand = Math.abs(new Random().nextInt()
% Integer.parseInt(MyGameMIDlet.getInstance().getAppProperty(
"CountFloor")));
Image floorTextureImage = MyGameMIDlet.makeImage("/floor"
+ String.valueOf(rand) + ".png");// 随机加载纹理图片
if (floorTextureImage != null) {
floorTexture = new Texture2D(new Image2D(Image2D.RGB,
floorTextureImage));// 创建纹理
floorTexture.setWrapping(Texture2D.WRAP_REPEAT,
Texture2D.WRAP_REPEAT);// 重复模式
floorTexture.setBlending(Texture2D.FUNC_REPLACE);// 纹理融合模式
floorTexture.setFiltering(Texture2D.FILTER_LINEAR,
Texture2D.FILTER_NEAREST);// 纹理滤波方式
floorAppearance.setTexture(0, floorTexture);// 设置纹理
}
Plane floor = new Plane(floorTransform, 10);// 创建Plane对象,并指定纹理重复10次
Mesh floorMesh = floor.createMesh();// 用Plane对象创建地板的地板Mesh对象
floorMesh.setAppearance(0, floorAppearance);// 将外观属性添加到Mesh对象中
floorMesh.setPickingEnable(false);// 不允许对地板拾取
world.addChild(floorMesh);// 将地板添加到场景中
}
public static float multiple = 8;
// create the player location square
private void createLocationSquare() {
Transform locationSquareTransform = new Transform();// 创建一个Transform对象,用来翻转
locationSquareTransform.postRotate(90.0f, -1.0f, 0.0f, 0.0f);// 从xy平面旋转到xz平面
locationSquareTransform.postScale(multiple, multiple, 1.0f);// 放大8倍
// 定位标志的外观属性特别简单,仅仅使用到纹理属性
Appearance locationSquareAppearance = new Appearance();// 创建一个外观属性对象
Texture2D locationSquareTexture = null;
Image locationSquareImage = MyGameMIDlet.makeImage("/location.png");// 加载纹理图片
if (locationSquareImage != null) {
// 用纹理图片创建Image2D对象,并用Image2D对象创建纹理对象
locationSquareTexture = new Texture2D(new Image2D(Image2D.RGBA,
locationSquareImage)); // 纹理对象采用钳位映射方式
locationSquareTexture.setWrapping(Texture2D.WRAP_CLAMP,
Texture2D.WRAP_CLAMP);
locationSquareTexture.setBlending(Texture2D.FUNC_REPLACE);// 替换
locationSquareTexture.setFiltering(Texture2D.FILTER_NEAREST,
Texture2D.FILTER_NEAREST);// 插值
locationSquareAppearance.setTexture(0, locationSquareTexture);// 将纹理属性添加到外观属性中
}
Plane locationPlane = new Plane(locationSquareTransform, 1);// 根据翻转矩阵创建标志平面,纹理重复为1
locationSquare = locationPlane.createMesh();// 用Plane对象创建Mesh对象
locationSquare.setAppearance(0, locationSquareAppearance);// 将外观属性添加到定位标志平面中
locationSquare.setRenderingEnable(false);// 初始情况下不可显示
locationSquare.setPickingEnable(false);// 定位标志不可拾取
world.addChild(locationSquare);// 将定位标志添加到游戏场景中去
}
private void setUpMaze() {
PolygonMode wallPolygonMode = new PolygonMode();
wallPolygonMode.setPerspectiveCorrectionEnable(true);// 启用透明修正
wallClearAppearance.setPolygonMode(wallPolygonMode);// 墙壁半透明的外观属性
CompositingMode wallClearCompositeMode = new CompositingMode();// 用于处理半透明
wallClearCompositeMode.setBlending(CompositingMode.ALPHA_ADD);// 颜色融合模式为ALPHA_ADD
wallClearAppearance.setCompositingMode(wallClearCompositeMode);// 透明墙壁的外观
wallAppearance.setPolygonMode(wallPolygonMode);// 普通墙壁的外观
int rand = Math.abs(new Random().nextInt()
% Integer.parseInt(MyGameMIDlet.getInstance().getAppProperty(
"CountWall")));
Image wallTextureImage = MyGameMIDlet.makeImage("/wall"
+ String.valueOf(rand) + ".png");// 随机加载纹理图片
System.out.println(rand);
if (wallTextureImage != null) {
Texture2D wallTexture = null;
wallTexture = new Texture2D(new Image2D(Image2D.RGB,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -