[Book Note: Android game programming starts from scratch] 11. Game Development BASICS (differences between SurfaceView game framework, View, and SurfaceView), learn android from scratch

Source: Internet
Author: User
Tags drawtext introductions

[Book Note: Android game programming starts from scratch] 11. Game Development BASICS (differences between SurfaceView game framework, View, and SurfaceView), learn android from scratch

1. SurfaceView game framework instance

Instance effect: the text on the screen is moved with the clicked place, as shown below:

 

Steps:

Create a project "GameSurfaceView". First, define a class "MySurfaceView". This class inherits SurfaceView and implements the android. view. SurfaceHolder. Callback interface. The Code is as follows:

Package com. example. ex4_5; import android. content. context; import android. graphics. canvas; import android. graphics. color; import android. graphics. paint; import android. view. motionEvent; import android. view. surfaceHolder; import android. view. surfaceHolder. callback; import android. view. surfaceView; // The Callback interface is used by SurfaceHolder to listen to the SurfaceView status. public class MySurfaceView extends SurfaceView implements Callba Ck {// used to control the SurfaceView size and format, and monitors the SurfaceView State private SurfaceHolder sfh; private Paint paint; private int textX = 30, textY = 30; public MySurfaceView (Context context) {super (context); // instance SurfaceView sfh = this. getHolder (); // Add status listening sfh for SurfaceView. addCallback (this); // instance a paint brush Paint = new paint (); // set the font size to paint. setTextSize (30); // you can specify the paint color. setColor (Color. GREEN);} @ Override // when SurfaceView After being created, the system returns public void surfaceCreated (SurfaceHolder holder) {myDraw () ;}@ Override // returns public void surfaceChanged (SurfaceHolder holder, int format, int width, int height) {}@ Override // when the SurfaceView state is destroyed, the Response public void surfaceDestroyed (SurfaceHolder holder) {}// SurfaceView uses SurfaceHolder to modify its data, therefore, the onDraw (Canvas canvas) function of the View is instantly rewritten and will not be executed when SurfaceView is started. Therefore, the custom drawing function is public here. Void myDraw () {// obtain the Canvas object of SurfaceView, // lock the obtained Canvas at the same time, this prevents SurfaceView from being modified or destroyed during the painting process. // another lockCanvas (Rect rect) function is used to input an instance of a Rect rectangle class, canvas canvas = sfh. lockCanvas (); // fill in the background color, that is, screen flushing. Each time before drawing the canvas, the canvas is overwritten. drawColor (Color. BLACK); // draw the content canvas. drawText ("This is a Text! ", TextX, textY, paint); // unlock the canvas and submit sfh. unlockCanvasAndPost (canvas);} // rewrite the event @ Override public boolean onTouchEvent (MotionEvent event) {textX = (int) event. getX (); textY = (int) event. getY (); myDraw (); return super. onTouchEvent (event );}}MySurfaceView

Modify the MainActivity class to display the custom SurfaceView.

Public class MainActivity extends Activity {@ Overrideprotected void onCreate (Bundle savedInstanceState) {super. onCreate (savedInstanceState); // display the custom SurfaceView setContentView (new MySurfaceView (this ));}}

Set the application to full screen in the configuration file

android.view.SurfaceHolder.Callback

For more information, see the code.

 

2. Add a thread to the SurfaceView

In the game, the canvas will not be re-painted until the user triggers the button event or touch screen event each time, but will be refreshed at a fixed time: for example, the countdown in the game, the dynamic flowers and plants, the water, and so on, these game elements do not interact with players, but these elements are dynamic. Therefore, in game development, there is a thread that constantly deduplicates the canvas and updates the status of game elements in real time.
Of course, in addition to the canvas that gives gamers the most direct dynamic display, there will also be a lot of logic that needs to be constantly updated, such as the AI of monsters (Artificial Intelligence), the update of coins in the game, and so on.

Next, we will add a thread to the SurfaceView view in the above instance for continuous re-painting and continuous execution of game logic.

The instance effect is as follows:

After modification, the MySurfaceView class code is as follows:

Package com. example. ex4_5; import android. content. context; import android. graphics. canvas; import android. graphics. color; import android. graphics. paint; import android. view. keyEvent; import android. view. motionEvent; import android. view. surfaceHolder; import android. view. surfaceHolder. callback; import android. view. surfaceView; // The Callback interface is used by SurfaceHolder to listen to the SurfaceView status. public class MySurfaceView extends SurfaceView implements Callback, Runnable {// used to control the SurfaceView size and format, and is mainly used to monitor the SurfaceView State private SurfaceHolder sfh; // declare a Paint brush private paint Paint; // text coordinate private int textX = 30, textY = 30; // declare a Thread private Thread th; // private boolean flag; // declare a Canvas private canvas Canvas; // declare the width and height of the screen private int screenW and screenH;/*** SurfaceView initialization function ** @ param context */public MySurfaceView (Context context) {super (context); // instance SurfaceView sfh = this. getHolder (); // Add status listening sfh for SurfaceView. addCallback (this); // instance a paint brush Paint = new paint (); // set the font size to paint. setTextSize (20); // you can specify the paint color. setColor (Color. WHITE); // set the focus setFocusable (true);}/*** SurfaceView creation, response to this function */@ Override public void surfaceCreated (SurfaceHolder holder) {screenW = this. getWidth (); screenH = this. getHeight (); Flag = true; // instance Thread th = new Thread (this); // start Thread th. start ();}/*** response to this function */@ Override public void surfaceChanged (SurfaceHolder holder, int format, int width, int height) when the SurfaceView status changes) {}/*** response to this function */@ Override public void surfaceDestroyed (SurfaceHolder holder) {flag = false ;} /*** game plotting */public void myDraw () {try {canvas = sfh. lockCanvas (); if (canvas! = Null) {// ---- use a rectangle to screen. // canvas. drawRect (0, 0, this. getWidth (), this. getHeight (), // paint); // ---- fill the canvas with the help of canvas. // canvas. drawColor (Color. BLACK); // ---- fill the canvas with the specified color component to screen the canvas. drawRGB (0, 0, 0); canvas. drawText ("La la, de masia! ", TextX, textY, paint) ;}catch (Exception e) {// TODO: handle exception} finally {if (canvas! = Null) {sfh. unlockCanvasAndPost (canvas) ;}}/ *** touch screen event listener */@ Override public boolean onTouchEvent (MotionEvent event) {textX = (int) event. getX (); textY = (int) event. getY (); return true ;}@ Override public boolean onKeyDown (int keyCode, KeyEvent event) {return super. onKeyDown (keyCode, event);}/*** game logic */private void logic () {}@ Override public void run () {while (flag) {long start = System. currentTimeMillis (); myDraw (); logic (); long end = System. currentTimeMillis (); try {if (end-start <50) {Thread. sleep (50-(end-start);} catch (Exception e) {e. printStackTrace ();}}}}MySurfaceView

Code Description:

(1) thread identifier

In the code, the "boolean flag;" statement declares a boolean value, which is mainly used for the following two points: ① It is convenient for a dead thread. Once a thread is started, it will execute the run () function, run () after the function execution is complete, the thread also disappears. Because the thread used in game development generally uses a while endless loop in the run () function, in which the drawing and logic functions are called, this allows you to constantly refresh the canvas and update the logic. If the game is paused or the game ends, a flag is set here to facilitate thread destruction. ② To prevent repeated creation threads and program exceptions, we should first start with the Android mobile phone. Anyone familiar with or familiar with Android systems knows that Android phones generally have "Back" and "Home" buttons. No matter what programs are running on your mobile phone, you only need to click "Back" or "Home, by default, the current program is switched to the system background for running (the two buttons are not intercepted in the Program). This also causes the status of the MySurfaceView to change. Click the Back button to switch the current program to the background, and then click the project to return to the program. The SurfaceView status changes to surfaceDestroyed-> constructor-> surfaceCreated-> surfaceChanged. Click the "Home" button to switch the current program to the background, and then click the project to return to the program. The SurfaceView status changes to surfaceDestroyed-> surfaceCreated-> surfaceChanged. The SurfaceView shows that when you click the Back button and re-enter the program, a constructor is executed more than clicking the Home button. That is to say, when you click "Back" to return the button, the SurfaceView will be reloaded. For this reason, if the thread Initialization is before the constructor or constructor, the thread should also be placed in the view constructor. Do not initialize a thread before creating a function in the surfaceCreated view, but start a thread in the function created in the surfaceCreated view, otherwise, the program throws an exception once the player clicks the "Home" button and returns to the game again. The exception is caused by the thread being started. The cause is very simple. When the program is switched to the background by the "Home" key and then restored from the background, it will directly go to the surfaceCreated view to create a function, thread started again! The solution is to put the initialization and startup of the thread in the constructor of the view, or both in the function created by the view. However, a new problem occurs here. If you put the initialization and startup of the thread in the constructor of the view, when the program is "Back" key into the background and then restored from the background, the number of threads increases, and the number of corresponding threads increases repeatedly. Then, if you change the flag thread identifier to false when the view is destroyed, the run method of the current thread is executed to destroy the thread, but what if I click "Home? When the program recovers, the program will not execute the thread, that is, the re-painting and logic functions will not be executed! Therefore, the best practice is to write the initialization of the thread and the startup of the thread in the surfaceCreated creation function of the view, and change the value of the thread flag to false when the view is destroyed. In this way, the "thread started" exception can be avoided, and the number of threads can be increased infinitely by clicking the Back button.Introductions

(2) Get the width and height of the View

Method for obtaining the width and height of a view in SurfaceView: this. getWidth (); get the view width this. getHeight (); obtain the view height. You must obtain the width and height of the view in SurfaceView. It must be obtained after the view is created, that is, after the surfaceCreated function, the result obtained before the function is executed is always zero, because the current view has not been created, and there is no high value of width.Introductions

(3) try the drawing function.

When SurfaceView is not editable or has not yet been created, calling the lockCanvas () function will return null. When Canvas is used for drawing, unpredictable problems may also occur, so try to draw the function... catch processing; since the lockCanvas () function may be obtained as null, to avoid errors reported by other functions that use the canvas instance for painting, you need to determine whether it is null.Introductions

(4) The submission canvas must be placed in finally

Unpredictable bugs may occur during drawing. Although the try statement is encapsulated, the program will not crash. However, once an error occurs before submitting the canvas, the Canvas function cannot be executed when it is unlocked and submitted. This will cause the program to throw an exception when it uses lockCanvas () to obtain the Canvas. The reason is that the Canvas was not unlocked and submitted last time! Therefore, the canvas should put the unlocked and submitted functions into the finally statement block. Note that, although this ensures that the Canvas can be normally submitted each time, you must ensure that the Canvas is not empty before you submit the Canvas for unlocking. Therefore, you must determine whether the Canvas is empty, in this way, it is perfect.Introductions

(5) Try to keep the frame flushing time consistent

Although the sleep time is set in the thread loop, This is not perfect! For example, in the current project, in the while loop of run, in addition to calling the drawing function, the logic () function that processes the game logic is always called, although no code is written in the logic functions of the current project, if the logic function logic () contains thousands of lines of logic, when the system processes the logic, whether the time overhead is the same as the previous one is unpredictable, but the time difference can be kept the same as possible. Assume that the sleep time of the game Thread is X ms. Generally, the Thread sleep statement is Thread. sleep (X); the optimization method is as follows: Step 1 first obtain a timestamp through the System function: long start = System. currentTimeMillis (); // functions in the thread, such as plotting and logic. Step 2. After processing all the above functions, obtain a timestamp through the System function again: long end = System. currentTimeMillis (); Step 3, through the difference between the two timestamps, you can know the time consumed by these functions: If (end-start)> X, then there is no need for the thread to sleep; If (end-start) <X, the thread's sleep time should be X-(end-start ). Thread sleep should be changed to the following statement: if (end-start) <X) {Thread. sleep (X-(end-start);} generally, the refresh time in the game is between 50 and ~ 100 milliseconds, that is, 10 ~ About 20 frames, depending on the actual situation and project.Introductions

 

3. Differences between View and SurfaceView

1. Update the canvas
Re-drawing the canvas in View is performed by calling the postInvalidate () and invalidate () functions provided by View, that is, the canvas is updated by the system main UI. Some problems may occur when the main UI thread of the system updates the canvas. For example, if the screen is updated for a long time, the main UI thread will be blocked by the rendering function, in this way, messages such as buttons and touch screens cannot be responded.
In SurfaceView, the re-painting of the canvas is performed by a new separate thread, so there will be no problems such as failure to respond to buttons and touch screen information due to blocking of the main UI thread.

2. View Mechanism
The View in Android does not have a dual buffer mechanism, but the SurfaceView does! SurfaceView is a View class expanded from View that is more suitable for game development.
Both View and SurfaceView have their own advantages:
For example, for a card and board game, the screen update of this type of game is passive update; because canvas re-painting is mainly dependent on buttons and touch-screen events (the canvas needs to be updated only after the player has an operation), it is more appropriate for such games to select the View for development, it also reduces the running overhead caused by the use of SurfaceView, which requires a new thread to constantly update the canvas.
However, for games that actively update canvases, such as RPG games and flying shooting games, many elements are dynamic and need to be re-painted constantly, in this case, it is obviously not appropriate to use the View.
Therefore, the development of the game to use which view is more appropriate depends on the type, style, and needs of the game.
In general, SurfaceView is more suitable for game development because it can adapt to more game types.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.