服务热线:13616026886

技术文档 欢迎使用技术文档,我们为你提供从新手到专业开发者的所有资源,你也可以通过它日益精进

位置:首页 > 技术文档 > JAVA > 新手入门 > 基础入门 > 查看文档

3d编程指南第三部分:粒子系统和立即模式渲染(2)

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)>>
  • 扫描关注微信公众号