Chapter 6 surfaceview Animation
Difficulty: Moderate
The content described above is relatively simple. With this knowledge, you can complete some non-real-time games, such as the game player, or some games with low screen refresh frequency and poor real-time performance, for example, we used mine clearance. However, our goal is the tank war, which requires a lot of real-time operations, and many more NPC workers need to handle the problem. The drawing workload is also huge, therefore, we need to use a new view class surfaceview instead of view to complete the display. Surfaceview and view have some differences, but we only use one of the features: drawing on the screen outside the main thread. In this way, the main thread blocking can be avoided when the drawing task is heavy, thus improving the response speed of the program.
First, let's redefine a gameview class so that it inherits from surfaceview and implement the surfaceholder. Callback interface. Why do we need to implement the callback interface? Because surfaceview has a principle that all plotting work must be started after the surface is created. This concept is often mentioned in graphic programming. Basically, we can use it as a ing of the video memory. The content written to the surface can be directly copied to the video memory for display, which makes the display speed very fast ), the surface must end before it is destroyed. Therefore, surfacecreated and surfacedestroyed in callback form the boundary of the drawing processing code. We directly implement the callback interface for the gameview class to make the program simpler.
This is what gameview looks like after it is created and added to the constructor (the methods for creating classes and adding constructor are described earlier)
PackageOrg. yexing. Android. Games. tank;
ImportAndroid. content. context;
ImportAndroid. View. surfaceholder;
ImportAndroid. View. surfaceview;
ImportAndroid. View. surfaceholder. Callback;
Public ClassGameviewExtendsSurfaceviewImplementsCallback {
PublicGameview (context ){
Super(Context );
//TodoAuto-generated constructor stub
}
Public VoidSurfacechanged (surfaceholder arg0,IntArg1,IntArg2,IntArg3 ){
//TodoAuto-generated method stub
}
Public VoidSurfacecreated (surfaceholder arg0 ){
//TodoAuto-generated method stub
}
Public VoidSurfacedestroyed (surfaceholder arg0 ){
//TodoAuto-generated method stub
}
}
Here we see a new class surfaceholder. We can use it as a surface controller to operate the surface. Because we do not need to directly operate the surface, we will not explain it in detail. The only thing that needs to be used is surfaceholder. addcallback, that is, adding a callback function for surfaceholder. The cause is described as follows:
PublicGameview (context ){
Super(Context );
//TodoAuto-generated constructor stub
Getholder (). addcallback (This);
}
Now we can run it. Like using view for the first time, there is nothing on the interface. Because we haven't written the drawing code yet.
As mentioned above, surfaceview is used to replace view because surfaceview can be used to plot outside the main thread, thus improving the interface response speed. What we need to do is create a thread for drawing. However, before that, we can first learn about the game loop:
We know that the general application is user-driven, that is, user operations, and the program will respond again. In our games, no matter whether users operate or not, there will be some changes. The most obvious thing is that the NPC will move and there will be world events. Therefore, we can say that a game program is called a game loop in an infinite loop. So what should we do in the game loop? Let's use a flowchart to illustrate the game loop process:
This is just a hypothetical process. Different games will certainly change. In addition, there will be more differences in details.
After learning about the game loop, the following job is to create a thread that contains a game loop and update various game data in the loop, based on the data, the game screen is finally displayed to players on the surface.
The method for creating a thread is simple. We do not need to know many advanced features of the thread. You only need to know that you need to reload the run () function to complete specific work in the thread. The thread starts through the START () function. Then the content in the run () function will be executed, and the thread will terminate after the run () function is executed. Therefore, we place the game loop in the run () function. Start the loop through start () and end the loop in an appropriate way to end the entire thread. Note that all operations on the surface must be synchronized, so we will use the synchronized keyword to synchronize surfaceholder.
The code after adding gamethread is as follows:
Public ClassGameviewExtendsSurfaceviewImplementsCallback {
Public Static FinalStringTag= "Gameview ";
// Declare the gamethread class instance
Gamethread;
PublicGameview (context ){
Super(Context );
//TodoAuto-generated constructor stub
// Obtain surfaceholder
Surfaceholder = getholder ();
// Add a callback object
Surfaceholder. addcallback (This);
// Create a gamethread class instance
Gamethread =NewGamethread (surfaceholder );
}
Public VoidSurfacechanged (surfaceholder arg0,IntArg1,IntArg2,IntArg3 ){
//TodoAuto-generated method stub
Log.V(Tag, "Surfacechanged ");
}
Public VoidSurfacecreated (surfaceholder arg0 ){
//TodoAuto-generated method stub
Log.V(Tag, "Surfacecreated ");
// Start gamethread
Gamethread. Start ();
}
Public VoidSurfacedestroyed (surfaceholder arg0 ){
//TodoAuto-generated method stub
Log.V(Tag, "Surfacedestroyed ");
// End gamethread by ending the run () function. For details, see the definition of the gamethread class.
Gamethread. Run =False;
}
/**
* Definition of gamethread
*@ Author Xingye
*
*/
ClassGamethreadExtendsThread {
Surfaceholder;
// Parameters used to control loops in the run () function.
BooleanRun =True;
PublicGamethread (surfaceholder ){
This. Surfaceholder = surfaceholder;
}
@ Override
Public VoidRun (){
//TodoAuto-generated method stub
IntI = 0;
While(Run ){
Log.V(Tag, "Gamethread ");
Canvas c =Null;
Try{
Synchronized(Surfaceholder ){
// We display a counter on the screen and refresh it once every 1 second.
C = surfaceholder. lockcanvas ();
C. drawargb (255,255,255,255 );
C. drawtext ("" + I +++, 100,100,NewPaint ());
Thread.Sleep(1000 );
}
}Catch(Exception e ){
//TodoAuto-generated Catch Block
E. printstacktrace ();
}Finally{
If(C! =Null){
Surfaceholder. unlockcanvasandpost (C );
}
}
}
}
}
}
Run the program to check the effect