⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 life3d.java

📁 3D演示例子,初步认识3D的绘制,编程. 适合初学者!
💻 JAVA
📖 第 1 页 / 共 2 页
字号:
/******************************************************************************//** *	@file	Life3D.java *	@brief	Implements a 3D version of Conway's "game of life". * *	Copyright (C) 2004 Superscape plc * *	This file is intended for use as a code example, and *	may be used, modified, or distributed in source or *	object code form, without restriction, as long as *	this copyright notice is preserved. * *	The code and information is provided "as-is" without *	warranty of any kind, either expressed or implied. *//******************************************************************************/package com.superscape.m3g.wtksamples.life3d;import javax.microedition.midlet.MIDlet;import javax.microedition.midlet.MIDletStateChangeException;import javax.microedition.lcdui.*;import java.util.Random;import java.util.Timer;import java.util.TimerTask;import javax.microedition.m3g.*;/** * 	Life3D Midlet - implements a 3D version of Conway's "game of life". * *	The "game of life" is an interesting system discovered by John Conway in 1968. *	This is a generalization of that system to 3D. * *	The game grid is divided into cubical cells, each of which can be alive or dead. *	A live cell is indicated by a cube at that position; a dead cell is vacant. * *	At each generation, the number of living neighbours for each cell is counted, and *	the state of the cell in the next generation is determined by that count. Each has *	26 possible neighbors (including ones that are diagonal in one or more directions), *	and if a live cell has fewer than 4 live neighbors, it dies of loneliness. If it has *	more than 5 live neighbors, it dies of overcrowding. A vacant cell will have a new *	cell created inside it if it has exactly 4 live neighbors. * *	This apparently simple rule, when applied to all the cells simultaneously, leads *	to surprisingly complex behavior. Certain patterns of cells are stable, some die *	out, some flip between two or more configurations, and some actually progress through *	the grid in an ordered manner (these are called "gliders"). * *	Although the grid starts in a random state, we have added the most interesting patterns *	we have found to a pattern library, which can be accessed from the keyboard. * *	Keys: *		0: Pause generation *		1: Full speed (1 generation per frame) *		2: Increase generation speed *		3: Decrease generation speed *		4: Load previous pattern in library *		5: Load next pattern in library *		*: Load random pattern * *	If a pattern dies out completely, then the game restarts with a random pattern again. */public class Life3D extends MIDlet implements CommandListener{    /**     * 	Default constructor.     *     *  This just sets up a canvas and attaches it to the display. The actual     *	initialization happens in startApp.     */    public Life3D()    {		// Set up the user interface.        myDisplay = Display.getDisplay(this);        myCanvas = new CallbackCanvas(this);        myCanvas.setCommandListener(this);        myCanvas.addCommand(exitCommand);    }    /**     *	This initializes the game state, and generates a M3G world programmatically.     */    public void startApp() throws MIDletStateChangeException    {    	// Catch excpetions here before they go too far.        try        {        	// Create a new M3G world.			myWorld = new World();			// In this world, we have a root group which will contain everything else			// and which is tilted 15 degrees towards the camera.			Group rootGroup2 = new Group();			myWorld.addChild(rootGroup2);			rootGroup2.setOrientation(15.0f,1.0f,0.0f,0.0f);			// Under this, we have a second group which will be the one we rotate			// to get an all-round view of the game grid.			rootGroup = new Group();			rootGroup2.addChild(rootGroup);			// We now create a parallel camera - parallel projection is faster than			// perspective, and since we are rendering 512 separate objects that's a			// saving worth having.			Camera myCamera = new Camera();			myWorld.addChild(myCamera);			myWorld.setActiveCamera(myCamera);			myCamera.setParallel(CUBESIZE*1.5f, 1.0f, -CUBESIZE, CUBESIZE);			// This is geometry data for the shape that represents a single cell - a cube. 			// It consists of 6 triangle strips, one for each face, each of which			// has 2 triangles (and therefore 4 vertices). We will set the vertex			// colors so that the colors of the sides are different from each other.						// This data is shared by all the cells in the grid, rather than each having			// its own copy. This keeps memory overhead down.			int[][] aaStripLengths = {{4}, {4}, {4}, {4}, {4}, {4}};			// These are the vertex positions			short[] aPos =			{				// Front				-1, -1,  1,	// B				 1, -1,  1,	// C				-1,  1,  1,	// A				 1,  1,  1,	// D				// Bottom				-1, -1, -1,	// F				 1, -1, -1,	// G				-1, -1,  1,	// B				 1, -1,  1,	// C				// Top				-1,  1,  1,	// A				 1,  1,  1,	// D				-1,  1, -1,	// E				 1,  1, -1,	// H				// Right				 1,  1,  1,	// D				 1, -1,  1,	// C				 1,  1, -1,	// H				 1, -1, -1,	// G				// Left				-1, -1,  1,	// B				-1,  1,  1,	// A				-1, -1, -1,	// F				-1,  1, -1,	// E				// Back				 1, -1, -1,	// G				-1, -1, -1,	// F				 1,  1, -1,	// H				-1,  1, -1	// E			};			// These are the colors for the vertices			byte[] aCol =			{				// Front				-1, 0, 0,				-1, 0, 0,				-1, 0, 0,				-1, 0, 0,				// Bottom				 0, -1, 0,				 0, -1, 0,				 0, -1, 0,				 0, -1, 0,				// Top				 0,  0, -1,				 0,  0, -1,				 0,  0, -1,				 0,  0, -1,				// Right				-1, -1,  0,				-1, -1,  0,				-1, -1,  0,				-1, -1,  0,				// Left				-1,  0, -1,				-1,  0, -1,				-1,  0, -1,				-1,  0, -1,				// Back				 0, -1, -1,				 0, -1, -1,				 0, -1, -1,				 0, -1, -1,			};			// Calculate the number of submeshes and vertices directly from the sizes			// of the arrays. This prevents us getting a mismatch if we decide to change			// the cells to a different shape later.			int cSubmeshes = aaStripLengths.length;			int cVertices = aPos.length/3;			// We will share a default appearance between all the faces on the cube. Each			// face is a separate "submesh" - it can have a separate appearance if we wish.			Appearance app = new Appearance();			// We need to specify an appearance and the submesh data for each face.			Appearance[] appa = new Appearance[cSubmeshes];			IndexBuffer[] iba = new IndexBuffer[cSubmeshes];			int startIndex=0;			for(int i=0;i<cSubmeshes;i++)			{				// We use the same apppearance for each.				appa[i]=app;				// And we create a new triangle strip array for each submesh.				// The start index for each one just follows on from previous submeshes.				iba[i] = new TriangleStripArray(startIndex, aaStripLengths[i]);				for(int j=0; j<aaStripLengths[i].length;j++)					startIndex+=aaStripLengths[i][j];			}			// Now we create a new vertex buffer that contains all the above information			VertexBuffer vertexBuffer = new VertexBuffer();			vertexBuffer.setDefaultColor(0xFFFFFFFF); // white			{				// Copy the vertex positions into a VertexArray object				VertexArray vaPos = new VertexArray(cVertices, 3, 2);				vaPos.set(0, cVertices, aPos);				vertexBuffer.setPositions(vaPos, 0.40f, null);			}			{				// Copy the vertex colors into a VertexArray object				VertexArray vaCols = new VertexArray(cVertices, 3, 1);				vaCols.set(0, cVertices, aCol);				vertexBuffer.setColors(vaCols);			}			// Create all the cells, in a random state.			// The X, Y and Z positions of the cells range from -CUBESIZE/2 to +CUBESIZE/2 units.			// They are all children of the rootGroup object.			cells = new Mesh[NUMCELLS];			nextState = new byte[NUMCELLS];			currentState = new byte[NUMCELLS];			rand = new Random();			int index = 0;			for(int i=0; i<CUBESIZE; i++)			{				float x = (i*2 - CUBESIZE) * 0.5f;				for(int j=0; j<CUBESIZE; j++)				{					float y = (j*2 - CUBESIZE) * 0.5f;					for(int k=0; k<CUBESIZE; k++)					{						float z = (k*2 - CUBESIZE) * 0.5f;						Mesh m = new Mesh(vertexBuffer, iba, appa);						m.setTranslation(x,y,z);						rootGroup.addChild(m);						// This test gives a 1 in 4 chance of being alive at the start				    	currentState[index]=(rand.nextInt()>0x40000000)?(byte)1:(byte)0;						cells[index++] = m;					}				}			}			// Attach to display	        myDisplay.setCurrent(myCanvas);			// Force a repaint so that we get the update loop started.            myCanvas.repaint();        }        catch(Exception e)        {            e.printStackTrace();        }    }    /**     *	If cell[i] is alive, this increments the "live neighbor" count	 *	on all the neighboring cells. This is more efficient than counting	 *	the neighboring cells for each cell, because there are likely to be	 *	fewer live cells than dead cells.	 *	 *	The cube wraps around, so that the neighbor to the right of a cell	 *	in the last row is in fact in the first row. The same happens with 	 *	columns and planes. We speed things up here by using bit operations	 *	to effect this wrapping (which is why CUBESIZE must be a power of 2)	 *	and we also unroll the loop.     */    public void updateNeighbours(int i)    {		if(currentState[i]!=0)		{	    	int ix0 = (i-STEPX)&MASKX;	    	int iy0 = (i-STEPY)&MASKY;	    	int iz0 = (i-STEPZ)&MASKZ;	    	int ix1 = (i)&MASKX;	    	int iy1 = (i)&MASKY;	    	int iz1 = (i)&MASKZ;	    	int ix2 = (i+STEPX)&MASKX;	    	int iy2 = (i+STEPY)&MASKY;	    	int iz2 = (i+STEPZ)&MASKZ;			++nextState[ix0|iy0|iz0];			++nextState[ix0|iy0|iz1];			++nextState[ix0|iy0|iz2];			++nextState[ix0|iy1|iz0];			++nextState[ix0|iy1|iz1];			++nextState[ix0|iy1|iz2];			++nextState[ix0|iy2|iz0];			++nextState[ix0|iy2|iz1];			++nextState[ix0|iy2|iz2];			++nextState[ix1|iy0|iz0];			++nextState[ix1|iy0|iz1];			++nextState[ix1|iy0|iz2];			++nextState[ix1|iy1|iz0];	//!		++nextState[ix1|iy1|iz1];			++nextState[ix1|iy1|iz2];			++nextState[ix1|iy2|iz0];			++nextState[ix1|iy2|iz1];			++nextState[ix1|iy2|iz2];	   		++nextState[ix2|iy0|iz0];			++nextState[ix2|iy0|iz1];			++nextState[ix2|iy0|iz2];			++nextState[ix2|iy1|iz0];			++nextState[ix2|iy1|iz1];			++nextState[ix2|iy1|iz2];			++nextState[ix2|iy2|iz0];			++nextState[ix2|iy2|iz1];			++nextState[ix2|iy2|iz2];		}    }    /**     *	Works out current alive/dead state based on neighbour count.     *	If a cell is alive, it will die of loneliness if it has at fewer than     *	minSurvive neighbors, but if it has more than maxSurvive neighbors it     *	will die of overcrowding. If a cell has between minBirth and maxBirth     *	neighbours, and it is currently dead, a new cell is born in that position.     */    public void updateState(int i)    {    	byte count = nextState[i];    	nextState[i]=0;		if(currentState[i]==0)		{        	currentState[i]=(count>=minBirth && count<=maxBirth)?(byte)1:(byte)0;  		}        else        {        	currentState[i]=(count>=minSurvive && count<=maxSurvive)?(byte)1:(byte)0;        }		// After calculating the new state, set the appropriate rendering enable for the		// cell object in the world, so we can see it. We take advantage of this test to		// count the current live population, too.		if(currentState[i]!=0)		{	        cells[i].setRenderingEnable(true);	        ++population;	 	}		else	        cells[i].setRenderingEnable(false);    }    /**     * On pause, simply shut everything down.     */    public void pauseApp()    {        myRefreshTask.cancel();	myRefreshTask = null;	// Release resources.	myWorld = null;    }    /**     * On exit, simply shut everything down     */    public void destroyApp(boolean unconditional) throws MIDletStateChangeException    {        myRefreshTimer.cancel();        myRefreshTimer = null;        myRefreshTask = null;		// Release resources.        myWorld = null;		myCanvas = null;    }    /**     *	MIDlet paint method.     *     * 	This is called back from the inner Canvas class. It renders the current state of the     *	cells, then updates them and schedules another update.     */    public void paint(Graphics g)    {

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -