📄 jpctdemo.java
字号:
import java.io.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import com.threed.jpct.*;
import com.threed.jpct.util.*;
/**
* This is a simple demonstration of how a first-person-shooter like application
* can be implementated using jPCT. It shows fps-like movement and collision detection
* as well as loading a 3DS-level, some OcTree-stuff etc.
*/
class JPCTDemo {
/**
* The starting position of the player
*/
private final static SimpleVector STARTING_POS=new SimpleVector(800, -120, -400);
/**
* The radius of the sphere used for sphere/polygon collision detection
*/
private final static float COLLISION_SPHERE_RADIUS=8f;
/**
* The "height" of the player, i.e. how many units the camera is loacted above the ground.
*/
private final static float PLAYER_HEIGHT=30f;
/**
* The dimensions of the ellipsoid used for collision detection. This represents the "size"
* of the player
*/
private final static SimpleVector ELLIPSOID_RADIUS=new SimpleVector(COLLISION_SPHERE_RADIUS,PLAYER_HEIGHT/2f,COLLISION_SPHERE_RADIUS);
/**
* The speed with which the player will fall if there's no ground below his feet
*/
private final static float GRAVITY=4f;
/**
* How fast the player will move (in world units)
*/
private final static float MOVE_SPEED=2.5f;
/**
* How fast the player will turn
*/
private final static float TURN_SPEED=0.06f;
/**
* A flag that signals a change of the renderer (don't ask about the 35 here....)
*/
private final static int SWITCH_RENDERER=35;
/**
* Should we try to do fullscreen?
*/
private boolean fullscreen=false;
/**
* Are we using OpenGL?
*/
private boolean openGL=false;
/**
* Are we rendering in wireframe mode?
*/
private boolean wireframe=false;
/**
* Some jPCT related stuff...
*/
private Object3D level=null;
private Object3D weapon=null;
private Object3D elevator=null;
private FrameBuffer buffer=null;
private World theWorld=null;
private TextureManager texMan=null;
private Camera camera=null;
/**
* The texture used for blitting the framerate
*/
private Texture numbers=null;
/**
* playerDirection stores the player's current orientation, so that the player's
* movement is decoupled from the actual camera.
*/
private Matrix playerDirection=new Matrix();
private SimpleVector tempVector=new SimpleVector();
/**
* Default size of the framebuffer
*/
private int width=640;
private int height=480;
/**
* Some AWT related stuff
*/
private Frame frame=null;
private Graphics gFrame=null;
private BufferStrategy bufferStrategy=null;
private GraphicsDevice device=null;
private int titleBarHeight=0;
private int leftBorderWidth=0;
private int switchMode=0;
private int fps;
private int lastFps;
private long totalFps;
private int pps;
private int lastPps;
private boolean isIdle=false;
private boolean exit=false;
/**
* Flags for the keys
*/
private boolean left=false;
private boolean right=false;
private boolean up=false;
private boolean down=false;
private boolean forward=false;
private boolean back=false;
/**
* The KeyMapper that offers a uniform way to access
* the keyboard in hard- and software-mode
*/
private KeyMapper keyMapper=null;
/**
* Some vars to handle the elevator
*/
float elevatorOffset=-0.8f;
float elevatorPosition=-90f;
int elevatorCountdown=50;
/**
* Very complex stuff...impossible to explain...
*/
public static void main(String[] args) {
JPCTDemo start=new JPCTDemo(args);
}
/**
* The constructor. Here we are initializing things...
*/
private JPCTDemo(String[] args) {
/**
* Evaluate the commandline parameters
*/
for (int i=0; i<args.length; i++) {
if (args[i].equals("fullscreen")) {
fullscreen=true;
Config.glFullscreen=true;
}
if (args[i].equals("mipmap")) {
Config.glMipmap=true;
}
if (args[i].equals("trilinear")) {
Config.glTrilinear=true;
}
if (args[i].equals("16bit")) {
Config.glColorDepth=16;
}
try {
if (args[i].startsWith("width=")) {
width=Integer.parseInt(args[i].substring(6));
}
if (args[i].startsWith("height=")) {
height=Integer.parseInt(args[i].substring(7));
}
if (args[i].startsWith("refresh=")) {
Config.glRefresh=Integer.parseInt(args[i].substring(8));
}
if (args[i].startsWith("zbuffer=")) {
Config.glZBufferDepth=Integer.parseInt(args[i].substring(8));
if (Config.glZBufferDepth==16) {
Config.glFixedBlitting=true;
}
}
} catch (Exception e) {
// We don't care...
}
}
isIdle=false;
switchMode=0;
totalFps=0;
fps=0;
lastFps=0;
/**
* Initialize the World instance and get the TextureManager (a singleton)
*/
theWorld=new World();
texMan=TextureManager.getInstance();
/**
* Setup the lighting. We are not using overbright lighting because the OpenGL
* renderer can't do it, but we are using RGB-scaling. Some hardware/drivers
* for OpenGL don't support this.
*/
Config.fadeoutLight=true;
Config.linearDiv=100;
Config.lightDiscardDistance=350;
theWorld.getLights().setOverbrightLighting(Lights.OVERBRIGHT_LIGHTING_DISABLED);
theWorld.getLights().setRGBScale(Lights.RGB_SCALE_2X);
theWorld.setAmbientLight(10, 15, 15);
/**
* Place the lightsources...
*/
theWorld.addLight(new SimpleVector(820, -150, -400), 5, 20, 15);
theWorld.addLight(new SimpleVector(850, -130, -580), 20, 18, 2);
theWorld.addLight(new SimpleVector(850, -130, -760), 15, 10, 15);
theWorld.addLight(new SimpleVector(1060, -170, -910), 20, 0, 0);
theWorld.addLight(new SimpleVector(760, -200, -990), 15, 10, 20);
theWorld.addLight(new SimpleVector(850, -230, -780), 0, 15, 25);
theWorld.addLight(new SimpleVector(600, -230, -770), 20, 25, 0);
theWorld.addLight(new SimpleVector(405, -230, -610), 18, 20, 25);
theWorld.addLight(new SimpleVector(340, -150, -370), 15, 20, 25);
theWorld.addLight(new SimpleVector(650, -170, -200), 15, 0, 0);
theWorld.addLight(new SimpleVector(870, -230, -190), 15, 20, 20);
theWorld.addLight(new SimpleVector(540, -190, -180), 15, 15, 15);
/**
* We are using fog. Please note that the fog implementation is not very well suited for
* any other fog color than black when using OpenGL's lighting model.
*/
theWorld.setFogging(World.FOGGING_ENABLED);
theWorld.setFogParameters(500, 0, 0, 0);
Config.farPlane=500;
/**
* Load the textures needed and add them to the TextureManager. We are loading the "numbers"
* texture for blitting the framerate as well as the weapon's environment map and all JPGs
* that can be found in the "textures"-directory. The 3DS file of the level contains
* materials that are pointing to these textures (identified by name).
*/
char c=File.separatorChar;
numbers=new Texture("textures"+c+"other"+c+"numbers.jpg");
texMan.addTexture("numbers", numbers);
texMan.addTexture("envmap", new Texture("textures"+c+"other"+c+"envmap.jpg"));
File dir=new File("textures");
String[] files=dir.list();
for (int i=0; i<files.length; i++) {
String name=files[i];
if (name.toLowerCase().endsWith(".jpg")) {
texMan.addTexture(name, new Texture("textures"+c+name));
}
}
/**
* Load and setup the weapon. To ease the placement of the weapon in the gameloop,
* we are transforming the mesh here too.
*/
Object3D[] miss=Loader.load3DS("3ds"+c+"weapon.3ds", 2);
weapon=miss[0];
weapon.rotateY(-(float) Math.PI/2f);
weapon.rotateZ(-(float) Math.PI/2f);
weapon.rotateX(-(float) Math.PI/7f);
// Make the rotations permanent
weapon.rotateMesh();
weapon.translate(6, 6, 10);
// Make the translation permanent
weapon.translateMesh();
weapon.setRotationMatrix(new Matrix());
weapon.setTranslationMatrix(new Matrix());
weapon.setTexture("envmap");
weapon.setEnvmapped(Object3D.ENVMAP_ENABLED);
weapon.setEnvmapMode(Object3D.ENVMAP_WORLDSPACE);
theWorld.addObject(weapon);
/**
* Load the level...
*/
Object3D[] levelParts=Loader.load3DS("3ds"+c+"ql.3ds", 20f);
level=new Object3D(0);
for (int i=0; i<levelParts.length; i++) {
Object3D part=levelParts[i];
/**
* The level is not rotated correctly after loading (something all Quake3 levels
* share when converted to 3DS-format, because Quake3 uses a different coordinate
* system than jPCT.
*/
part.setCenter(SimpleVector.ORIGIN);
part.rotateX((float)-Math.PI/2);
part.rotateMesh();
part.setRotationMatrix(new Matrix());
/**
* Merge all parts into one object. This is usefull for this level, because the parts
* don't represent sectors or zones but are widespreaded over the level, which would render
* an octree useless for this level. By merging them all, the octree can be used much
* more efficient.
*/
level=Object3D.mergeObjects(level, part);
}
/**
* Create triangle strips (good for OpenGL performance) and setup the collision
* detection mode. Furthermore, an octree is created for the level.
*/
level.createTriangleStrips(2);
level.setCollisionMode(Object3D.COLLISION_CHECK_OTHERS);
level.setCollisionOptimization(Object3D.COLLISION_DETECTION_OPTIMIZED);
OcTree oc=new OcTree(level, 100, OcTree.MODE_OPTIMIZED);
oc.setCollisionUse(OcTree.COLLISION_USE);
level.setOcTree(oc);
/**
* The level won't move, so...
*/
level.enableLazyTransformations();
/**
* Done! Now add the result to the world.
*/
theWorld.addObject(level);
/**
* Setup the elevator. The elevator is a more or
* less hardcoded entity in this level that serves
* demonstration purposes only. You'll most
* likely have to implement a more advanced elevator
* management if you want to use elevators at all.
*/
elevator=Primitives.getBox(15f,0.1f);
elevator.rotateY((float)Math.PI/4);
elevator.setOrigin(new SimpleVector(800,-90,-450));
elevator.setCollisionOptimization(Object3D.COLLISION_DETECTION_OPTIMIZED);
elevator.setCollisionMode(Object3D.COLLISION_CHECK_OTHERS);
elevator.setTexture("envmap");
elevator.setEnvmapped(Object3D.ENVMAP_ENABLED);
elevator.setEnvmapMode(Object3D.ENVMAP_CAMERASPACE);
theWorld.addObject(elevator);
/**
* Place the camera at the starting position.
*/
camera=theWorld.getCamera();
camera.setPosition(STARTING_POS);
/**
* Now build() all objects.
*/
theWorld.buildAllObjects();
/**
* This is needed for weapon movement, but has to be done after calling build()
* on the weapon because build() resets the rotation pivot to the object's
* (calculated) center.
*/
weapon.setRotationPivot(new SimpleVector(0, 0, 0));
/**
* Setup some optimizations for outdoor rendering (the level is not very outdoorish at
* all, but at least the framebuffer needs clearing because the level is not closed.
*/
Config.collideOffset=250;
Config.tuneForOutdoor();
/**
* Do some AWT setup work
*/
initializeFrame();
/**
* Here we go...!
*/
gameLoop();
}
/**
* This initializes the AWT frame either in fullscreen or in windowed mode.
* This is not a waterproof intialization, but i didn't want to do a AWT
* tutorial here (and i would be the wrong person to do this anyway...:-)).
* Change whatever you think that needs change here...
*/
private void initializeFrame() {
if (fullscreen) {
GraphicsEnvironment env=GraphicsEnvironment.getLocalGraphicsEnvironment();
device=env.getDefaultScreenDevice();
GraphicsConfiguration gc=device.getDefaultConfiguration();
frame=new Frame(gc);
frame.setUndecorated(true);
frame.setIgnoreRepaint(true);
device.setFullScreenWindow(frame);
if (device.isDisplayChangeSupported()) {
device.setDisplayMode(new DisplayMode(width, height, 32, 0));
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -