|
TutorialMidlet import javax.microedition.lcdui.Command; import javax.microedition.lcdui.CommandListener; import javax.microedition.lcdui.Display; import javax.microedition.lcdui.Displayable; import javax.microedition.midlet.MIDlet; import javax.microedition.midlet.MIDletStateChangeException; public class TutorialMidlet extends MIDlet implements CommandListener { // A variable that holds the unique display private Display display = null; // The canvas private M3GCanvas canvas = null; // The MIDlet itself private static MIDlet self = null; /** Called when the application starts, and when it is resumed. * We ignore the resume here and allocate data for our canvas * in the startApp method. This is generally very bad practice. */ protected void startApp() throws MIDletStateChangeException { // Allocate display = Display.getDisplay(this); canvas = new M3GCanvas(30); // Add a quit command to the canvas // This command won''t be seen, as we // are running in fullScreen mode // but it''s always nice to have a quit command canvas.addCommand(new Command("Quit", Command.EXIT, 1)); // Set the listener to be the MIDlet canvas.setCommandListener(this); // Start canvas canvas.start(); display.setCurrent(canvas); // Set the self self = this; } /** Called when the game should pause, such as during a call */ protected void pauseApp() { } /** Called when the application should shut down */ protected void destroyApp(boolean unconditional) throws MIDletStateChangeException { // Method that shuts down the entire MIDlet notifyDestroyed(); } /** Listens to commands and processes */ public void commandAction(Command c, Displayable d) { // If we get an EXIT command we destroy the application if(c.getCommandType() == Command.EXIT) notifyDestroyed(); } /** Static method that quits our application * by using the static field ''self'' */ public static void die() { self.notifyDestroyed(); } } M3GCanvas import javax.microedition.lcdui.Graphics; import javax.microedition.lcdui.game.GameCanvas; import javax.microedition.m3g.Background; import javax.microedition.m3g.Camera; import javax.microedition.m3g.Graphics3D; import javax.microedition.m3g.Light; import javax.microedition.m3g.Transform; public class M3GCanvas extends GameCanvas implements Runnable { // Thread-control boolean running = false; boolean done = true; // If the game should end public static boolean gameOver = false; // Rendering hints public static final int STRONG_RENDERING_HINTS = Graphics3D.ANTIALIAS | Graphics3D.TRUE_COLOR | Graphics3D.DITHER; public static final int WEAK_RENDERING_HINTS = 0; public static int RENDERING_HINTS = STRONG_RENDERING_HINTS; // Key array boolean[] key = new boolean[5]; // Key constants public static final int FIRE = 0; public static final int UP = FIRE + 1; public static final int DOWN = UP + 1; public static final int LEFT = DOWN + 1; public static final int RIGHT = LEFT + 1; // Global identity matrix Transform identity = new Transform(); // Global Graphics3D object Graphics3D g3d = null; // The background Background back = null; // The global camera object Camera cam = null; // The particle system ParticleSystem ps = null; FountainEffect fx = null; /** Constructs the canvas */ public M3GCanvas(int fps) { // We don''t want to capture keys normally super(true); // We want a fullscreen canvas setFullScreenMode(true); // Load our camera loadCamera(); // Load our background loadBackground(); // Set up graphics 3d setUp(); } /** Prepares the Graphics3D engine for immediate mode rendering by adding a light */ private void setUp() { // Get the instance g3d = Graphics3D.getInstance(); // Add a light to our scene, so we can see something g3d.addLight(createAmbientLight(), identity); } /** Creates a simple ambient light */ private Light createAmbientLight() { Light l = new Light(); l.setMode(Light.AMBIENT); l.setIntensity(1.0f); return l; } /** When fullscreen mode is set, some devices will call * this method to notify us of the new width/height. * However, we don''t really care about the width/height * in this tutorial so we just let it be */ public void sizeChanged(int newWidth, int newHeight) { } /** Loads our camera */ private void loadCamera() { // Create a new camera cam = new Camera(); } /** Loads the background */ private void loadBackground() { // Create a new background, set bg color to black back = new Background(); back.setColor(0); } /** Draws to screen */ private void draw(Graphics g) { // Envelop all in a try/catch block just in case try { // Get the Graphics3D context g3d = Graphics3D.getInstance(); // First bind the graphics object. We use our pre-defined rendering hints. g3d.bindTarget(g, true, RENDERING_HINTS); // Clear background g3d.clear(back); // Bind camera at fixed position in origo g3d.setCamera(cam, identity); // Init particles if(ps == null) { fx = new FountainEffect(90); ps = new ParticleSystem(fx, 20); } // Emit the particles ps.emit(g3d); // Check controls for fountain rotation if(key[LEFT]) fx.setAngle(fx.getAngle() + 5); if(key[RIGHT]) fx.setAngle(fx.getAngle() - 5); // Quit if user presses fire if(key[FIRE]) TutorialMidlet.die(); } catch(Exception e) { reportException(e); } finally { // Always remember to release! g3d.releaseTarget(); } } /** Starts the canvas by firing up a thread */ public void start() { Thread myThread = new Thread(this); // Make sure we know we are running running = true; done = false; // Start myThread.start(); } /** Run, runs the whole thread. Also keeps track of FPS */ public void run() { while(running) { try { // Call the process method (computes keys) process(); // Draw everything draw(getGraphics()); flushGraphics(); // Sleep to prevent starvation try{ Thread.sleep(30); } catch(Exception e) {} } catch(Exception e) { reportException(e); } } // Notify completion done = true; } /** * @param e */ private void reportException(Exception e) { System.out.println(e.getMessage()); System.out.println(e); e.printStackTrace(); } /** Pauses the game */ public void pause() {} /** Stops the game */ public void stop() { running = false; } /** Processes keys */ protected void process() { int keys = getKeyStates(); if((keys & GameCanvas.FIRE_PRESSED) != 0) key[FIRE] = true; else key[FIRE] = false; if((keys & GameCanvas.UP_PRESSED) != 0) key[UP] = true; else key[UP] = false; if((keys & GameCanvas.DOWN_PRESSED) != 0) key[DOWN] = true; else key[DOWN] = false; if((keys & GameCanvas.LEFT_PRESSED) != 0) key[LEFT] = true; else key[LEFT] = false; if((keys & GameCanvas.RIGHT_PRESSED) != 0) key[RIGHT] = true; else key[RIGHT] = false; } /** Checks if thread is running */ public boolean isRunning() { return running; } /** checks if thread has finished its execution completely */ public boolean isDone() { return done; } } MeshFactory import javax.microedition.lcdui.Image; import javax.microedition.m3g.Appearance; import javax.microedition.m3g.Image2D; import javax.microedition.m3g.IndexBuffer; import javax.microedition.m3g.Mesh; import javax.microedition.m3g.PolygonMode; import javax.microedition.m3g.Texture2D; import javax.microedition.m3g.TriangleStripArray; import javax.microedition.m3g.VertexArray; import javax.microedition.m3g.VertexBuffer; /** * Static class that handles creation of code-generated Meshes */ public class MeshFactory { /** Creates a texture plane that is alpha-blended * * @param texFilename The name of the texture image file * @param cullFlags The flags for culling. See PolygonMode. * @param alpha The alpha value of blending. Is a full color in 0xAARRGGBB format * @return The finished textured mesh */ public static Mesh createAlphaPlane(String texFilename, int cullFlags, int alpha) { // Create a normal mesh Mesh mesh = createPlane(texFilename, cullFlags); // Make it blended MeshOperator.convertToBlended(mesh, alpha, Texture2D.FUNC_BLEND); return mesh; } /** * Creates a textured plane. * @param texFilename The name of the texture image file * @param cullFlags The flags for culling. See PolygonMode. * @return The finished textured mesh */ public static Mesh createPlane(String texFilename, int cullFlags) { // The vertrices of the plane short vertrices[] = new short[] {-1, -1, 0, 1, -1, 0, 1, 1, 0, -1, 1, 0}; // Texture coords of the plane short texCoords[] = new short[] {0, 255, 255, 255, 255, 0, 0, 0}; // The classes VertexArray vertexArray, texArray; IndexBuffer triangles; // Create the model''s vertrices vertexArray = new VertexArray(vertrices.length/3, 3, 2); vertexArray.set(0, vertrices.length/3, vertrices); // Create the model''s texture coords texArray = new VertexArray(texCoords.length / 2, 2, 2); texArray.set(0, texCoords.length / 2, texCoords); // Compose a VertexBuffer out of the previous vertrices and texture coordinates VertexBuffer vertexBuffer = new VertexBuffer(); vertexBuffer.setPositions(vertexArray, 1.0f, null); vertexBuffer.setTexCoords(0, texArray, 1.0f/255.0f, null); // Create indices and face lengths int indices[] = new int[] {0, 1, 3, 2}; int[] stripLengths = new int[] {4}; // Create the model''s triangles triangles = new TriangleStripArray(indices, stripLengths); // Create the appearance Appearance appearance = new Appearance(); PolygonMode pm = new PolygonMode(); pm.setCulling(cullFlags); appearance.setPolygonMode(pm); // Create and set the texture try { // Open image Image texImage = Image.createImage(texFilename); Texture2D theTexture = new Texture2D(new Image2D(Image2D.RGBA, texImage)); // Replace the mesh''s original colors (no blending) theTexture.setBlending(Texture2D.FUNC_REPLACE); // Set wrapping and filtering theTexture.setWrapping(Texture2D.WRAP_CLAMP, Texture2D.WRAP_CLAMP); theTexture.setFiltering(Texture2D.FILTER_BASE_LEVEL, Texture2D.FILTER_NEAREST); // Add texture to the appearance appearance.setTexture(0, theTexture); } catch(Exception e) { // Something went wrong System.out.println("Failed to create texture"); System.out.println(e); } // Finally create the Mesh Mesh mesh = new Mesh(vertexBuffer, triangles, appearance); // All done return mesh; } } MeshOperator import javax.microedition.m3g.CompositingMode; import javax.microedition.m3g.Mesh; /** * Performs some basic operations on Mesh objects */ public class MeshOperator { /** Sets the alpha blending of a mesh. Only meaningful if the mesh already is alpha blended */ public static void setMeshAlpha(Mesh m, int alpha) { m.getVertexBuffer().setDefaultColor(alpha); } /** * * @param m The mesh to convert to a blended one * @param alpha The alpha color to blend with * @param textureBlending The texture blending parameter. */ public static void convertToBlended(Mesh m, int alpha, int textureBlending) { // Set the alpha setMeshAlpha(m, alpha); // Fix the compositing mode CompositingMode cm = new CompositingMode(); cm.setBlending(CompositingMode.ALPHA); m.getAppearance(0).setCompositingMode(cm); m.getAppearance(0).getTexture(0).setBlending(textureBlending); } } Particle /** * Holds all the information of a particle. * A particle''s alpha is controlled directly by its life. Its alpha is always * life * 255. */ public class Particle { // The life of the particle. Goes from 1.0f to 0.0f private float life = 1.0f; // The degradation of the particle private float degradation = 0.1f; // The velocities of the particle private float[] vel = {0.0f, 0.0f, 0.0f}; // The position of the particle private float[] pos = {0.0f, 0.0f, 0.0f}; // The color of the particle (RGB format 0xRRGGBB) private int color = 0xffffff; /** Empty initialization */ public Particle() { } /** * Initializes the particle * @param velocity Sets the velocity * @param position Sets the position * @param color Sets the color (no alpha) */ public Particle(float[] velocity, float[] position, int color) { setVel(velocity); setPos(position); this.setColor(color); } /** * @param life The life to set. */ void setLife(float life) { this.life = life; } /** * @return Returns the life. */ float getLife() { return life; } /** * @param vel The vel to set. */ void setVel(float[] tvel) { System.arraycopy(tvel, 0, vel, 0, vel.length); } /** * @return Returns the vel. */ float[] getVel() { return vel; } /** * @param pos The pos to set. */ void setPos(float[] tpos) { System.arraycopy(tpos, 0, pos, 0, pos.length); } /** * @return Returns the pos. */ float[] getPos() { return pos; } /** * @param color The color to set. */ void setColor(int color) { this.color = color; } /** * @return Returns the color. */ int getColor() { return color; } /** * @param degradation The degradation to set. */ public void setDegradation(float degradation) { this.degradation = degradation; } /** * @return Returns the degradation. */ public float getDegradation() { return degradation; } } ParticleEffect import javax.microedition.m3g.Graphics3D; /** * The interface that determines which effect the particle engine will display. * The ParticleEffect class also holds information about the bitmap used * for displaying particles (if any) */ public interface ParticleEffect { // Initializes a particle public void init(Particle p); // Updates a particle public void update(Particle p); // Renders a particle public void render(Particle p, Graphics3D g3d); } BitmapParticleEffect import javax.microedition.m3g.Graphics3D; import javax.microedition.m3g.Mesh; import javax.microedition.m3g.PolygonMode; import javax.microedition.m3g.Transform; /** * Represents a particle effect that uses a bitmap. */ public abstract class BitmapParticleEffect implements ParticleEffect { // The mesh Mesh mesh = null; // The transformation matrix Transform trans = new Transform(); // The scale float scale = 1.0f; /** Initializes the bitmap used to render particles */ public BitmapParticleEffect(String filename, float scale) { // Load the plane with the wanted texture mesh = MeshFactory.createAlphaPlane(filename, PolygonMode.CULL_BACK, 0xffffffff); // Make sure we set the scale this.scale = scale; } /** * @see ParticleEffect#render(Particle, Graphics3D) */ public void render(Particle p, Graphics3D g3d) { // Calculate the alpha int alpha = (int)(255 * p.getLife()); // Create the color int color = p.getColor() | (alpha << 24); // Set alpha MeshOperator.setMeshAlpha(mesh, color); // Transform trans.setIdentity(); trans.postScale(scale, scale, scale); float[] pos = p.getPos(); trans.postTranslate(pos[0], pos[1], pos[2]); // Render g3d.render(mesh, trans); } } FountainEffect import java.util.Random; /* * Created on 2005-aug-31 */ /** * Creates a nice fountain effect for the particles, that shoots particles * in a certain direction, determined by its angle. The angle can be changed in real-time. */ public class FountainEffect extends BitmapParticleEffect { // The angle of particle emission private int angle = 90; // The sine and cosine of the current angle private float[] trig = {1.0f, 0.0f}; // The emitting origin private float[] pos = {0.0f, 0.0f, 0.0f}; // The randomizer Random rand = null; /** * @param angle The angle of particle emission */ public FountainEffect(int angle) { // Init the bitmap super("/res/particle.png", 0.05f); // Set the angle setAngle(angle); // Get randomizer rand = new Random(); } /** * @see ParticleEffect#init(Particle) */ public void init(Particle p) { // Set the particle''s life p.setLife(1.0f); // Set the particle''s position p.setPos(pos); // Create the particle''s velocties float[] vel = new float[3]; // We want velocities from 0.2f to 1.0f float xyvel = rand.nextFloat() * 0.8f + 0.2f; // We want the particle to die slowly p.setDegradation(xyvel / 18); // Set velocities according to trigonometry with a small deviation vel[0] = xyvel * trig[1] + rand.nextFloat() * 0.125f - 0.0625f; vel[1] = xyvel * trig[0] + rand.nextFloat() * 0.125f - 0.0625f; // No movement in depth vel[2] = 0.0f; // Set the velocity p.setVel(vel); // Set the random color int r = (int)(120 * rand.nextFloat()) + 135; int g = (int)(120 * rand.nextFloat()) + 135; int b = (int)(120 * rand.nextFloat()) + 135; int col = (r << 16) | (g << 8) | b; p.setColor(col); } /** * @see ParticleEffect#update(Particle) */ public void update(Particle p) { // Simply update position float[] ppos = p.getPos(); float[] vel = p.getVel(); ppos[0] += vel[0]; ppos[1] += vel[1]; ppos[2] += vel[2]; // Update life p.setLife(p.getLife() - p.getDegradation()); // Check life. If it is dead, we just reinit it if(p.getLife() < -0.001f) { init(p); } } /** * @param angle The angle to set. */ public void setAngle(int angle) { this.angle = angle; trig[0] = (float)Math.sin(Math.toRadians(angle)); trig[1] = (float)Math.cos(Math.toRadians(angle)); } /** * @return Returns the angle. */ public int getAngle() { return angle; } /** * @param pos The pos to set. */ void setEmittingOrigin(float[] pos) { this.pos = pos; } /** * @return Returns the pos. */ float[] getEmittingOrigin() { return pos; } } ParticleSystem import javax.microedition.m3g.Graphics3D; /** * Manages emission of particles in our 3D world */ public class ParticleSystem { // The effect private ParticleEffect effect = null; // The particles Particle[] parts = null; /** * Creates a particle system that emits particles according to a defined effect. * @param effect The effect that controls the behaviour of the particles * @param numParticles The number of particles to emit */ public ParticleSystem(ParticleEffect effect, int numParticles) { // Copy the effect setEffect(effect); // Init the particles parts = new Particle[numParticles]; for(int i = 0; i < numParticles; i++) { parts[i] = new Particle(); effect.init(parts[i]); } } /** The method that does it all. Needs to be called every tick of a game loop */ public void emit(Graphics3D g3d) { for(int i = 0; i < parts.length; i++) { getEffect().update(parts[i]); getEffect().render(parts[i], g3d); } } /** * @param effect The effect to set. */ public void setEffect(ParticleEffect effect) { this.effect = effect; } /** * @return Returns the effect. */ public ParticleEffect getEffect() { return effect; } }
原文地址:http://developer.sonyericsson.com/site/global/techsupport/tipstrickscode/mobilejava3d/p_java3d_tutorial_part3_compliments_redikod.jsp
源文件(Java 类和资源)>>
应用程序包 (JAR/JAD)>>
|