在上一章我們沒有把標題欄和狀態欄給去掉 , 如果在遊戲中 是不會顯示 顯示標題欄和狀態欄的, 如何去掉瞭, 很簡單, 在mainActivity 的onCreate方法中加入下面兩句 即可 :
requestWindowFeature(Window.FEATURE_NO_TITLE); //設置無標題
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); //設置全屏
趕緊去試試吧 , 寫程序就是要 多試 嘻嘻..
圖片有瞭 ,我們怎麼樣才能讓圖片有行為呢 ? 那就需要人機交互瞭,通過觸摸屏讓遊戲具有行為
先在這裡 說明下android 的坐標系
android 的坐標系 左上定點為原點坐標(0,0), 向右為X軸,向下為Y軸 說明這個位置是因為有些遊戲引擎是 以 左下為原點的哦 , 大傢要記住喔,後面如果用引擎的話 也有個概念
下面 我們來看看android 的 觸摸屏事件是怎麼處理的
我們先來分析下 現在的用戶界面 都是通過事件驅動 實現人機交互的,當屏幕的界面接受到事件時 根據不同情況 進行不同的處理 就可以實現人機交互瞭
android 支持的觸摸屏事件有:按下、彈起、移動、雙擊、長按、滑動。
按下、彈起、移動(down、move、up)是簡單的觸摸屏事件 我們本章就來說說這個東東.
而雙擊、長按、滑動、滾動需要根據運動的軌跡來做識別的。在Android中有專門的類去識別,android.view.GestureDetector。 這一塊我們後面的章節 在講
那如何實現呢?
在Android中任何一個控件和Activity都是間接或者直接繼承於android.view.View。一個View對象可以處理測距、佈局、繪制、焦點變換、滾動條,以及觸屏區域自己表現的按鍵和手勢,因為我們的view 是繼承瞭surfaceView,surfaceView又是繼承view 所以要實現簡單的觸摸屏事件,隻需要重寫父類view 裡面的onTouchEvent 方法就可以實現簡單的觸屏屏事件瞭
下面我們來實現一個功能 用上一章的程序 來實現 把圖片顯示在點擊觸摸屏的地方和圖片能根據手指移動而移動
直接看代碼
package yxqz.com;
import android.content.Context;
import android.content.DialogInterface;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.SurfaceHolder.Callback;
/**
* android surfaceview觸摸屏事件學習
* @author mahaile
*
*/
public class GameSurfaceView extends SurfaceView implements Callback{
boolean flag; //線程標示位 當為false時停止刷新界面
SurfaceHolder surfaceHolder;
GameViewThread gameViewThread;
float x=0,y=0;
int direction=0; //圖片運行方向 控制圖片向上 或向下運動
int width,height;
Bitmap bitmap_role;
public GameSurfaceView(Context context) {
super(context);
surfaceHolder=this.getHolder();
surfaceHolder.addCallback(this); //添加回調
bitmap_role=BitmapFactory.decodeResource(getResources(), R.drawable.role);
//設置焦點 如果不設置焦點的話 在該界面下 點擊觸摸屏是無效的 默認為false
setFocusable(true);
}
public void onDraw(Canvas canvas){
canvas.drawColor(Color.BLACK);
canvas.drawBitmap(bitmap_role, x-bitmap_role.getWidth()/2, y-bitmap_role.getHeight()/2, null);
}
//重寫父類中的 onTouchEvent就可以監聽到 觸摸事件瞭 記住要設置焦點喔
@Override
public boolean onTouchEvent(MotionEvent event) {
if(event.getAction()==MotionEvent.ACTION_DOWN){ //處理屏幕屏點下事件 手指點擊屏幕時觸發
x=event.getX();
y=event.getY();
}else if(event.getAction()==MotionEvent.ACTION_UP){//處理屏幕屏抬起事件 手指離開屏幕時觸發
}else if(event.getAction()==MotionEvent.ACTION_MOVE){//處理移動事件 手指在屏幕上移動時觸發
x=event.getX();
y=event.getY();
}
return true; //此處需要返回true 才可以正常處理move事件 詳情見後面的 說明
}
public void surfaceChanged(SurfaceHolder surfaceHolder, int format, int width, int height) {
}
public void surfaceCreated(SurfaceHolder surfaceHolder) {
//獲取屏幕的 寬高 隻有在 surface創建的時候 才有效 ,才構造方法中獲取 寬高是獲取不到的
width=this.getWidth();
height=this.getHeight();
//初始化繪圖線程
gameViewThread=new GameViewThread();
gameViewThread.flag=true;
gameViewThread.start();
}
public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
gameViewThread.flag=false; //銷毀線程
}
class GameViewThread extends Thread{
public boolean flag;
public void run(){
while(flag){
Canvas canvas=null;
try{
canvas=surfaceHolder.lockCanvas(); //鎖定畫佈 並獲取canvas
onDraw(canvas);//調用onDraw 渲染到屏幕
surfaceHolder.unlockCanvasAndPost(canvas); //此步不要忘記瞭喔 否則界面上顯示不出來的
}catch(Exception e){
e.printStackTrace();
}
try {
Thread.sleep(10);//線程休眠時間 控制幀數
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} //每10毫秒刷新一次
}
}
}
}
MainActivity 類 這裡就不貼代碼瞭,因為和上一章一樣 ,很簡單的
onTouchEvent() 返回值 解釋
解釋:
onTouchEvent(),預設使用Oeverride這個方法,通常情況下去呼叫super.onTouchEvent()並傳回佈林值。但是這裡要註意一點,預設如果去呼叫super.onTouchEvent()則很有可能super裡面並沒做任何事,並且回傳false回來,一旦回傳false回來,很可能後面的event (例如:Action_Move、Action_Up) 都會收不到瞭,所以為瞭確保保後面event能順利收到,要註意是否要直接呼super.TouchEvent()。
下一張 我們看看如果使用android的手勢識別
最後還要註意一點:在初始化的時候不要忘記setFocusableInTouchMode(true);觸屏模式獲取焦點,比較類似 setFocusable(true);
——setFocusable(true);//此方法是用來響應按鍵!如果是自己定義一個繼承自View的類,重新實現onKeyDown方法後,隻有當該View獲得焦點時才會調用onKeyDown方法,Actvity中的onKeyDown方法是當所有控件均沒有處理該按鍵事件時,才會調用.
原代碼下載地址:http://up.aiwalls.com/2012/0417/20120417100011952.rar
補充點 :
在android 中使用觸摸屏 在模擬機中 我們的鼠標當點擊一次模擬器屏幕然後釋放,先觸發 ACTION_DOWN 然後 ACTION_UP ;如果是在屏幕上移動那麼才會觸發 ACTION_MOVE 的動作;這個很正常, 但在真機中呢 ,是不是 也是這樣的呢 ? 答案是否定的 如果我們那真機測試的話 流程如下
先觸發 ACTION_DOWN 如果手指不抬起的話 會一直觸發ACTION_MOVE事件(就是不移動也會觸發) 然後 ACTION_UP
原因有兩點:第一點是因為,Android 對於觸屏事件很敏感!第二點:雖然我們的手指感覺是靜止沒有移動,其實事實不是如此!當我們的手指觸摸到手機屏幕上之後,感覺靜止沒動,其實手指在不停的微顫抖震動。 所以才會一直觸發action_move事件
這樣的情況對我們的程序有什麼影響呢
比如我們app線程繪圖時間每次用瞭10ms,當手指觸摸屏幕,這短暫的0.1秒內大概會產生10個左右的MotionEvent ,並且系統會盡可能快的把這些event發給監聽線程, 這樣的話在這一段時間內cpu可能忙於處理onTouchEvent事件 從而造成app 的界面沒有足夠資源去處理,而照成界面刷新一卡一卡的。
那麼我們其實根本用不著按鍵響應這麼多次,而是需要在我們每次繪圖後,或者繪圖前接受一次用戶觸摸事件就OK瞭,這樣能讓幀率不至於下降的太厲害不是麼?!如果我們能把觸屏監聽事件 觸發的事件 給慢下來 不就是可以解決這個問題瞭嗎 ,嘻嘻 就是這麼優化的
@Override
public boolean onTouchEvent(MotionEvent event) {
if(event.getAction()==MotionEvent.ACTION_DOWN){
}else if(event.getAction()==MotionEvent.ACTION_UP){
}else if(event.getAction()==MotionEvent.ACTION_MOVE){
}
synchronized(this){
try{
this.wait(Time); //讓事件線程休眠 減少觸發次數
}catch(InterruptedException e){
e.printStackTrace();
}
}
return true;
}
上面的代碼 加到你的onTouch 裡面 但有一點要註意喔 ,上面的線程同步對象使用瞭this ,如果這個類 也被別的類作為同步對象的話 ,可能發生死鎖喔, 如果這個類已經被作為瞭同步對象的話 , 我們重新初始化的時候 新new 一個對象 作為onTouch的同步對象就可以瞭
摘自 android,unity3d