📄 mazecanvas.java
字号:
import java.util.*;
import javax.microedition.lcdui.*;
import javax.microedition.lcdui.game.*;
import javax.microedition.m3g.*;
// Main class. It setups the 3D scene and does the movements
// and rendering
class MazeCanvas
extends GameCanvas
implements Runnable
{
// Height of the walls
private final static float WALL_HEIGHT = 10.f;
// overall side of the maze
private final static float MAZE_SIDE_LENGTH =200f;
// amount to advance at each step
private final static float STEP = 3.0f;
// amount to rotate each time
private final static float ANGLE_STEP = 8.0f;
// millis to wait in the main loop
private final static int MILLIS_PER_TICK = 5;
// Size of the steps to directions x and z
// stored to avoid extra trigonometric calculations
private float stepz = -STEP, stepx = 0f;
// player's location
private float locationx = 0f, locationz = 0;
// player's rotation
private float angley = 0f;
// flags whether we are looking the game from the top
private boolean topView = false;
// flags to keep the drawing going
private volatile boolean playing = true;
// stores the amount of frames per second being displayed
private volatile float fps = 0;
// stores how long has taken to run thorugh the maze
private volatile long gameStart = 0;
// stores how long has taken to run thorugh the maze
private volatile long duration = 0;
// indicates whether the game has finished
private boolean finished;
// Parent MIDlet
private final Maze3DMIDlet midlet;
// Graphics 3D global instance
private Graphics3D g3d;
// the world of the application
private World world;
// the world has 2 cameras
private Camera camera, topCamera;
// world's background
private Background background = null;
// simple rectangular mesh used to locate the player
private Mesh locationSquare = null;
// wall alternate appeareances
private Appearance wallClearAppearance = new Appearance();
private Appearance wallAppearance = new Appearance();
// points to the mesh last made semi transparent
private Mesh transparentMesh = null;
private Maze maze = new Maze(10, MAZE_SIDE_LENGTH, WALL_HEIGHT);
private Thread mainThread = null;
// Construct the Displayable
MazeCanvas(Maze3DMIDlet midlet)
{
super(true);
this.midlet = midlet;
}
// (Re)Starts the game
void start()
{
playing = true;
gameStart = System.currentTimeMillis() - duration;
mainThread = new Thread(this);
mainThread.start();
}
// stops/pauses the game
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
midlet.viewSwitched();
}
void setView()
{
// reset the locaiton and draw on top of the maze
locationSquare.setTranslation(locationx,
2 * WALL_HEIGHT + 3f, locationz);
// the square is rendered only in top view
locationSquare.setRenderingEnable(topView);
// the background is removed in top view
world.setBackground(topView ? null : background);
// sets the actual active camera
if (topView)
{
world.setActiveCamera(topCamera);
}
else
{
world.setActiveCamera(camera);
}
}
// Builds the world
void init()
{
setFullScreenMode(true);
duration = 0;
// get a Graphics3D instance
g3d = Graphics3D.getInstance();
// build the world and the cameras
world = new World();
camera = new Camera();
topCamera = new Camera();
world.addChild(camera);
world.addChild(topCamera);
float w = (float)getWidth();
float h = (float)getHeight();
// set the perspective
camera.setPerspective(60.f, w / h, 0.1f, 1000.f);
topCamera.setPerspective(60.f, w / h, 0.1f, 1000.f);
// the top camer has a fixed transform looking from the top
Transform topCameraTransform = new Transform();
topCameraTransform.postRotate(90, -1f, 0f, 0f);
topCameraTransform.postTranslate(0f, 0f,MAZE_SIDE_LENGTH);
//topCameraTransform.postTranslate(0f, 0f, 1.2f * MAZE_SIDE_LENGTH);
topCamera.setTransform(topCameraTransform);
// Setup the background
background = new Background();
Image backgroundImage = Maze3DMIDlet.makeImage("/background.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();
// setup the initial location
locationx = maze.findStartLocationX();
locationz = maze.findStartLocationZ();
// look at the center
angley = -180f;
setupCamera();
start();
}
// creates the labeld at the start and at the end of the maze
private void createStartEndMarks()
{
// The marks' appearance
Appearance startMarkAppearance = new Appearance();
Appearance endMarkAppearance = new Appearance();
// The composite mode is ALPHA to show only the letters
// the background is hidden using the alpha layer
CompositingMode markCompositeMode = new CompositingMode();
markCompositeMode.setBlending(CompositingMode.ALPHA);
startMarkAppearance.setCompositingMode(markCompositeMode);
endMarkAppearance.setCompositingMode(markCompositeMode);
// The label's text is built using a texture
Texture2D startMarkTexture = null;
Image startMarkTextureImage =
Maze3DMIDlet.makeImage("/start_label.png");
if (startMarkTextureImage != null)
{
startMarkTexture = new Texture2D(
new Image2D(Image2D.RGBA, startMarkTextureImage));
// the texture is not repeated
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 =
Maze3DMIDlet.makeImage("/end_label.png");
if (endMarkTextureImage != null)
{
endMarkTexture = new Texture2D(
new Image2D(Image2D.RGBA, endMarkTextureImage));
// the texture is not repeated
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);
}
// create the start mesh
Plane startMarkPlane = maze.createStartMark();
Mesh startMarkMesh = startMarkPlane.createMesh();
startMarkMesh.setAppearance(0, startMarkAppearance);
// these are not pickable
startMarkMesh.setPickingEnable(false);
world.addChild(startMarkMesh);
// creates the end mesh
Plane endMarkPlane = maze.createEndMark();
Mesh endMarkMesh = endMarkPlane.createMesh();
endMarkMesh.setAppearance(0, endMarkAppearance);
// is not pickable either
endMarkMesh.setPickingEnable(false);
// Create a sequence of 4 keyframes
KeyframeSequence keyframes =
new KeyframeSequence(4,3, KeyframeSequence.LINEAR);
keyframes.setDuration(12000);
keyframes.setRepeatMode(KeyframeSequence.LOOP);
float[] trans = new float[4];
endMarkMesh.getOrientation(trans);
// create set the keyframes.
// Basically keep x and z and animate in the y axis
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();
animationTrack.setController(anim);
// add the animation track
endMarkMesh.addAnimationTrack(animationTrack);
world.addChild(endMarkMesh);
}
// creates the floor
private void createFloor()
{
float floorSide = MAZE_SIDE_LENGTH / 2;
// define the location and size of the floor
Transform floorTransform = new Transform();
floorTransform.postRotate(90.0f, -1.0f, 0.0f, 0.0f);
floorTransform.postScale(floorSide, floorSide, 1.0f);
// The floor appearance. Basically a texture repeated many times
Appearance floorAppearance = new Appearance();
// The floor needs that perspective correction is enabled
PolygonMode floorPolygonMode = new PolygonMode();
floorPolygonMode.setPerspectiveCorrectionEnable(true);
floorAppearance.setPolygonMode(floorPolygonMode);
// load the texture
Texture2D floorTexture = null;
Image floorTextureImage = Maze3DMIDlet.makeImage("/floor.png");
if (floorTextureImage != null)
{
floorTexture = new Texture2D(
new Image2D(Image2D.RGB, floorTextureImage));
// the texture is repeated many times
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);
// build the mesh
Mesh floorMesh = floor.createMesh();
floorMesh.setAppearance(0, floorAppearance);
// the floor is not pickable
floorMesh.setPickingEnable(false);
// add to the world
world.addChild(floorMesh);
}
// create the player location square
private void createLocationSquare()
{
// initial location of the square
// we are only interested in rotating and scaling it
Transform locationSquareTransform = new Transform();
locationSquareTransform.postRotate(90.0f, -1.0f, 0.0f, 0.0f);
locationSquareTransform.postScale(8, 8, 1.0f);
// the location apparance is a simple texture decal
Appearance locationSquareAppearance = new Appearance();
Texture2D locationSquareTexture = null;
Image locationSquareImage = Maze3DMIDlet.makeImage("/location.png");
if (locationSquareImage != null)
{
locationSquareTexture = new Texture2D(
new Image2D(Image2D.RGB, locationSquareImage));
// the texture is not repeated
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -