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
闽公网安备 35060202000074号