Android遊戲之抽象『屏幕』

Android遊戲之抽象『屏幕』

設計抽象『屏幕』SCREEN類.為以後屏幕設計提供模板.update()更新所有對像.而present()則負責渲染. deltaTime為每次調用時間間隔. pause()與resume()當遊戲『暫停』與『恢復』時調用. 而dispose()則在遊戲退出時銷毀所有資源.釋放『記憶體』並保存設置.

public abstract class SCREEN {

public abstract void update(float deltaTime);// 更新

public abstract void present(float deltaTime);// 渲染

public abstract void pause();// 暫停

public abstract void resume();// 恢復

public abstract void dispose();// 清除/銷毀

public abstract boolean back();//檢查返會鍵

}

另需要『屏幕切換系統』GAME.每當設換屏幕時首先『暫停』然後『銷毀』資源並保存設置.然後設定新屏幕並『恢復』與『更新』.

public class GAME {

static private SCREEN  screen = null;// 當前屏幕

設置當前屏幕

static public void setCurrentScreen(SCREEN newScreen){

if(screen != null){

screen.pause();// 暫停

screen.dispose();// 銷毀

}

screen = newScreen;

screen.resume();// 恢復

screen.update(0);// 更新

}

獲取當前屏幕

static public SCREEN getCurrentScreen() {

return screen;

}

}

Android遊戲之紋理區域

Android遊戲之紋理區域

『紋理區域』指『紋理』中『矩形區域』.2D紋理通常尺寸較小.可以將多個2D紋理放在單一個紋理圖中.以提升OpenGL ES渲染性能.將其像素座標到紋理座標轉進行封裝.u1,v1為紋理座標左上角.u2,v2為紋理座標右下角.以確定紋理區域.值範圍0~1

public class REGION {

public TEXTURE texture;// 紋理

public float u1,v1,u2,v2;// 紋理坐標

像素坐標轉紋理坐標.輸入『像素』左上角與『寬和高』

public REGION(TEXTURE texture,float x,float y,float width,float height){

u1 = x/(float)texture.width;

v1 = y/(float)texture.height;

u2 = u1 + width/(float)texture.width;

v2 = v1 + height/(float)texture.height;

this.texture = texture;

}

}

Android遊戲之精靈批處理

Android遊戲之精靈批處理

OpenGL ES盡可能每次渲染多個精靈.以提高渲染性能.為此需要知道精靈『位置』『尺寸』『紋理區域』.『批處理』將多個渲染合拼在一起.這對GPU有利.批處理設立浮點數『緩存』保存頂點.該緩存區初此時需清空.定義『批處理』結構BATCHER.

public class BATCHER {

成員Buffer為浮點型數組用於存儲頂點.

private static float[] buffer;

成員indices為短整形索引.以三角形排列用於儲存頂點.

public static short[] indices ;

頂點列表用於批處理渲染

private static VERTICES vertices;

緩存寫入索引初此為零

private static int index = 0;

精零數量初此為零

public static int num = 0;

初次批處理.max精靈為最大量.

public static void Init(int max){

分配2D精靈頂點緩存,每個精靈有4頂點,每頂點要4個浮點數(空間坐標x,y兩個,紋理坐標u,v兩個)

buffer = new float[max44];

分配頂點緩存.『頂點』『紋理座標』『索引』

vertices = new VERTICES(max * 4, max*6, false,true);

分配索引每個精靈6個索引

indices = new short[max*6];

int len = indices.length;// 索引數組長度

index = 0;// 緩存寫入索引

num = 0;//  精零數量

生成頂點索引

for (int i=0,j=0; i < len; i += 6, j += 4) {

indices[i + 0] = (short)(j + 0);

indices[i + 1] = (short)(j + 1);

indices[i + 2] = (short)(j + 2);

indices[i + 3] = (short)(j + 2);

indices[i + 4] = (short)(j + 3);

indices[i + 5] = (short)(j + 0);

}

設置頂點索引

vertices.SetIndices(indices, 0, indices.length);

}

準備進行批處理渲染.首先綁定紋理.並將『精零數量』『緩存索引』置零

public static void Begin(TEXTURE texture){

texture.Bind();// 綁定紋理

num = 0;//  精零數量

index = 0;// 緩存寫入索引

}

結束批處理渲染.將頂點提交給OpenGL數組並觸發.綁定頂點數據後進形三角形渲染.然後取消數據綁定.每次調用繪畫時.向緩存區中添加4個頂點參數為『位置』『顏色』『索引』『紋理區域』

public void boolean End(){

vertices.SetVertices(buffer,0,index);

vertices.Bind();

vertices.Draw(GL10.GL_TRIANGLES, 0, num * 6);

vertices.Unbind();

}

批處理繪畫計算精靈中心『位置』及『寬和高』.和『紋理區域』.生成精靈『左下角』與『右上角』『空間座標』與『紋理座標』

public static void Draw(float x,float y,float width,float height,REGION region){

float halfWidth = width/2.0f;// 寬度一半

float halfHeight = height/2.0f;//高度一半

float x1 = x – halfWidth;

float y1 = y – halfHeight;

float x2 = x + halfWidth;

float y2 = y + halfHeight;

buffer[index++] = x1;

buffer[index++] = y1;

buffer[index++] = region.u1;

buffer[index++] = region.v2;

buffer[index++] = x2;

buffer[index++] = y1;

buffer[index++] = region.u2;

buffer[index++] = region.v2;

buffer[index++] = x2;

buffer[index++] = y2;

buffer[index++] = region.u2;

buffer[index++] = region.v1;

buffer[index++] = x1;

buffer[index++] = y2;

buffer[index++] = region.u1;

buffer[index++] = region.v1;

++num;

}

}

在調用時首先清理緩存並存入紋理.但只能對使用同一紋理精靈進行批處理.最後結束渲染.如下:

BATCHER.Begin(Texture);

BATCHER.Draw(X,Y,WIDTH,HEIGHT,Region);

BATCHER.End();

Android遊戲之頂點索引

Android遊戲之頂點索引

OpenGL均採用三角形列表進行渲染.每個三角形都有三個頂點.在有些情況下兩個或多個三角形會共用頂點.如上圖有兩個頂點具有相同『位置』『顏色』『紋理座標』.但甘浪費空間.更好解卻方法是將所有頂點保存在列表.而三角形頂點保存索引.OpenGL ES要求索引值使用短整數或字節.即OpenGL ES每次最多渲染65536個頂點.

我地需要一個Vertices類,用於存儲每個頂點『位置』『顏色』與『紋理座標』,並且它需要兩個選項.頂點是否『顏色』與『紋理座標』

public class VERTICES {

boolean color_have = false;//  擁有顏色

boolean texture_have =false;// 擁有紋理坐標

int vertex_size = 0;// 每個頂點所占大小

使用FloatBuffer保存頂點

FloatBuffer  vertex_array = null;

使用ShortBuffer頂點索引

ShortBuffer index_array = null;

頂點隊列分配記憶體,vertex_max為最大頂點量, index_max為最大索引量

VERTICES(int vertex_max,int index_max,boolean color_have,boolean texture_have){

this.color_have  = color_have;//  擁有頂點顏色

this.texture_have = texture_have;// 擁有紋理坐標

計算每頂點所占大小.顏色占4單元.紋理座標占2單元.2D座標占2單元.每個整數占4字節

int vertex_size = (2 + (color_have?4:0) + (texture_have?2:0) ) * 4;

因為OpenGL ES是以C API結口提供.無法直接使用JAVA數組.因此你需要C數組系統堆棧記憶體.而非JAVA虛擬機記憶體.需要 FloatBuffer分配頂點記憶體.

vertex_max為最大頂點量.

ByteBuffer buffer = ByteBuffer.allocateDirect(vertex_size * vertex_max);

將『網絡字節』改為『主機字節』或稱為『CPU字節』

buffer.order(ByteOrder.nativeOrder());

獲取整數數組

vertex_array = buffer.asIntBuffer();

每個短整形占兩個字節.index_max為最大索引量

buffer = ByteBuffer.allocateDirect(index_max * Short.SIZE/8);

將『網絡字節』改為『主機字節』

buffer.order(ByteOrder.nativeOrder());

頂點短整數數組

index_array = buffer.asShortBuffer();

}

將頂點提交給OpenGL數組並觸發

public void SetVertices(float[] vertices,int offset,int count){

vertex_array.clear();// 清空緩存.設定當前位置

int len = offset + count;

for(int i=offset, j=0; i < len; i++, j++)

vertex_Buffer[j] = Float.floatToRawIntBits(vertices[i]);

vertex_array.put(vertex_Buffer, 0, count); // 寫入數據.移動當前位置

vertex_array.flip();// 觸發

}

將頂點索引提交給OpenGL數組

public void SetIndices(short[] indices,int offset,int count) {

index_array.clear();// 清空緩存.設定當前位置

index_array.put(indices, offset, count); // 寫入數據.移動當前位置

index_array.flip();// 觸發

}

綁定數據

public void Bind(){

GL10  gl = GRAPHICS.gl;

啟用頂點數組

gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);

設置當前寫入位置0

vertex_array.position(0);

設置頂點指針,每個頂點兩個元素.xy兩分量

gl.glVertexPointer(2, GL10.GL_FLOAT, vertex_size, vertex_array);

if(color_have == true){//顏色

啟用頂點顏色數組

gl.glEnableClientState(GL10.GL_COLOR_ARRAY);

設置當前寫入位置2

vertex_array.position(2);

設置顏色指針,RGBA四分量

gl.glColorPointer(4, GL10.GL_FLOAT, vertex_size, vertex_array);

}

if(texture_have ){// 紋理坐標

啟用紋理坐標數組

gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);

vertex_array.position(color_have?6:2);// 寫入位置

設置紋理坐標指針,UV兩分量

gl.glTexCoordPointer(2, GL10.GL_FLOAT, vertex_size, vertex_array);

}

}

取消綁定數據

public void Unbind(){

GL10 gl = GRAPHICS.gl;

關閉頂點紋理數組

if(color_have)

gl.glDisableClientState(GL10.GL_COLOR_ARRAY );

關閉頂點顏色數組

if(texture_have)

gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);

}

繪畫三角形

public void Draw(int mode,int offset,int count){

GL10 gl = GRAPHICS.gl;

繪畫頂點

if(index_array != null){// 繪畫

index_array.position(offset);//

gl.glDrawElements(mode, count, GL10.GL_UNSIGNED_SHORT, index_array);

}

else{

gl.glDrawArrays(mode, offset, count);

}

}

}

Android遊戲之『軸對齊邊界盒』碰撞

Android遊戲之『軸對齊邊界盒』碰撞

大部分模形都適合使用『圓形碰撞』.但若模形呈長條形則適合使用『矩形碰撞』.也稱為『軸對齊邊界盒碰撞』.特點是頂底邊與X軸平行,左右邊與Y軸平行.碰撞算法以包圍著對象最小矩形.但缺點是無法隨物體旋轉.速度快但精度較差.若定義矩形則由中心位置與長寬所組成.

public class RECT2D {

矩形中心位置

public VECTOR2D center;

矩形寬與高

public float  width;

public float  height;

購造『軸對齊邊界盒』輸入中心位置與寬高.

public RECT2D(float x,float y,float width,float height){

this.center = new VECTOR2D(x, y);    // 中心點

this.width  = width;

this.height = height;

}

『點』與『矩形』碰撞.若點為於四條邊之內則發生碰撞

public boolean overlap(VECTOR2D point){

if(point.x  < center.x + width/2 &&

point.x  > center.x – width/2 &&

point.y  < center.y + height/2 &&

point.y  > center.y – height/2 )

return true;

else

return false;

}

兩矩形碰撞測試,原點在左下角.算法睇上圖有D複雜.『矩形1左邊』在『矩形2右邊』之左則.『矩形1右邊』在『矩形2左邊』之右則.『矩形1底邊』在『矩形2頂邊』之下則.『矩形1頂邊』在『矩形2底邊』之上則.只要全部符合則兩矩形重疊.

public boolean overlap(RECT2D rect){

if(center.x – width/2 < rect.center.x + rect.width/2 &&

center.x + width/2 > rect.center.x – rect.width/2 &&

center.y – height/2 < rect.center.y + rect.height/2 &&

center.y + height/2 > rect.center.y – rect.height/2 )

return true;

else

return false;

}

『圓形』與『矩形』碰撞.原點在左下角.需先計算『矩形』與『圓心』之『最近點』.『圓心』在『矩形』之外.則『最近點』落在『矩形』邊緣之上.如果『圓心』在『矩形』之內.則『最近點』是『圓心』.然後計算『圓心』與『最近點』之距離.若小於『圓半徑』內則發生重疊.

public boolean overlap(CIRCLE2D circle){

float closestX = circle.center.x; // 圓心座標X

float closestY = circle.center.y;// 圓心座標Y

if(circle.center.x < center.x – width/2)

closestX = center.x – width/2;

else

if(circle.center.x > center.x + width/2)

closestX = center.x + width/2;

if(circle.center.y < center.y – height/2)

closestY = center.y – height/2;

else

if(circle.center.y > center.y + height/2)

closestY = center.y + height/2;

if(circle.center.DistSquared(closestX,closestY) < circle.radius * circle.radius)

return true; // 『圓』內則發生碰撞

else

return false; // 無發生碰撞

}

}

Android遊戲之2D圓形碰撞

Android遊戲之2D圓形碰撞

當物體移動並相互發生作用.需進行碰撞撿測.若重疊便發生碰撞.常見碰撞算法是通過『圓形邊界球』.它是包圍著對象最小圓. 無需隨物體旋轉而旋轉.所以速度最快之算法但精度較差.它由『圓心』與『半徑』所組成.

public class CIRCLE2D{

中心位置

public VECTOR2D center;

半徑

public float radius;

購造圓形邊界球,輸入中心位置與半徑.

public CIRCLE2D(float x,float y,float radius){

this.center = new VECTOR2D(x,y);

this.radius = radius;

}

『圓』與『點』碰撞檢測.計算『圓心』與『點』之距離.若距離小於『圓半徑』則發生碰撞.

public boolean overlap(VECTOR2D point){

float distance = center.Dist(point);

if(distance < radius  )

return true;// 發生碰撞

else

return false;// 無發生碰撞

}

兩圓形碰撞檢測.計算兩圓心『距離』.若『距離』小於兩圓半徑之和則發生碰撞

public boolean overlap(CIRCLE2D circle){

float distance = center.Dist(circle.center);// 兩圓之距

if(distance <= radius + circle.radius)

return true;// 發生碰撞

else

return false;// 無發生碰撞

}

『圓形』與『矩形』碰撞算法最為複雜.需先計算『矩形』與『圓心』最近之點.然後計算『圓心』與『最近點』之距離.若此點在『圓』內則發生重疊.

public boolean overlap(RECT2D rect){

float closestX = center.x; // 最接近X

float closestY = center.y;// 最接近Y

if(center.x < rect.center.x – rect.width/2)

closestX = rect.center.x – rect.width/2;

else

if(center.x > rect.center.x + rect.width/2)

closestX = rect.center.x + rect.width/2;

if(center.y < rect.center.y – rect.height/2)

closestY = rect.center.y – rect.height/2;

else

if(center.y > rect.center.y + rect.height/2)

closestY = rect.center.y + rect.height/2;

if(center.Dist(closestX,closestY) < radius)

return true; // 『圓』內則發生碰撞

else

return false; // 無發生碰撞

}

}

 

Android遊戲之FPS

Android遊戲之FPS

遊戲性能最重要指標FPS『每秒渲染幀量』遊戲越流暢FPS越高.不過所有Android手機都限制FPS最高60幀.若遊戲流暢FPS要高於30幀.下面代碼實現幀計數器

public class FPS {

返回納秒級時鐘.一納秒是一秒十億分之一

static private long startTime = System.nanoTime();

幀計數初此為零

static private int   frames = 0;

計算幀個數並在LOG『日誌』輸出.在GLSurfaceView.onDrawFrame(GL10 gl)中調用

static public void logFrame(){

幀個數加一

++frames;

每1秒輸出一次

if(System.nanoTime() – startTime >= 1000000000){

在LOG『日誌』輸出

Log.d(“FPS”,String.valueOf(frames));

幀個數清零

frames = 0;

更新納秒級時鐘

startTime = System.nanoTime();

}

}

}

 

 

Android遊戲之2D矢量

Android遊戲之2D矢量

『矢量』Vector也稱『向量』它其實是『抽象量』.它可以有多種解析如『位置』『速度』『加速度』『方向』『距離』.因為用於2D遊戲開發定義2D『矢量』

public class VECTOR2D {

浮點數儲存2D矢量

public float x,y;

角度轉弧度

public static float DEGREES_TO_RADIANS = ((1.0f/180.0f)* (float)Math.PI);

弧度轉角度

public static float RADIANS_TO_DEGREES = ((1.0f/(float)Math.PI)*180.0f);

購造函式初此為0

public VECTOR2D(){

x=y=0;

}

購造函式並設定x與y

public VECTOR2D(float x,float y){

this.x = x;

this.y = y;

}

返回新2D『矢量』拷貝

public VECTOR2D Copy(){

VECTOR2D v;

v=new VECTOR2D(x,y);

return v;

}

重設2D矢量

public VECTOR2D set(VECTOR2D v){

this.x = v.x;

this.y = v.y;

return this;

}

2D矢量加法

public VECTOR2D Add(VECTOR2D v){

this.x = this.x + v.x;

this.y = this.y + v.y;

return this;

}

2D矢量減法

public VECTOR2D Sub(VECTOR2D v){

this.x = this.x – v.x;

this.y = this.y – v.y;

return this;

}

2D矢量乘法等於對矢量進行縮放.

public VECTOR2D Mul(float scalar){

this.x = this.x * scalar;

this.y = this.y * scalar;

return this;

}

計算2D矢量長度

public float Len(){

float len;

len = (float) Math.sqrt(xx+yy);

return len;

}

2D矢量單位化,長度為1

public VECTOR2D Normer(){

float len;

len = Len();

if(len != 0) {

x = x / len;

y = y / len;

}

return this;

}

計算2D矢量角度

public float Angle(){

float angle = 0;

angle = (float)Math.atan2(y,x)*RADIANS_TO_DEGREES;

if(angle<0)

angle += 360;

return angle;

}

計算兩2D矢量角度在(0~360)度之間

public float Angle(VECTOR2D v){

float angle = 0;

float distanceX,distanceY;

distanceX = this.x – v.x;

distanceY = this.y – v.y;

angle = (float)Math.atan2(distanceY,distanceX)*RADIANS_TO_DEGREES;

if(angle<0)

angle += 360;

return angle;

}

2D矢量繞原點旋轉, angle為旋轉角度

public VECTOR2D rotate(float angle){

float rad = angle * DEGREES_TO_RADIANS; // 角度轉弧度

float cos = (float) Math.cos(rad);

float sin = (float) Math.sin(rad);

float newX = this.x * cos – this.y * sin;

float newY = this.x * sin + this.y * cos;

this.x = newX;

this.y = newY;

return this;

}

計算兩個2D矢量之間距離

public float Dist(VECTOR2D v){

float distX = this.x – v.x;

float distY = this.y – v.y;

float dist = (float)Math.sqrt(distX*distX + distY * distY);

return dist;

}

計算兩2D矢量之間距離平方

public float DistSquared(VECTOR2D v){

float distX = this.x – v.x;

float distY = this.y – v.y;

float dist = distX*distX + distY * distY ;

return dist;

}

}

Android遊戲之2D相機

Android遊戲之2D相機

定義2D相機即設定『投影矩陣』與『視口』

『視口』用於控制輸出圖像尺寸與渲染幀緩存位置.OpenGL ES使用『視口』將投影到『近裁剪面』點座標變換為『幀緩存』像素座標

GL10.glViewport(int x,int y,int width,int height);

x和y座標為幀緩存區視口左上角.width和height為視口大小.單位為像素.幀緩存座標原點為屏幕左下角.通常將x和y設為0.width和height設為屏幕分辨率.即設為全屏.

gl.glViewport(0, 0, view.getWidth(), view.getHeight());

『投影矩陣』在2D相機中只使用『平行投影』.首先將當前矩陣設為『投影矩陣』

gl.glMatrixMode(GL10.GL_PROJECTION);

載入單位矩陣

gl.glLoadIdentity();

設置正交投影矩陣

GL10. glOrthof(int left,int right,int bottom,int top,int near,int far);

OpenGL ES座標系統正X軸指向右,正Y軸指向上.正Z軸指向我.left與right為X軸左右兩條邊.bottom與 top為Y軸上下兩條邊.near為近端裁剪面.far為遠端裁剪面.若設2D橫向相機左下角(0,0)右上角(480,320)視錐深度為2

gl.glOrthof(0,480,0,320,1, -1);

重設為模型視圖矩陣

gl.glMatrixMode(GL10.GL_MODELVIEW);

gl.glLoadIdentity();

2D相機將『觸屏』坐標轉『世界』坐標.首先設定視錐體寬為15高為10.

float frustum_width = 15;

float frustum_height = 10;

設縮放係數為1.用於放大屏幕大於1,縮小屏幕小於1

float zoom = 1;

首先將『觸屏』位置歸範圍(0~1).然後乘以視錐體寬和高

touch.x = (touch.x / view.getWidth()) * frustum_width * zoom;

因為觸屏座標原點位於屏幕左上角.需倒轉Y軸

touch.y = (1-touch.y /view.getHeight()) * frustum_height * zoom;

與相機位置相機

touch.add(position);

最後減於視錐體中心位置.得到遊戲『世界』坐標

touch.x = touch.x – frustum_width*zoom/2f;

touch.y = touch.y – frustum_height*zoom/2f;

 

Android遊戲之OpenGL ES

Android遊戲之OpenGL ES

OpenGL ES專為移動與嵌入設備設計之圖形編程接口. 它並非由ARB委員會定義.而是由Khronos組織定義.該組織包括ATI、NVIDIA、Intel等組成.雖然『OpenGL』與『OpenGL ES』來自兩個不同組織. 『OpenGL ES』係『OpenGL』刪減板.但你依然可寫出在兩種標準下都可運行之程式.這對於移植遊戲很重要.OpenGL ES同樣以C文檔發佈API.而代碼實現由硬件廠商完成.

如果AndroidManifest.xml中無配置glEsVersion,則表示支持OpenGL ES 1.0但所有Android系統都支持.若支持OpenGL ES 2.0需在AndroidManifest.xml中添加:

<uses-feature  android:required=”false”  android:glEsVersion=”0x00020000″ />

OpenGL ES版本號為32位整數.高16位表示OpenGL ES大版本,低16位表示OpenGL ES小版本.

required必須 簡介
true 必需支持否則不能運行
false 可選支持可能影響部分運行

 

OpenGL ES版本 glEsVersion
GLES 1.0 0x00010000
GLES 1.1 0x00010001
GLES 2.0 0x00020000
GLES 3.0 0x00030000
GLES 3.1 0x00030001
GLES 3.2 0x00030002

 

Android遊戲之紋理映射

Android遊戲之紋理映射

將『Bitmap』加載給OpenGL ES然後加載到圖形卡記憶體重,並最終交給GPU渲染.因為OpenGL最終以三角形為單位進行渲染.而將『Bitmap』映射到三角形上.需要為三角形每個頂點設定紋理座標(texture coordinates).3D座標(x,y,z)和2D座標(x,y)對應紋理座標(u,v)位圖頂點.而(u,v)座標相當於(橫,縱)座標.紋理寬與高必需是2倍數.

紋理映射 (u,v)
左上角 (0,0)
右下角 (1,1)即使寬與高不相等
右上角 (1.0)
左下角 (0,1)

生成紋理隊列,用於保存紋理ID

int[] ids = new int[1];

生成紋理並獲取id.紋理依然為空

gl.glGenTextures(1, ids,0);

紋理id

int id = ids[0];

讀取位圖

Bitmap bitmap = BITMAP.Read(file_name);

獲取位圖寬度

int   width = bitmap.getWidth();

獲取位圖高度

int   height = bitmap.getHeight();

綁定2D紋理

gl.glBindTexture(GL10.GL_TEXTURE_2D, id);

上傳2D紋理

GLUtils.texImage2D(GL10.GL_TEXTURE_2D,0,bitmap,0);

設置紋理屬性指定縮小倍數過濾器

gl.glTexParameterf(GL10.GL_TEXTURE_2D,GL10.GL_TEXTURE_MIN_FILTER,GL10.GL_NEAREST);

設置紋理屬性指定放大倍數過濾器

gl.glTexParameterf(GL10.GL_TEXTURE_2D,GL10.GL_TEXTURE_MAG_FILTER,GL10.GL_NEAREST);

 

過濾 簡介
GL10.GL_NEAREST 像素採樣點最接近中心點『清晰』
GL10.GL_LINEAR 像素採樣點線性插值平均加權『模糊』

取消綁定紋理ID

gl.glBindTexture(GL10.GL_TEXTURE_2D, 0);

回收位圖.以免浪費記憶體

bitmap.recycle();

每當Activity被暫停(APP切換)GLSurfaceView都會被銷毀.每當Activity恢復時調用GLSurfaceView. onResume()讓GLSurfaceView重構渲染界面.但OpenGL ES中上傳紋理都會丟失.你需要在onSurfaceCreated()中需重新載入並上傳紋理.

重新載入代碼見上文

Texture.load(filen_ame);

重新綁定紋理後設置紋理屬性

gl.glBindTexture(GL10.GL_TEXTURE_2D, id);

gl.glTexParameterf(GL10.GL_TEXTURE_2D,GL10.GL_TEXTURE_MIN_FILTER,GL10.GL_NEAREST);

gl.glTexParameterf(GL10.GL_TEXTURE_2D,GL10.GL_TEXTURE_MAG_FILTER,GL10.GL_NEAREST);

取消綁定紋理

gl.glBindTexture(GL10.GL_TEXTURE_2D, 0);

 

當遊戲退出.便要刪除紋理釋放記憶體.首先取消紋理邦定

gl.glBindTexture(GL10.GL_TEXTURE_2D, id);

刪除紋理

int[] ids = { id };

gl.glDeleteTextures(1,ids,0);

渲染三角形時要告知OpenGL要啟用紋理渲染

gl.glEnable(GL10.GL_TEXTURE_2D);

完成渲染後禁用紋理渲染

gl.glDisable(GL10.GL_TEXTURE_2D);

2D遊戲通常只佔用圖像一小片區域.需要將像素座標(x,y)轉換為紋理座標(u,v)

計算紋理座標左上角

u1 = x/texture.width;

v1 = y/texture.height;

計算紋理座標右下角

u2 = u1 + width/texture.width;

v2 = v1 + height/texture.height;

 

 

 

Android遊戲之Bitmap讀取

Android遊戲之Bitmap讀取

遊戲由『背景』與『角色』『植物』『房舍』等圖檔組成.在C時代要逐個寫圖檔分析器.而在java可以通過BitmapFactory讀取Bitmap『位圖』.幾乎支持所有常見圖檔『jpg』『png』『bmp』『png』.把所有『位圖』保存到『ASSETS』目錄下

資源管理器用於訪問『ASSETS』目錄

AssetManager asset_manager = context.getAssets();

指定『位圖名』並返回輸入流

InputStream input_stream = asset_manager.open(file_name);

讀取Bitmap默認轉換為RGB_565色

Bitmap bitamp = BitmapFactory.decodeStream(input_stream);

關閉輸入流

Input_Stream.close();

獲取位圖寬度

int width = bitmap.getWidth();

讀取位圖寬度

int height = bitmap.getHeight();

獲取位圖顏色格式.

Bitmap.Config config = bitamp.getConfig();

Bitmap.Config 位圖顏色格式
ALPHA_8 256色
ARGB_8888 32bit含ALPHA分量
RGB_565 16bit(默認)
ARGB_4444 16bit含透明度分量

以特定顏色格式進行讀取.但渲染時最終要與OpenGL ES顏色格式一致

設定顏色格式為ARGB_8888

BitmapFactory.Options options = new BitmapFactory.Options();

options.inPreferredConfig = Bitmap.Config.ARGB_8888;

指定『位圖名』並返回輸入流

InputStream Input_Stream = asset_manager.open(file_name);

讀取Bitmap並轉換為ARGB_8888色

Bitmap bitamp = BitmapFactory.decodeStream(Input_Stream, null, options);

關閉輸入流

Input_Stream.close();

Android Studio之Error running ‘app’ No target device found

Android Studio之Error running ‘app’ No target device found

剛啟動Android Studio運行app進行調試『Run->Debug』時彈出:

『Error running ‘app’ No target device found』運行app『應用』錯誤穩唔到目標設備.即穩唔到手機.之前已安裝『ADB 驅動』.肯定是ADB服務未啟動所以先未穩到部手機.

啟用ADB服務可按

『Run->Attach debuger to Android process』

或在CMD輸入

adb start-server

 

Android遊戲之全屏

Android遊戲之全屏

自『街機遊戲』到『電腦遊戲』所有遊戲都以全屏形態出現.所以Android遊戲也應全屏.在super.onCreate()調用之前設定全屏

去除APP標題欄

this.requestWindowFeature(Window.FEATURE_NO_TITLE);

去除系通通知欄

Window window = this.getWindow(); window.setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN);

創建Activity.需要

super.onCreate(savedInstanceState);

把圖形界面『佈局』填充給Activity

setContentView(R.layout.main);

 

Android遊戲之SharedPreferences『共享參數』

Android遊戲之SharedPreferences『共享參數』

遊戲運行中經常要將數據保在磁盤中.等有需要時讀取.Android提供輕量級存儲工具SharedPreferences它適用於小量數據保存.

獲得默認共享首選項

SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);

獲得編輯器

Editor editor = sp.edit();

寫入文本.第一參數key文本.第二參數『value』文本

editor.putString(“text”,”data”);

寫入整數數值. 第一參數是key值.第二參數是整數

editor.putInt(“int”,1);

寫入浮點數. 第一參數key值.第二參數是浮點數

editor.putFloat(“float”,0.1);

提交保存數據

editor.commit();

讀取文本.若無該值則返回NULL

String value = sp.getString(“text”,null);

讀取整數.若無該值返回0

int value = sp.getInt(“int”,0);

讀取浮點數.若無該值返回0

float value = sp.getFloat(“float”,0);

Android遊戲之SDK版本

Android遊戲之SDK版本

在AndroidManifest.xml中修改< uses-sdk>以設置APP最低支持Android系統.以及編譯APP之SDK版本.設定Android版本需指定整數值也稱為SDK版本號.編譯版本『targetSdkVersion』應儘量使用最新SDK版本.而最低版本『minSdkVersion』應最量低,讓遊戲在更多Android設備上安裝.但也要避免使用低版SDK從而『不支持某些API』.例如下:

<uses-sdk android:minSdkVersion=”9″ android:targetSdkVersion=”28″ />

獲取當前android系統版本號

int   SDK = Integer.parseInt(android.os.Build.VERSION.SDK);

uses-sdk屬性 簡介
minSdkVersion APP最低支持Android系統
targetSdkVersion 編譯APP之SDK版本

 

Android版本 API Level『SDK版本號』
Android API 28
Android 8.1(Oreo) 27
Android 8.0(Oreo) 26
Android 7.1.1(Nougat) 25
Android 7.0(Nougat) 24
Android 6.0(Marshmallow) 23
Android 5.1(Lollipop) 22
Android 5.0(Lollipop) 21
Android 4.4W(KitKat Wear) 20
Android 4.4(KitKat) 19
Android 4.3(Jelly Bean) 18
Android 4.2(Jelly Bean) 17
Android 4.1(Jelly Bean) 16
Android 4.0.3(IceCreamSandwich) 15
Android 4.0(IceCreamSandwich) 14
Android 3.2(Honeycomb) 13
Android 3.1(Honeycomb) 12
Android 3.0(Honeycomb) 11
Android 2.3.3(Gingerbread) 10
Android 2.3(Gingerbread) 9
Android 2.2(Froyo) 8
Android 2.1(Eclair) 7
Android 2.0.1(Eclair) 6
Android 2.0(Eclair) 5
Android 1.6(Donut) 4
Android 1.5(Cupcake) 3
Android 1.1 2
Android 1.0 1

 

Android遊戲之縱向與橫向

Android遊戲之縱向與橫向

Android特點是每當改變手機旋轉方向時APP方向也隨之改變.『橫向』或『縱向』通過加速計傳感器確定.遊戲方向在設計時便確立.所以根本無需改變遊戲方向.只要指定Activity方向便可鎖定不變.在AndroidManifest.xml中修改<activity>屏幕方向屬性『screenOrientation』

強制屏幕縱向

<activity android:name=”.MainActivity”

android:screenOrientation=”portrait”>

強制屏幕橫向

<activity android:name=”.MainActivity”

android:screenOrientation=”landscape”>

在運行時更改屏幕為橫向

setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);

在運行時更改屏幕為縱向

setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);

screenOrientation屏幕方向 簡介
unspecified 默認值,由系統決定
landscape 強制屏幕橫屏顯示
portrait 強制屏幕豎屏顯示
behind 與前一個Activity方向相同
sensor 根據加速計傳感器轉動手機90度、180度、270度. Activity都更著變化
sensorLandscape 屏幕只可橫屏旋轉
sensorPortrait 屏幕只可豎屏旋轉
nosensor 忽略加速計傳感器.旋轉手機不會改變方向
user 用戶當前設置方向

 

Android遊戲之版本控制

Android遊戲之版本控制

Android遊戲發佈到Google Play需要追蹤遊戲『版本』.以便Google Play自動更新遊戲.要設定版本號需編輯 AndroidManifest.xml其根元素<manifest>添加versionCode和versionName屬性

versionCode:版本代碼(整數)大於等於1

versionName:版本名(字符).在Google Play上顯示.建議『versionName= versionCode/100.0f』如『versionCode=”2″』則『versionName=”0.02″』.因為任何遊戲都需要幾十次更新才可達置完善.如下:

<manifest xmlns:android=”http://schemas.android.com/apk/res/android”

package=”net.bookcard.aa”

android:versionCode=”1″

android:versionName=”0.01″>

獲取包管理器

PackageManager  package_manager = context.getPackageManager();

獲取Android應用包名這裡返回『net.bookcard.aa』

package_name = context.getPackageName();

獲取版本信息

PackageInfo package_info = Package_Manager.getPackageInfo(package_name,0);

獲取版本名

String version = Package_Info.versionName;

獲取版本代碼

int code = Package_Info.versionCode;

 

Android遊戲之喚醒鎖

Android遊戲之喚醒鎖

Android最耗電首當觸摸屏.為節約電能很多人都將亮度降低.但又耗神.折中之法是系統自動變暗進入睡眠狀態.觸屏後自動變明亮.如果想屏膜保持喚醒狀態可是WakeLock.但觸屏遊戲是不需WakeLock『喚醒鎖』.它只適用於通過『加速計』控制之遊戲.

首先在AndroidManifest.xml添加權限

<uses-permission android:name=”android.permission.WAKE_LOCK” />

獲取電源管理器

PowerManager power_manager = (PowerManager)context.getSystemService(Context.POWER_SERVICE);

生成喚醒鎖. levelAndFlagsw為控制標記.tag為鎖名

PowerManager.newWakeLock(int levelAndFlags, String tag)

levelAndFlags: 屏幕燈 鍵盤燈
PARTIAL_WAKE_LOCK 關閉 關閉
SCREEN_DIM_WAKE_LOCK 低亮度 關閉
SCREEN_BRIGHT_WAKE_LOCK 高亮度 關閉
FULL_WAKE_LOCK 高亮度 開啟
ON_AFTER_RELEASE 延時關燈 關閉
ACQUIRE_CAUSES_WAKEUP 強制開啟 強制開啟

一般使用PARTIAL_WAKE_LOCK生成喚醒鎖

WakeLock wake_lock = power_manager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,”LOCK”);

啟用喚醒鎖.在Activity.onResume()中調用

wake_lock.acquire();

釋放喚醒鎖.在Activity.onPause()中調用

wake_lock.release();

 

Android遊戲之背景音樂

Android遊戲之背景音樂

遊戲聲音分為『音樂』與『音效』.遊戲背景『音樂』播放時間通常達幾分鐘以上.音檔通常較大不能一次性載入記憶體.只能以『數據流』方式逐次讀入數據塊.並解碼為PCM數據交給音頻芯片上.Android系統提供MediaPlayer幫你解卻所有問題. 將所有『音樂』文檔存放在『\app\src\main\assets』目錄下.讓AssetManager能夠訪問.

生成MediaPlayer音頻播放器

MediaPlayer media_player = new MediaPlayer();

獲取ASSET文檔描述符

AssetFileDescriptor afd = asset_manager.openFd(file_name);

文檔描述符

FileDescriptor file_descriptor = afd.getFileDescriptor();

獲取音檔數據開此位置偏移量

long offset = afd.getStartOffset();

獲取音檔數據長度

long length = afd.getLength();

設定音檔數據

media_player.setDataSource(descriptor,offset,length);

每次啟動播放時.都需載入準備播放

media_player.prepare();

啟動播放

media_player.start();

播放中若暫停播放

media_player.pause();

播放中若停止播放

media_player.stop();

設定循環播放.

media_player.setLooping(true);

設定左右聲道音量.數值在0~1之間

media_player.setVolume(volume,volume);

判定時否播放中. isPlaying()若返回true則播放中否則返回false

media_player.isPlaying();

或用註冊OnCompletionListener簡聽器

media_player.setOnCompletionListener(listener);

若退出遊戲需釋放記憶體

media_player.release();

Android遊戲之音效模塊

Android遊戲之音效模塊

遊戲聲音分為『音樂』與『音效』.音效長度不應超過5秒.讓其可以載入『記憶體』中.並將所有音效文檔存放在『\app\src\main\assets』目錄下.讓AssetManager能夠訪問.並將所有『音效』文檔存為『OGG』格式.並且採用低採樣頻率.

Android提供SoundPool『音效池』實現音效載入與播放.

SoundPool(int maxStreams, int streamType, int srcQuality)

maxStreams:用時能播放音效量

streamType:使用音樂流輸出音頻.這裡使用AudioManager.STREAM_MUSIC

srcQuality:廢棄,總為0

構建音效播放

SoundPool sound_pool = new SoundPool(32, AudioManager.STREAM_MUSIC,0);

用於訪問Asset目錄

AssetManager asset_manager = context.getAssets();

獲取資源文檔描述符

AssetFileDescriptor afd = asset_manager.openFd(file_name);

把音效文檔載入『記憶體』中,讓AssetFileDescriptor傳給load()並返回整數ID句柄

int id = sound_pool.load(afd,1);

播放音效

public final int play (int soundID, float leftVolume, float rightVolume, int priority, int loop, float rate)

soundID:音效ID句柄

leftVolume\rightVolume:左右聲道音量在0.0f – 1.0f之間

priority:優先級.值越大優先級越高,0優先級最低

loop:循環次數.0代表不循環

rate:播放速率取值0.5f – 2.0f之間.其中0.5f表示播放速度慢一半.1表示正常速率播放.

單次播放音效

sound_pool.play(id, 1.0f, 1.0f, 0, 0, 1);

當不需要音效時,需要釋放音效記憶體

sound_pool.unload(ID);

當退出遊戲時需釋放SoundPool『音效池』

sound_pool.release();

Android Studio之自定遊戲圖標

Android Studio之自定遊戲圖標

Android遊戲都有其icon圖標.而且該圖標也會Google Play上展示.要自定圖標需在遊戲項目『\app\src\main\res\mipmap-xxx』查找icon圖標.然後將其替換.若Eclipse則在drawable目錄下. 並且隨著手機屏幕分辨率不斷進化.遊戲需要提供不同密度圖標『自適應圖標』.圖標分為兩類『圓』與『方』.並且需要在AndroidManifest.xml添加icon圖標屬性.

<application  android:icon=”@mipmap/ic_launcher”

android:roundIcon=”@mipmap/ic_launcher_round”>

Android Studio帶有icon圖標生成器,全自動生成所有不同分辨率圖標.在Eclipse你需要用PS生成.

  1. 項目右擊『New->Image Asset』
  2. Icon Type:選Launcher Icons(Adaptive and Legacy)
  3. Name:填ic_launcher
  4. Asset Type:勾選Image
  5. Path:輸入自定圖標路徑
  6. Trim勾選Yes
  7. Resize拖到100%
  8. Legacy Icon勾選Yes
  9. Gound Icon Generate勾選Yes
  10. Google Play Store Icon勾選Yes
類型 文檔名
方形 ic_launcher.png
圓形 ic_launcher_round.png
前景 ic_launcher_foreground.png
背景 ic_launcher_background.png

 

目錄 簡介 分辨率
mipmap-mdpi 中密度圖標(必須有) 48*48
mipmap-hdpi 高密度圖標 72*72
mipmap-xhdpi 超高密度圖標 96*96
mipmap-xxhdpi 超超高密度圖標 144*144
mipmap-xxxhdpi 超超超高密度圖標 192*192

 

Android遊戲之文檔讀寫

Android遊戲之文檔讀寫

在Android遊戲開發時需要讀入大量Asset(資源).如『3D模型』『紋理』『音頻』『地型』等Asset(資源)文檔.Android建議把資源存放於『res』目錄,但它不適合存放原生資源. 在遊戲開發時使用『assets』目錄,所有遊戲資源文檔存放該目錄下.而且還可以指定目錄結構. 要訪問『assets』目錄需AssetManager資源管理器:

『assets』目錄位於『\app\src\main\assets』這點與Eclipse有所不同.

AssetManager asset_manager = context.getAssets();

打開Asset文檔並返回輸入流InputStream

InputStream input_stream = asset_manager.open(file_name);

讀取『外部緩存』SD卡

Asset只適合用於讀取遊戲資源.若在遊戲運行時讀寫文檔數據.若訪問SD卡需要加入度寫權限:

<uses-permission android:name=”android.permission.WRITE_EXTERNAL_STORAGE”/>

<uses-permission android:name=”android.permission.READ_EXTERNAL_STORAGE”/>

然後需要確定手機是否裝有SD卡

獲取『外部緩存』SD卡裝態.其實現在手機載固態硬盤劃出部分空間作為『外部緩存』

String state = Environment.getExternalStorageState();

Environment.MEDIA_MOUNTED:SD卡插入並可正常讀寫

Environment.MEDIA_MOUNTED_READ_ONLY:SD卡已插入,但只能讀取

獲取『外部緩存』路徑

File file_path = Environment.getExternalStorageDirectory();

並不建議在『外部緩存』SD卡讀寫.一SD卡可能被彈出.二可能需要用戶授權.如果數據較小建議寫入『內部存儲』

APP內部存儲緩存目錄『/data/data/< package name >/files/』

File file_path = context.getFilesDir() ;

生成目錄

file_path.mkdir();

連接路徑

File file  = new File(file_path,file_name);

打開文檔並返回輸入流

InputStream input_stream = new FileInputStream(file);

打開文檔並返回輸出流

OutputStream output_stream = new FileOutputStream(file);

獲取指定寫入/讀取路徑 存儲位置
Environment.getExternalStorageDirectory() /mnt/sdcard/
context.getExternalFilesDir() /mnt/sdcard/Android/data/< package name >/files/
context.getExternalCacheDir() /mnt/sdcard/Android/data/< package name >/cach/
context.getFilesDir() /data/data/< package name >/files/
context.getCacheDir() /data/data/< package name >/cach/

 

獲取指定寫入/讀取路徑 簡介
Environment.getExternalStorageDirectory() 外部存儲
context.getExternalFilesDir() 外部存儲
context.getExternalCacheDir() 外部臨時存儲
context.getFilesDir() 內部存儲
context.getCacheDir() 內部臨時緩存

 

Android遊戲之按鍵

Android遊戲之按鍵

Android其實是支持標準鍵盤.大多數Android手機只支持軟鍵盤. 遊戲要捕足按鍵事件你需要實現OnKeyListener接口.它通過與接收鍵盤事件View相連並接收按鍵事件.

public boolean onKey(View view,int keyCode,KeyEvent event);

按鍵編碼keyCode為整數0~127一共128個按鍵.常量值形式為KeyEvent.KEYCODE_XXX

獲取按鍵字符:KeyEvent.getUnicodeChar();

獲取按鍵事件類型: KeyEvent.getAction();

獲取按鍵事件類型: KeyEvent.getAction(); 簡介
KeyEvent.ACTION_MULTIPLE 連續多個重複鍵事件
KeyEvent.ACTION_DOWN 按下按鍵時觸發
KeyEvent.ACTION_UP 鬆開按鍵時觸發

當鍵盤按下時其值被保存在鍵盤列狀態

public static int   MAX_KEY = 128;// 128個按鍵

public static int[] Key_Action  = new int[MAX_KEY];// 按鍵事件,按下/送開

public static int[] Key_Code   = new int[MAX_KEY];// 按鍵代碼

public static int[] Key_Char   = new int[MAX_KEY];// 按鍵字符

public static int  Key_Count  = 0; // 未處理按鍵量

private static boolean[] Key_State = new boolean[128];// 按鍵的當前狀態true按下.false鬆開

private static KeyboardListener Keyboard_Listener = new KeyboardListener();//按鍵監聽器

實現鍵盤監聽接口從View中接收鍵盤事件並處理

static class KeyboardListener implements View.OnKeyListener{

@Override

public boolean onKey(View view, int keyCode, KeyEvent event){

int index;

int Action;

if(Key_Count >= MAX_KEY)

return false;

index = Key_Count;

++Key_Count;

Key_Code[index] = keyCode;// 鍵代碼

Key_Char[index] = event.getUnicodeChar();// 鍵字符

Action = event.getAction();//  獲取按鍵事件類型

if(Action == KeyEvent.ACTION_MULTIPLE)// 多重

return false;

if(Action == KeyEvent.ACTION_DOWN)

{// 按下

if(keyCode >0 && keyCode < 127)

Key_State[keyCode] = true;// 按下

Key_Action[index] = KeyEvent.ACTION_DOWN;

}

else

if(Action == KeyEvent.ACTION_UP)

{// 鬆開

if(keyCode >0 && keyCode < 127)

Key_State[keyCode] = false;

Key_Action[index] = KeyEvent.ACTION_UP;

}

return false;

}

初此按鍵監聽器

public static boolean Init(View view)

{

for(int i=0;i<Key_State.length;++i)

Key_State[i] = false;

view.setOnKeyListener(Keyboard_Listener);// view對按鍵進行監聽

view.requestFocus();//請求焦點

return true;

}

}

電話鍵常量 數值
KEYCODE_CALL 撥號鍵
KEYCODE_ENDCALL 掛機鍵
KEYCODE_HOME Home鍵返回面
KEYCODE_MENU 菜單鍵
KEYCODE_BACK 返回鍵
KEYCODE_SEARCH 搜索鍵
KEYCODE_CAMERA 拍照鍵
KEYCODE_FOCUS 拍照對焦鍵
KEYCODE_POWER 電源鍵
KEYCODE_NOTIFICATION 通知鍵
KEYCODE_MUTE 話筒靜音鍵
KEYCODE_VOLUME_MUTE 揚聲器靜音鍵
KEYCODE_VOLUME_UP 音量增加鍵
KEYCODE_VOLUME_DOWN 音量減小鍵

 

控制鍵常量 數值
KEYCODE_ENTER ENTER回車鍵
KEYCODE_ESCAPE ESC鍵
KEYCODE_DPAD_CENTER 方向鍵/確定鍵
KEYCODE_DPAD_UP 方向鍵/向上鍵
KEYCODE_DPAD_DOWN 方向鍵/向下鍵
KEYCODE_DPAD_LEFT 方向鍵/向左鍵
KEYCODE_DPAD_RIGHT 方向鍵/向右鍵
KEYCODE_MOVE_HOME 光標移動到開始鍵
KEYCODE_MOVE_END 光標移動到末尾鍵
KEYCODE_PAGE_UP 向上翻頁鍵
KEYCODE_PAGE_DOWN 向下翻頁鍵
KEYCODE_DEL 退格鍵
KEYCODE_FORWARD_DEL 刪除鍵
KEYCODE_INSERT 插入鍵
KEYCODE_TAB Tab鍵/焦點切換鍵
KEYCODE_NUM_LOCK 小鍵盤鎖
KEYCODE_CAPS_LOCK 大寫鎖定鍵
KEYCODE_BREAK Break/Pause鍵
KEYCODE_SCROLL_LOCK 滾動鎖定鍵
KEYCODE_ZOOM_IN 放大鍵
KEYCODE_ZOOM_OUT 縮小鍵

 

組合鍵常量 簡介
KEYCODE_ALT_LEFT Alt+Left
KEYCODE_ALT_RIGHT Alt+Right
KEYCODE_CTRL_LEFT Control+Left
KEYCODE_CTRL_RIGHT Control+Right
KEYCODE_SHIFT_LEFT Shift+Left
KEYCODE_SHIFT_RIGHT Shift+Right

 

數字與字母鍵常量 簡介
KEYCODE_0 數字鍵0
KEYCODE_1 數字鍵1
KEYCODE_2 數字鍵2
KEYCODE_3 數字鍵3
KEYCODE_4 數字鍵4
KEYCODE_5 數字鍵5
KEYCODE_6 數字鍵6
KEYCODE_7 數字鍵7
KEYCODE_8 數字鍵8
KEYCODE_9 數字鍵9
KEYCODE_A 字母鍵A
KEYCODE_B 字母鍵B
KEYCODE_C 字母鍵C
KEYCODE_D 字母鍵D
KEYCODE_E 字母鍵E
KEYCODE_F 字母鍵F
KEYCODE_G 字母鍵G
KEYCODE_H 字母鍵H
KEYCODE_I 字母鍵I
KEYCODE_J 字母鍵J
KEYCODE_K 字母鍵K
KEYCODE_L 字母鍵L
KEYCODE_M 字母鍵M
KEYCODE_N 字母鍵N
KEYCODE_O 字母鍵O
KEYCODE_P 字母鍵P
KEYCODE_Q 字母鍵Q
KEYCODE_R 字母鍵R
KEYCODE_S 字母鍵S
KEYCODE_T 字母鍵T
KEYCODE_U 字母鍵U
KEYCODE_V 字母鍵V
KEYCODE_W 字母鍵W
KEYCODE_X 字母鍵X
KEYCODE_Y 字母鍵Y
KEYCODE_Z 字母鍵Z

 

符號鍵常量 簡介
KEYCODE_PLUS 加號+
KEYCODE_MINUS 減號-
KEYCODE_STAR 乘號*
KEYCODE_SLASH 除號/
KEYCODE_EQUALS 等號=
KEYCODE_AT 符號鍵@
KEYCODE_POUND 井號鍵#
KEYCODE_APOSTROPHE 單引號’
KEYCODE_BACKSLASH 斜杆\
KEYCODE_COMMA 逗號,
KEYCODE_PERIOD 句號.
KEYCODE_LEFT_BRACKET 左括號[
KEYCODE_RIGHT_BRACKET 右括號]
KEYCODE_SEMICOLON 分號;
KEYCODE_GRAVE `
KEYCODE_SPACE 空格鍵

 

小鍵盤常量 簡介
KEYCODE_NUMPAD_0 小鍵盤數字鍵0
KEYCODE_NUMPAD_1 小鍵盤數字鍵1
KEYCODE_NUMPAD_2 小鍵盤數字鍵2
KEYCODE_NUMPAD_3 小鍵盤數字鍵3
KEYCODE_NUMPAD_4 小鍵盤數字鍵4
KEYCODE_NUMPAD_5 小鍵盤數字鍵5
KEYCODE_NUMPAD_6 小鍵盤數字鍵6
KEYCODE_NUMPAD_7 小鍵盤數字鍵7
KEYCODE_NUMPAD_8 小鍵盤數字鍵8
KEYCODE_NUMPAD_9 小鍵盤數字鍵9
KEYCODE_NUMPAD_ADD 小鍵盤加號+
KEYCODE_NUMPAD_SUBTRACT 小鍵盤減號-
KEYCODE_NUMPAD_MULTIPLY 小鍵盤乘號*
KEYCODE_NUMPAD_DIVIDE 小鍵盤除號’/’
KEYCODE_NUMPAD_EQUALS 小鍵盤等號’=’
KEYCODE_NUMPAD_COMMA 小鍵盤逗號’,’
KEYCODE_NUMPAD_DOT 小鍵盤點號’.’
KEYCODE_NUMPAD_LEFT_PAREN 小鍵盤左括弧'(‘
KEYCODE_NUMPAD_RIGHT_PAREN 小鍵盤左括弧’)’
KEYCODE_NUMPAD_ENTER 小鍵盤回車鍵

 

功能鍵常量 簡介
KEYCODE_F1 按鍵F1
KEYCODE_F2 按鍵F2
KEYCODE_F3 按鍵F3
KEYCODE_F4 按鍵F4
KEYCODE_F5 按鍵F5
KEYCODE_F6 按鍵F6
KEYCODE_F7 按鍵F7
KEYCODE_F8 按鍵F8
KEYCODE_F9 按鍵F9
KEYCODE_F10 按鍵F10
KEYCODE_F11 按鍵F11
KEYCODE_F12 按鍵F12

 

多媒體鍵常量 簡介
KEYCODE_MEDIA_PLAY 播放鍵
KEYCODE_MEDIA_STOP 停止鍵
KEYCODE_MEDIA_PAUSE 暫停鍵
KEYCODE_MEDIA_PLAY_PAUSE 播放/暫停鍵
KEYCODE_MEDIA_FAST_FORWARD 快進鍵
KEYCODE_MEDIA_REWIND 快退鍵
KEYCODE_MEDIA_NEXT 下一首鍵
KEYCODE_MEDIA_PREVIOUS 上一首鍵
KEYCODE_MEDIA_CLOSE 關閉鍵
KEYCODE_MEDIA_EJECT 彈出鍵
KEYCODE_MEDIA_RECORD 錄音鍵

 

通用遊戲手柄按鈕按鍵常量 簡介
KEYCODE_BUTTON_1 #1
KEYCODE_BUTTON_2 #2
KEYCODE_BUTTON_3 #3
KEYCODE_BUTTON_4 #4
KEYCODE_BUTTON_5 #5
KEYCODE_BUTTON_6 #6
KEYCODE_BUTTON_7 #7
KEYCODE_BUTTON_8 #8
KEYCODE_BUTTON_9 #9
KEYCODE_BUTTON_10 #10
KEYCODE_BUTTON_11 #11
KEYCODE_BUTTON_12 #12
KEYCODE_BUTTON_13 #13
KEYCODE_BUTTON_14 #14
KEYCODE_BUTTON_15 #15
KEYCODE_BUTTON_16 #16
KEYCODE_BUTTON_A 手柄A
KEYCODE_BUTTON_B 手柄B
KEYCODE_BUTTON_C 手柄C
KEYCODE_BUTTON_X 手柄X
KEYCODE_BUTTON_Y 手柄 Y
KEYCODE_BUTTON_Z 手柄 Z
KEYCODE_BUTTON_L1 手柄 L1
KEYCODE_BUTTON_L2 手柄L2
KEYCODE_BUTTON_R1 手柄R1
KEYCODE_BUTTON_R2 手柄R2
KEYCODE_BUTTON_MODE 手柄Mode
KEYCODE_BUTTON_SELECT 手柄Select
KEYCODE_BUTTON_START 手柄Start
KEYCODE_BUTTON_THUMBL 左拇指鍵
KEYCODE_BUTTON_THUMBR 右拇指鍵

 

按鍵常量 簡介
KEYCODE_NUM Number modifier
KEYCODE_INFO Info
KEYCODE_APP_SWITCH App switch
KEYCODE_BOOKMARK Bookmark
KEYCODE_AVR_INPUT A/V Receiver input
KEYCODE_AVR_POWER A/V Receiver power
KEYCODE_CAPTIONS Toggle captions
KEYCODE_CHANNEL_DOWN Channel down
KEYCODE_CHANNEL_UP Channel up
KEYCODE_CLEAR Clear
KEYCODE_DVR DVR
KEYCODE_ENVELOPE Envelope special function
KEYCODE_EXPLORER Explorer special function
KEYCODE_FORWARD Forward
KEYCODE_FORWARD_DEL Forward Delete
KEYCODE_FUNCTION Function modifier
KEYCODE_GUIDE Guide
KEYCODE_HEADSETHOOK Headset Hook
KEYCODE_META_LEFT Left Meta modifier
KEYCODE_META_RIGHT Right Meta modifier
KEYCODE_PICTSYMBOLS Picture Symbols modifier
KEYCODE_PROG_BLUE Blue “programmable”
KEYCODE_PROG_GREEN Green “programmable”
KEYCODE_PROG_RED Red “programmable”
KEYCODE_PROG_YELLOW Yellow “programmable”
KEYCODE_SETTINGS Settings
KEYCODE_SOFT_LEFT Soft Left
KEYCODE_SOFT_RIGHT Soft Right
KEYCODE_STB_INPUT Set-top-box input
KEYCODE_STB_POWER Set-top-box power
KEYCODE_SWITCH_CHARSET Switch Charset modifier
KEYCODE_SYM Symbol modifier
KEYCODE_SYSRQ System Request / Print Screen
KEYCODE_TV TV鍵
KEYCODE_TV_INPUT TV input鍵
KEYCODE_TV_POWER TV power鍵
KEYCODE_WINDOW Window鍵
KEYCODE_UNKNOWN 未知按鍵

 

Android遊戲之觸摸屏

Android遊戲之觸摸屏

Android最初就配備有觸摸屏.單只支持單點觸碰.直到Android2.0(SDK 5)才支持多點觸碰.你需要註冊觸摸監聽器OnTouchListener接口,通過onTouch()函式接受觸碰事件並處理.若已處理觸碰事件返回true但後續ACTION_DOWN事件將無法接收.在遊戲中要持續監聽應返回false.而且要分別處理單點觸碰和多點觸碰兩種情況.

static class TounchListener implements View.OnTouchListener {

@Override

public boolean onTouch(View v, MotionEvent event)

{

if(SYSTEM.GetVersion() >= 5)

MultiTouch(v, event);// 多點觸碰

else

SingleTouch(v, event);// 單點觸碰

return false;

}

觸摸監聽器

private static TounchListener Tounch_Listener = new TounchListener();

然後定義三個觸碰事件. 鬆開、按下、拖動.

public static int ACTION_UP    =  1;//  鬆開事件

public static int ACTION_DOWN =   2;// 按下事件

public static int ACTION_DRAGGED = 3;// 拖動事件

定義觸碰點緩存列.

public static int MAX_POINT = 1024;

public static int[] Point_Action = new int[MAX_POINT]; // 事件緩存

public static int[] Point_X    = new int[MAX_POINT];// x座標緩存

public static int[] Point_Y    = new int[MAX_POINT];// y座標緩存

public static int   Point_Count = 0;// 觸碰點量

因為遊戲分辨率與屏幕分辨率並不一至.所以你縮放比變量.

private static float  Scale_X;//  寬度縮放比

private static float  Sacle_Y;//  高度縮放比

初此觸碰模塊.view為Activity.分別輸入『目標分辨率寬與高』和『設備分辨率寬與高』

public static boolean Init(View view,int target_width,int target_height,int real_width,int real_height)

{ // 設置觸摸監聽器

view.setOnTouchListener(Tounch_Listener);

// 計算縮放因子

Scale_X = (float)target_width/(float)real_width;

Sacle_Y = (float)target_height/(float)real_height;

return true;

}

獲取觸摸事件. MotionEvent.getAction()返回觸摸事件

觸摸常量 簡介
ACTION_DOWN 第一隻手指觸屏時觸發
ACTION_POINTER_DOWN 非第一隻手指屏時觸發
ACTION_UP 最後一隻手指離開屏幕時觸發
ACTION_POINTER_UP 非最後一隻手指離開屏幕時觸發
ACTION_CANCEL 手勢取消時觸發
ACTION_MOVE 一隻或多隻手指移動時觸發
ACTION_MASK 提取觸摸事件

MotionEvent.getAction() & MotionEvent.ACTION_MASK

ACTION_POINTER_ID_MASK 提取手指索引

MotionEvent.getAction()&MotionEvent.ACTION_POINTER_ID_MASK)>>MotionEvent.ACTION_POINT

處理單點觸碰事件.獲取觸摸座標MotionEvent.getX()返回x軸. MotionEvent.getY()返回y軸.屏幕左上角為座標原點.x軸指向右邊.y軸指向下邊

static void SingleTouch(View v, MotionEvent event)

{

int action;

int index;

action = event.getAction() & MotionEvent.ACTION_MASK;// 提取觸碰事件動作

index = Point_Count; //  索引

Point_Count = Point_Count + 1;// 觸碰量加一

Point_Action[index] = action; //  事件

if(action == MotionEvent.ACTION_DOWN ||

action == MotionEvent.ACTION_POINTER_DOWN)

Point_Action[index] = ACTION_DOWN;// 按下

else

if(action == MotionEvent.ACTION_UP ||

action == MotionEvent.ACTION_POINTER_UP ||

action == MotionEvent.ACTION_CANCEL)

Point_Action[index] = ACTION_UP;// 鬆開

else

if(action == MotionEvent.ACTION_MOVE)

Point_Action[index] = ACTION_DRAGGED;// 拖動

// 計算遊戲屏幕座標

Point_X[index] = (int)(event.getX()*Scale_X);

Point_Y[index] = (int)(event.getY()*Sacle_Y);

}

處理多點觸碰可以通過MotionEvent.getPointerCount()獲知同時有幾隻手指觸碰屏膜.而手指觸碰屏幕都會獲得新索引.索引可以通過getAction()提取:

MotionEvent.getAction()&MotionEvent.ACTION_POINTER_ID_MASK)>>MotionEvent.ACTION_POINTER_ID_SHIFT;

static void MultiTouch(View v, MotionEvent event)

{

int action;

int Point_index;// 點索引

action = event.getAction() & MotionEvent.ACTION_MASK;//  提取觸摸事件

Point_index = (event.getAction() & MotionEvent.ACTION_POINTER_ID_MASK)>>MotionEvent.ACTION_POINTER_ID_SHIFT;//手指索引

Point_Count = event.getPointerCount();//  手指觸碰量

for(int index = 0; index< Point_Count ; ++index)

{

if (action != MotionEvent.ACTION_MOVE && index != Point_index)

continue;

if(action == MotionEvent.ACTION_DOWN ||

action == MotionEvent.ACTION_POINTER_DOWN)

Point_Action[index] = ACTION_DOWN;// 按下

else

if(action == MotionEvent.ACTION_UP ||

action == MotionEvent.ACTION_POINTER_UP ||

action == MotionEvent.ACTION_CANCEL)

Point_Action[index] = ACTION_UP;// 鬆開

else

if(action == MotionEvent.ACTION_MOVE)

Point_Action[index] = ACTION_DRAGGED;// 拖動

//讀取指定手指座並計算遊戲屏幕座標

Point_X[index] = (int)(event.getX(index)*Scale_X);

Point_Y[index] = (int)(event.getY(index)*Sacle_Y);

++index;

}

}

Android遊戲之LogCat調試日誌系統

Android遊戲之LogCat調試日誌系統

APP調試最常用是『斷點調試』(break).但如果想睇大量數據變化則力有不逮.可以通Log()不斷把數據輸出到LogCat窗口以此觀察數據變化.通過『View->Tool Windows->Logcat』顯示Logcat窗口.更可以通過濾器隨時顯示5種特定信息.

函式 顏色 簡介
Log.d(String tag, String msg); 藍色 代表debug調試
Log.v(String tag, String msg); 黑色 代表verbose囉嗦之意.一般信息輸出
Log.i(String tag, String msg); 綠色 代表information提示性消息
Log.w(String tag, String msg); 藍色 代表warning警告信息
Log.e(String tag, String msg); 紅色 代表error錯誤消息

 

Android遊戲之Activity模板

Android遊戲之Activity模板

Android是Linux系統.於其上運行APP都是Linux進程.Android APP沒有main入口函式.所以Android系統啟動APP時以Main Activity作為APP入口點.要理解Android APP運行需理解Activity生命週期.睇上圖左邊從Create到Destroyed完成整個生命週期.

Activity.onCreate():在創建時Activity加載界面並分配資源,如讀取音頻和3D模型.只會在啟動時被調用一次.

Activity.onStart():在onCreate()之後被調用或onRestart()之後調用

Activity.onRestart():用於重置Activity在onStop()之後被調用.

Activity.onResume():用於恢復(總會被調用)Activity在onStart()之後被調用或onPause()之後被調用

Activity.onPause():暫停(總會被調用).當Activity進入後臺時被調用

Activity.onStop():停止.當APP進入後臺時被調用.在onPause()之後調用.

Activity.onDestroy():銷毀.當APP退出時調用.若調用onPause()或onStop()之後onDestroy()將不會被調用.

為讓遊戲結構變得簡單.只需重寫onCreate()、onResume()和onPause()三個函式.下面是用於遊戲開發MainActivity.java模板

public class MainActivity extends Activity {

@Override

protected void onCreate(Bundle savedInstanceState) {

// 初此遊戲資源

super.onCreate(savedInstanceState); //創建Activity時調用

setContentView(R.layout.main); // 把佈局填充給Activity

}

@Override

protected void onResume() {

// 恢復遊戲線程

super.onResume();

}

@Override

protected void onPause() {

// 暫停遊戲線程

super.onPause();

}

}

當你生成MainActivity.java文檔後需要在AndroidManifest.xml文檔中聲明為入口Activity

<activity android:name=”.MainActivity” android:label=”@string/app_name”>

<intent-filter>

<action android:name=”android.intent.action.MAIN” />

<category android:name=”android.intent.category.LAUNCHER” />

</intent-filter>

</activity>

Android Studio啟動Android應用

Android Studio啟動Android應用Debug
Android Studio啟動Android應用Variableh
Android Studio啟動Android應用
Android Studio啟動Android應用ADB
Android Studio啟動Android應用ADB

創建Android應用項目需要在手機上啟動.

  1. 對項目進行編譯工具欄Build/Mak Project
  2. 將手機與電腦連接(USB線)
  3. 設定/更多設定/開發者選項
  4. 啟動『開啟開發人員選項』
  5. 啟動『USB調試』連接USB後啟用偵錯模式
  6. 啟動『USB安裝』允許通過USB安裝應用
  7. 啟動『USB調試』(安全設定)允許通過USB調試修改權限或虛擬觸碰
  8. 編輯配置文檔Run->Edit Configurations->app->General
  9. Module選app
  10. Deploy選Default APK
  11. Launch選Default Activity
  12. Target選USB Device
  13. 在手機上啟動工具欄Run->Run

 

未能正確在手機上調試APP多為ADB(Android Debug Bridge)未正確安裝

  1. 下載Android SDK Platform-Tools(包含EXE)
  2. 系統『Path』變數必須需正確設置. 『%ANDROID_HOME%\platform-tools;%ANDROID_HOME%\tools;』
  3. 下載並正確安裝Google USB Driver.這點很重要很多時就是Android ADB Interface驅動無正確安裝.
  4. 『系統內容->硬體->裝置管理員->ADB Interface』若有嘆號則代表驅動未正確安裝
  5. 下載驅去頁Get the Google USB Driver 最新驅動Download the Google USB driver下載後解壓縮到D:\Android\usb_driver
  6. 最後強制安裝驅動.『系統內容->硬體->裝置管理員->ADB Interface->更新驅動程式->瀏覽電腦上驅動程式軟體(手動尋找並安裝驅動程式軟體)->讓我從電腦上裝置取動程式清單中挑選(此清單會顯示已安裝並且與裝置相容驅動程式軟體,以及與裝置屬￿同類別所有驅動程式軟體)->從磁片安裝->打開(USB drect)->選擇(Android ADB Interface)』

 

若ADB依然未能正確運行可嘗試手動重啟.win+r輸入CMD啟動命令行窗口

1.停止ADB服務

adb kill-server

2.啟動ADB服務

adb start-server

3.查看目前連接Android 設備

adb devices

Android Studio新建Android項目

Android Studio新建Android項目
Android Studio新建Android項目SDK
Android Studio新建Android項目Activity
Android Studio新建Android項目Build

Android Studio新建Project『項目』與Eclipse類似.下面將創建空項目用於遊戲製作.

  1. 啟動Android Studio
  2. 點擊Start a new Android Studio project
  3. Application name應用名使用全小寫如aa
  4. Company domain公司域名如net
  5. Project location工程目錄路徑D:\Android\aa
  6. Package name包名建議使用反向域名語法創建包名.『應用名+域名』以防Java類名衝突.按Edit輸入『bookcard.aa』
  7. 單擊NEXT選擇生成應用設備類型和SDK版本.設備類型有『手機』『平板』『穿戴設備』『電視』『汽車』『物聯網』
  8. 選擇Android SDK最新版本是API-28甘樣只有最新版本Android設備才能運行.而且Android向前(舊版本)兼容.所以你應儘量使用低版本SDK依度選擇API-14 Andorid4.0舊設備已經很難在市面見到.按Help me choose可查看Android各板本市場佔有率
  9. 安卓即時應用程序『Include Android Instant app support』無需勾選
  10. 單擊NEXT選擇模板.這裡選擇Empty Activity不含用戶界面只創建XML佈局
  11. 單擊NEXT生成主Activity文件.『Activity Name』填MainActivity 勾選『Generate Layout File』生成佈局文檔
  12. 『Layout Name』佈局名填main勾選Backwards Compatibility(AppCompat) 『向兼容』
  13. 最後單擊Finish生成Project

Android Studio導入Eclipse項目

Android Studio導入Eclipse項目
Android Studio導入Eclipse項目

雖然Eclipse ADT和Android Studio有不同目錄結構與配置.但可通過其自帶『Import Project』完成工程轉換

  1. 使用『Import Project(Gradle,Eclipse ADT,etc.)』導入Eclipse項目
  2. 選擇Eclipse項目目錄路徑『Select Eclipse or Gradle Project to Import』如G:\Android\aa
  3. 選擇導入目標目錄路徑『Import Destination Directory』如D:\Android\aa
  4. 若目錄不存在則生成『Directory Does Not Exist』
  5. 勾選Replace jars with dependencise,when possible『替換附屬jars』
  6. 勾選Replace library sources with dependencies,when possible『替換附屬Lib文檔』
  7. 勾選Create Gradle-style(camelCase)module names『創建漸變風格模塊名稱』
  8. 如果出現項目無法轉換 如properties Library reference .. could not be found只需要編輯project.properties刪掉無穩到Library即可
  9. 按Finish轉換項目

Android Studio下載與安裝

安裝JAVA
安裝Android Studio
安裝Android Studio
安裝Android Studio
Android Studio下載與安裝Path

以前開發Android遊戲一直使用Eclipse ADT插件進行.因為換左台新電腦覺得是時候轉入『Android Studio』懷抱.只因它是Google親生仔.而且已中止為Eclipse ADT插件和Android Ant編譯系統更新開發.而且Android Studio比起Eclipse啟動速度快很多(因為無需載入所有項目)

安裝JAVA

  1. 首先要下載Java SE(Standard Edition) Development Kit簡稱(JDK) 下載jdk-10.0.1_windows-x64_bin.exe(JDK10只有x64版本)
  2. 單擊開此安裝JDK,勾選『Public JRE』和『Development Tools』、『Source Code』
  3. 安裝路徑選擇默認即可C:\Program Files\Java\jdk-10.0.1\
  4. 為JAVA設定Windows環境路徑.按『Win + Pause Break』鍵打開『系統』/進階系統設定/環境變量/系統變數(S)/
  5. 按『新增』系統變數.『變數名稱』輸入JAVA_HOME『變數值』輸入JAVA安裝路徑『C:\Program Files\Java\jdk-10.0.1\』按『確定』保存
  6. 編輯『Path』系統變數追加『%JAVA_HOME%\bin;』 按『確定』保存

 

安裝Android Studio

  1. 打開下載 Android Studio頁面. Windows有x64安裝版android-studio-ide-173.4819257-windows.exe
  2. 單擊安裝Android Studio 並且確保電腦能連結互聯網.因為安裝過程需要下載所需文檔
  3. 構選Android Virtual Device
  4. 安裝路徑選擇默認即可C:\Program Files\Android\Android Studio
  5. 首次啟動會睇到Complete Installation對話框.因為是全新安裝勾選Do not import settings不導入設置
  6. 第一次啟動時若出現『Unable to access Android SDK add-on list』因為沒有安裝Android SDK.按Cancel後逐安裝
  7. 介面有Intellij和Darcula可選
  8. 勾選Android Virtual Device和Performance(Intel HAXM)HAXM是虛擬引擎加強運行x86 Android虛擬機表現
  9. 最後下載Android SDK完成安裝.要保正常連結com
  10. 為Android Studio設定Windows環境路徑.按『Win + Pause Break』鍵打開『系統』/進階系統設定/環境變量/系統變數(S)/
  11. 按『新增』系統變數.『變數名稱』輸入ANDROID_HOME『變數值』輸入Android SDK安裝路徑如『C:\Android\Sdk』. 按『確定』保存.如果你唔知SDK安裝路徑可同過『FILE->Other Settings->Default Project Structure->Android SDK location』睇到
  12. 編輯『Path』系統變數追加『%ANDROID_HOME%\platform-tools;%ANDROID_HOME%\tools;』 按『確定』保存
  13. 啟動Android Studio
  14. 下載『SDK Tools』按『File->Settings->Android SDK->SDK Tools』
  15. 勾選Android SDK Build-Tools
  16. 勾選Android SDK Platform-Tools
  17. 勾選Android SDK Tools
  18. 勾選Google Play APK Expansion library
  19. 勾選Google Play Licensing library
  20. 勾選Google Play services
  21. 勾選Google USB Driver
  22. 勾選Google WEB Driver
  23. 按Apply自動下載安裝

 

若在手機上調試APP必須正確安裝ADB

  1. 下載Android SDK Platform-Tools
  2. 系統『path』變數必須需正確設置.
  3. 下載並正確安裝Google USB Driver.
  4. adb.exe devices 查看是否正確連接手機

 

 

小米MAX2

小米MAX2

台『小米2S』經常報空間不足,點刪APP都一樣.而且可部機跌過落地,影相經常花屏.是時侯要換個台手機.睇來睇去都是『小米MAX2』擁有『128GB固態硬盤』『4GB記憶體』先是1699紋.喂一不足時款式以落後.拿到手後想通過『一鍵換機』將電話簿『連絡人』移到『小米MAX2』點知按『我是新手機』WIFI馬上關閉.你需要重新『開啟WLAN』.後來通過『同步』『連絡人』,支持快充台機只是微微發熱.

 

Android桌面已鎖定

Android桌面已鎖定

近日台Android電話在刪除或移動APP時,彈出『桌面已鎖定』大驚難道中毒?細想之下應該是桌面被鎖定,通過下面設定即可修復

  1. 打開『設定』
  2. 打開『系統和設備/桌面與近期任務』
  3. 禁用『桌面佈局/鎖定桌面佈局』

小米電視4A人工智能語音55英寸小測

小米電視4A人工智能語音55英寸小測
小米電視4A人工智能語音55英寸小測

我老竇屋企台20年前29寸電視終於離開左我,需要穩一台質量性能都要過得去電視.鑒於LCD屏幕都是進口, 話買杂牌子也可了, 睇咗多個杂牌子RAM與硬盤都較小.唯有小米人工智能語音版有內存2GB硬盤32GB.在官網3599單價+200運費=3799元.但要20天內發貨.

於是與老竇去小米的專賣店梯下臺實機,雖然這台吾是無邊框設計但梯起來還可以.與是走去櫃檯問價格,報價2499單價+200運費=2699元.大驚以為店員搞錯細問之下,原來小米專賣店特權降價1100最後今晚,與老竇商量後馬上下單,8月27號晚落單8月30號下午送到,小米自有車所以無需經外面物流公司.

腳架與專賣店唔一樣在果度睇是一對叉,不過與官網上是一致.音頻輸出擴音機比較麻煩.手頭上無S/PDIF線,使用HDMI轉AV需要買轉換器,而藍牙大部分的功放都無這個接口.只能用個藍牙小音箱試左下.

清晰度要看最小矢量字體.而影片因為屏幕較大看分辯率細的效果吾會好,但如果片源分辯率高它的效果就可以梯出來.另外分辨率較高的片都要付費.較新都要VIP!暈…令外它帶有高頻頭可以自已裝條魚骨天線.

另外語音功能按住搖控器第二個按扭講話但意義不大

 

Android存儲空間不足

Android存儲空間不足
Android存儲空間不足

一般的Android存儲空間不足都是由於WebView的緩存和APP的下載的數據造成的,通過清理垃圾助手的工具一般可得到解決.但我遇到一個極端例子,把所有外加安裝的軟件刪除,在使用垃圾助手也會報存儲空間不足.它主要體現在果D使用WebView的應用無法打開圖片.後來我無意義之間得到修復.

  1. 設置/設備/應用/Google Play服務
  2. 結束運行
  3. 刪除

存儲空間不足的問題消失了.但我要警告.著是一個極端例子,而且此方法只適用於大陸被切割Google Play服務的Android手機,並且如造成系統的破壞與我無關.

顏色代碼

顏色代碼
這是一款生成自定義顏色的應用程式.
展示色樣,色板的實用工具!
全中文顏色名稱
專業的顏色選擇器
用戶自定義顏色(RGB/CMYK)
按音量鍵切換畫面
分享自定義的顏色代碼
支援多種顏色模型/顏色空間轉換

http://shouji.baidu.com/software/8050740.html

Android温度计

Android高度計

設計手機高度計!外出旅遊必備!

利用手機的氣壓傳感器,計算當前海拔高度!

安桌手機的通常帶有氣壓的監聽器

1.獲取感測器管理器

Sensor_Manager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE);

2.判斷是否有氣壓計,這個判斷很種要,如過返回則代表沒有可用的感測器!

if(Sensor_Manager.getSensorList(Sensor.TYPE_PRESSURE).size() == 0)

return false;

3.獲取默認的氣壓計

Pressure_Sensor = Sensor_Manager.getDefaultSensor(Sensor.TYPE_PRESSURE);

或者獲取的首個氣壓計

Pressure_Sensor = Sensor_Manager.getSensorList(Sensor.TYPE_PRESSURE).get(0);

4.生成氣監聽器

Pressure_Listener = new PressureListener();

5.註冊感測器事件

Sensor_Manager.registerListener(Pressure_Listener, Pressure_Sensor, SensorManager.SENSOR_DELAY_UI);

6.創建氣壓的監聽器類,用於獲取氣壓!

static class PressureListener implements SensorEventListener{

7.氣壓盤改變

@Override

public void onSensorChanged(SensorEvent event)

{

Pressure = event.values[0]; //獲取氣壓

}

}

8.氣壓轉高度

每上升12米,氣壓計中的水銀柱下降1毫米,

hPa是百帕

在海平面的平均氣壓 約為1013.25百帕斯卡(760毫米水銀柱),這個值也被稱為標準大氣壓

1百帕=1毫巴=3/4毫米水銀柱

所以901HPA(氣壓)

901HPA=901*3/4=682.5MM水銀柱

760-682.5=77.5MM

77.5*12=930米

public static float PressureToAltitude(float Pressure)

{

float Altitude = 0;// 高度

float PRESSURE_STANDARD_ATMOSPHERE = 1013.25f;// 在海平面的平均氣壓(百帕斯卡)

 

// 轉換為水銀柱

Altitude = (float) (44330000f* (1f- Math.pow( Pressure/PRESSURE_STANDARD_ATMOSPHERE, 1.0f/5255.0f )));

return Altitude;

}

 

10.退出應用時釋放感測器監聽

Sensor_Manager.unregisterListener(Pressure_Listener);

//米轉英尺

static float m2ft(float m)

{

float ft=0;

ft = m * 3.2808398950131f;

return ft;

}

 

//米轉英尺

static float ft2m(float ft)

{

float m=0;

m = ft * 0.3048f;

return m;

}

沒有氣壓傳感器則通過GPS確定高度,後續.

Android分贝仪

android分贝仪
邻居的音响影响你的睡眠?工地的噪音影响你的听力?
利用手机的咪克风,测量声音强度.
你需要android的录音AudioRecord接收声音
static android.media.AudioRecord          Audio_Record;
每个采样单位所占空间
static int BitsPerSample = 16;
设置音频采样率,44100是目前的标准,但是某些设备仍然支持22050,16000,11025
static int    Audio_Frequency = 44100;音频采样率
设置音频的录制的声道CHANNEL_IN_STEREO为双声道,CHANNEL_CONFIGURATION_MONO为单声道
设置声道配置-单声道,双声道除非你有两个咪克风,否则无意义.
static int    Audio_Channel   = AudioFormat.CHANNEL_CONFIGURATION_MONO;
static int    Audio_Channel_Count = 1;// 一个声道
static int    Audio_Encoding  =  AudioFormat.ENCODING_PCM_16BIT;// 音频编码
static byte   Audio_Buffer[];
static int    Audio_Buffer_Size;

1.计算缓冲的大小
Audio_Buffer_Size = android.media.AudioRecord.getMinBufferSize(Audio_Frequency, Audio_Channel, Audio_Encoding);
2.分配内存空间
Audio_Buffer = new byte[Audio_Buffer_Size];
3.分配录音对象
Audio_Record = new android.media.AudioRecord(MediaRecorder.AudioSource.MIC,
Audio_Frequency, Audio_Channel, Audio_Encoding,
Audio_Buffer_Size);
4.启动录音
Audio_Record.startRecording();
5.退出时要释放资源
Audio_Record.stop();// 停止
Audio_Record.release();// 释放

读取音频数据
size = Audio_Record.read(Audio_Buffer,0, Audio_Buffer_Size);
if(size == android.media.AudioRecord.ERROR_INVALID_OPERATION )
return true;
v = 0;
Audio_Size = Audio_Size + size;// 文件的大小

for(int i=0;i<size;i=i+2)
{
value = (Audio_Buffer[i+1] << 8) + Audio_Buffer[i];
v = v + (value * value);
}
平方和除以数据总长度,得到音量大小。
mean = v /(double)(size);  // 音量
最后计算分贝
Decibel_Val = 10 * Math.log10(mean);

创建新的线程
Audio_Thread = new Thread(new Runnable() {
public void run() {
while(Audio_State == STATE_RUN)
{
Read(); // 读取

}

Audio_Record.stop();// 停止
Audio_Record.release();// 释放
Audio_Record = null;
Audio_Thread = null;
}} );

Android罗盘又稱指南針,指北針

罗盘
罗盘又稱指南針,指北針,遊行必備,尋找目的地的方位!
支持磁偏角,真北极与磁北极之间转换!
偏航度:0-360
傾斜度:-90 ~ +90
橫搖度:-180 ~ +180
利用安桌手机的加速度传感器与磁场传感器,我在这里同时注册两个传感器.
1.获取传感器管理器
Sensor_Manager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE);
2.创建罗盘监听器对像
Compass_Listener = new CompassListener();
3.判断是否有加速度计
if(Sensor_Manager.getSensorList(Sensor.TYPE_ACCELEROMETER).size() == 0)
return false;
4.获取第一个加速度计
Sensor_Accelerometer = Sensor_Manager.getSensorList(Sensor.TYPE_ACCELEROMETER).get(0);
或着获取默认的加速度计
Sensor_Accelerometer = Sensor_Manager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
5.注册传感器事件
Sensor_Manager.registerListener(Compass_Listener, Sensor_Accelerometer, SensorManager.SENSOR_DELAY_UI);

6.判断是否有磁场传感器
if(Sensor_Manager.getSensorList(Sensor.TYPE_MAGNETIC_FIELD).size() == 0)
return false;
7.获取第一个磁场传感器
Sensor_Magnetic = Sensor_Manager.getSensorList(Sensor.TYPE_MAGNETIC_FIELD).get(0);
或着获取默认的磁场传感器
Sensor_Magnetic = Sensor_Manager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
5.注册传感器事件
Sensor_Manager.registerListener(Compass_Listener, Sensor_Magnetic, SensorManager.SENSOR_DELAY_UI);
退出时释放传感器监听
Sensor_Manager.unregisterListener(Compass_Listener);
Sensor_Manager.unregisterListener(Sensor_Manager);

6.生成罗盘的监听器
static class CompassListener implements SensorEventListener{
7.罗盘改变
@Override
public void onSensorChanged(SensorEvent event)
{
if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER)
{
Accelerometer_Values = event.values.clone();// 获取重力
float x = event.values[0];
float y = event.values[1];
float z = event.values[2];
GetAcceleration(x,y,z);// 获取重力
}
else
if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD)
{
Magnetic_Values = event.values.clone();  // 获取磁场
}
GetYaw();// 偏航度
GetPitch(); // 倾斜度
GetRoll();//  横摇度
//发送选择通知
notifyVisibility();
}
}

public static float Yaw=0;// 偏航度
public static float Pitch=0;//倾斜度
public static float Roll=0;//  横摇度

static float[] inR = new float[9];
static float[] outR = new float[9];
static float[] V = new float[3];

计算横摇度
倾斜度为0度时横摇度最准确
获取旋转矩阵
SensorManager.getRotationMatrix(inR, null,Accelerometer_Values,Magnetic_Values);
获取设备的方向
Window_Manager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
display = Window_Manager.getDefaultDisplay();
if(SYSTEM.GetVersion() >= 8)
rotation = display.getRotation();
else
rotation = display.getOrientation();
与设备的方向配合修正方向,省略.
x_axis = SensorManager.AXIS_X;
y_axis = SensorManager.AXIS_Y;
校正后的方向
SensorManager.remapCoordinateSystem(inR, x_axis, y_axis, outR);
提取弧度
SensorManager.getOrientation(outR, V);
弧度转为角度,横摇度
Roll =  (float) Math.toDegrees(V[2]);

获取倾斜度
获取旋转矩阵
SensorManager.getRotationMatrix(inR, null,Accelerometer_Values,Magnetic_Values);
获取设备的方向
Window_Manager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
display = Window_Manager.getDefaultDisplay();
if(SYSTEM.GetVersion() >= 8)
rotation = display.getRotation();
else
rotation = display.getOrientation();
与设备的方向配合修正方向,省略.
x_axis = SensorManager.AXIS_X;
y_axis = SensorManager.AXIS_MINUS_Z;

校正后的方向
SensorManager.remapCoordinateSystem(inR, x_axis, y_axis, outR);
提取弧度
SensorManager.getOrientation(outR, V);
弧度转为角度
Pitch = (float) Math.toDegrees(V[1]);

获取偏航度
获取旋转矩阵
SensorManager.getRotationMatrix(inR, null,Accelerometer_Values,Magnetic_Values);
获取设备的方向
Window_Manager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
display = Window_Manager.getDefaultDisplay();
if(SYSTEM.GetVersion() >= 8)
rotation = display.getRotation();
else
rotation = display.getOrientation();
与设备的方向配合修正方向,省略.
x_axis = SensorManager.AXIS_Y;
y_axis = SensorManager.AXIS_MINUS_X;
校正后的方向
SensorManager.remapCoordinateSystem(inR, x_axis, y_axis, outR);
提取弧度
SensorManager.getOrientation(outR, V);
弧度转为角度
Yaw = (float) Math.toDegrees(V[0]);
磁北极=正北极+偏磁角
正北极=磁北极-偏磁角
Yaw = Yaw – GPSService.Declination;

http://shouji.baidu.com/software/8452414.html

Android高度計

設計手機高度計!外出旅遊必備!
利用手機的氣壓傳感器,計算當前海拔高度!
安桌手機的通常帶有氣壓的監聽器
1.獲取感測器管理器
Sensor_Manager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE);
2.判斷是否有氣壓計,這個判斷很種要,如過返回則代表沒有可用的感測器!
if(Sensor_Manager.getSensorList(Sensor.TYPE_PRESSURE).size() == 0)
return false;
3.獲取默認的氣壓計
Pressure_Sensor = Sensor_Manager.getDefaultSensor(Sensor.TYPE_PRESSURE);
或者獲取的首個氣壓計
Pressure_Sensor = Sensor_Manager.getSensorList(Sensor.TYPE_PRESSURE).get(0);
4.生成氣監聽器
Pressure_Listener = new PressureListener();
5.註冊感測器事件
Sensor_Manager.registerListener(Pressure_Listener, Pressure_Sensor, SensorManager.SENSOR_DELAY_UI);
6.創建氣壓的監聽器類,用於獲取氣壓!
static class PressureListener implements SensorEventListener{
7.氣壓盤改變
@Override
public void onSensorChanged(SensorEvent event)
{
Pressure = event.values[0]; //獲取氣壓
}
}
8.氣壓轉高度
每上升12米,氣壓計中的水銀柱下降1毫米,
hPa是百帕
在海平面的平均氣壓 約為1013.25百帕斯卡(760毫米水銀柱),這個值也被稱為標準大氣壓
1百帕=1毫巴=3/4毫米水銀柱
所以901HPA(氣壓)
901HPA=901*3/4=682.5MM水銀柱
760-682.5=77.5MM
77.5*12=930米
public static float PressureToAltitude(float Pressure)
{
float Altitude = 0;// 高度
float PRESSURE_STANDARD_ATMOSPHERE = 1013.25f;// 在海平面的平均氣壓(百帕斯卡)

// 轉換為水銀柱
Altitude = (float) (44330000f* (1f- Math.pow( Pressure/PRESSURE_STANDARD_ATMOSPHERE, 1.0f/5255.0f )));
return Altitude;
}

10.退出應用時釋放感測器監聽
Sensor_Manager.unregisterListener(Pressure_Listener);

//米轉英尺
static float m2ft(float m)
{
float ft=0;
ft = m * 3.2808398950131f;
return ft;
}

//米轉英尺
static float ft2m(float ft)
{
float m=0;
m = ft * 0.3048f;
return m;
}
沒有氣壓傳感器則通過GPS確定高度,後續.