【问题标题】:Surfaceview Skeleton Tutorial questionsSurfaceview 骨架教程问题
【发布时间】:2012-08-01 01:47:42
【问题描述】:

在搜索了 google、各种 android 博客、各种游戏开发博客和其他有关 android 中 SurfaceView 的教程网站后,我希望对 SurfaceView 有一个完整的了解。我在 Safaribooks 上阅读了几本关于 android 和表面视图的书籍,但它们提供的信息要么太少,要么使用其他 SDK,例如 AndEngine。我希望严格地学习表面观点。我玩过 Lunar Lander 示例项目以及我发现的其他项目,并创建了一些骨架表面视图的代码。它由仅用于骨架的 3 个类组成。

MainActivity 类:

package com.learning.svlearning;

import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
import android.view.Window;
import android.view.WindowManager;

public class MainActivity extends Activity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

    //Set FullScreen Mode - No title bars!!
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
        // Screen created with pure java - Say no to xml (atleast for this demo)
        setContentView(new MainGamePanel(this));
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.layout_game_window, menu);
        return true;
    }
}

这门课很简单。主游戏活动窗口,请求全屏,没有标题栏。一个真正的游戏应该是怎样的:)这个类通过传递“this”(MainActivity)类的上下文来调用我们的下一个视图类。

MainGamePanel 类:

package com.learning.svlearning;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

public class MainGamePanel extends SurfaceView {
final static public String tag = "Tracer";

private GameThread gameThread;  // For our thread needed to do logical processing without holding up the UI thread
private SurfaceHolder holder; // For our CallBacks.. (One of the areas I don't understand!)

public MainGamePanel(Context context) {
    super(context);
    Log.d(tag, "Inside MainGamePanel");
    gameThread = new GameThread(this); //Create the GameThread instance for our logical processing
    holder = getHolder();


    holder.addCallback(new SurfaceHolder.Callback() {


// Since we are using the SurfaceView, we need to use, at very least, the surfaceDestroyed and surfaceCreated methods.
        @Override
        public void surfaceDestroyed(SurfaceHolder holder) {
            boolean retry = true;
            Log.d(tag, "Inside SurfaceHolder Callback - surfaceDestroyed");
            gameThread.setRunning(false); // Stop the Thread from running because the surface was destroyed.  Can't play a game with no surface!!  

            while (retry) { 
                try {
                    Log.d(tag, "Inside SurfaceHolder Callback - surfaceDestroyed - while statement");
                    gameThread.join();
                    retry = false; //Loop until game thread is done, making sure the thread is taken care of.
                } catch (InterruptedException e) {
                    //  In case of catastrophic failure catch error!!!
                }
            }

        }

        @Override
        public void surfaceCreated(SurfaceHolder holder) {
            // let there be Surface!
            Log.d(tag, "Inside SurfaceHolder Callback - surfaceCreated");
            gameThread.setRunning(true); // Now we start the thread
            gameThread.start(); // and begin our game's logical processing

        }

        @Override
        public void surfaceChanged(SurfaceHolder holder, int format,
                int width, int height) {
            // The code to resize the screen ratio when it flips from landscape to portrait and vice versa

        }
    });
}

@Override
protected void onDraw(Canvas canvas) {
//This is where we draw stuff..  since this is just a skeleton demo, we only draw the color Dark Grey so we can visibly see that we actually accomplished something with the surfaceview drawing
    Log.d(tag, "Inside onDraw"); 
    canvas.drawColor(Color.DKGRAY); // You can change the Color to whatever color you want, for this demo I just used Color.DKGRAY 

    }

}

这个类主要处理使用onDraw方法绘制我们的资源/图像,处理我们的表面被创建和销毁时发生的事情(也当屏幕发生变化,但我暂时没有编写任何代码来处理它),并调用处理游戏逻辑处理的 GameThread 类。

GameThread 类:

package com.learning.svlearning;

import android.graphics.Canvas;
import android.util.Log;



public class GameThread extends Thread{
final static public String tag = "Tracer";


private MainGamePanel view; 
private boolean running = false;

static final long FPS = 30; // To help limit the FPS when we draw, otherwise we would kill the CPU and increase the Battery Consumption.

public GameThread(MainGamePanel view){
    Log.d(tag, "inside GameThread");
    this.view = view;
}

public void setRunning(boolean run){
    Log.d(tag, "inside GameThread - setRunning");
    running = run; // For starting / stoping our game thread
}


@Override
public void run() {
    long ticksPS = 1000 / FPS; // Limit the frames per second
    long startTime; 
    long sleepTime;
    Log.d(tag, "inside GameThread - run");

    while(running){ // Our Main Game Loop is right here
        Canvas c = null; // build our canvas to draw on
        Log.d(tag, "inside GameThread - run - while loop");
        startTime = System.currentTimeMillis(); //get the current time in milliseconds - this is for helping us limit the FPS
        try{
            c = view.getHolder().lockCanvas(); //Before we can draw, we always have to lock the canvas, otherwise goblins will invade your app and destroy everything!
            synchronized (view.getHolder()){ // we have to synchronize this because we need to make sure that the method runs when at the proper time.
                view.onDraw(c); // this is where we pass our drawing information.  The canvas gets passed to the onDraw method in our MainGamePanel class.
            }
        }finally{
            if(c != null) {
                view.getHolder().unlockCanvasAndPost(c); // Once we are done drawing, we unlock our canvas and post.  which means we drew on the canvas, and now the devices screen will display our drawing.
            }
        }
        sleepTime = ticksPS-(System.currentTimeMillis() - startTime); // this is where we calculace how long we need this thread to sleep (again with the FPS) we want it limited to 30 FPS as defined in our FPS variable.
        try {
            if (sleepTime > 0){
                   sleep(sleepTime); // night night, sleep to limit the fps and save our batteries!
            }
            else{
                   sleep(10); // Incase something goes crazy, we still want to sleep the thread to save the battery.
            }
        }catch(Exception e){

        }

    }

}


}

该类处理游戏逻辑并将任何可绘制信息发送到 MainGamePanel 类中的绘制方法。例如,如果我们有一个角色移动,我们可以将 x 和 y 坐标发送到我们的 draw 方法以将我们的角色绘制到不同的位置。

现在这些课程的某些部分我并不完全理解。就像回调一样,当阅读 googles android 开发者页面上的信息时,我对它是什么以及我们为什么使用它感到更加困惑。另外,如果有人对此有更多意见,或者看到我可能误解的任何内容,请随时纠正我。我喜欢使用 android 工作,虽然这很困难,但当你开始弄清楚事情时,它是非常有益的!

【问题讨论】:

  • surfaceholder回调的目的是什么?
  • 对于这么短的问题,这是我见过的最长的帖子。为什么不直接发布问题而不解释您的背景?

标签: android surfaceview


【解决方案1】:

SurfaceHolder 回调的目的是处理这 3 个事件。 surfaceCreated()、surfaceDestroyed() 和 surfaceChanged()。

如果您阅读代码,您会看到surfaceCreated() 处理在创建表面时需要发生的事情等等......

这是您问题的答案还是还有更多?

【讨论】:

    【解决方案2】:

    使用 SurfaceView 时,您应该将绘图方法更改为除 onDraw() 以外的名称。这样主线程就永远不会意外地 invalidate() 它!

    【讨论】:

    • 它怎么会不小心失效呢?
    猜你喜欢
    • 2016-08-25
    • 2011-08-29
    • 2012-08-29
    • 2017-07-24
    • 2013-09-10
    • 2011-03-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多