Document directory
- Add and screen interaction
So far, we have understood the structure of the game. Even if you simply know that you have received the input, updated the internal status, and then rendered to the screen, it also plays a sound or vibrate.
Let's keep it simple and look at the chart below
In Android, everything happens inside the activity. The activity creates a new view, where the view is where everything happens, like a touch and a final picture. Think of activity as a table, while view is a piece of white paper that allows us to draw things. We use a pencil to draw things. The chemical reactions are all on paper, which produces pictures. It is also suitable for activity and view, as shown in
Let's open droidzactivity. Java and check this line of code.
1 |
setContentView(R.layout.main); |
The activity only assigns R. layout. View to the activity during creation. In our example, the value is assigned at the beginning.
Let's create a new view. A view is a simple class that provides event processing and visible rectangles for us to draw. The simplest thing is to expand the surfaceview of Android, we also need to implement surface. callback to obtain the path of the surface change, for example, when the view is destroyed or the device direction changes
Maingamepanel. Java
01 package net.obviam.droidz; 02 03 import android.content.Context; 04 import android.graphics.Canvas; 05 import android.view.MotionEvent; 06 import android.view.SurfaceHolder; 07 import android.view.SurfaceView; 08 09 public class MainGamePanel extends SurfaceView implements 10 SurfaceHolder.Callback { 11 12 public MainGamePanel(Context context) { 13 super(context); 14 // adding the callback (this) to the surface holder to intercept events 15 getHolder().addCallback(this); 16 // make the GamePanel focusable so it can handle events 17 setFocusable(true); 18 } 19 20 @Override 21 public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { 22 } 23 24 @Override 25 public void surfaceCreated(SurfaceHolder holder) { 26 } 27 28 @Override 29 public void surfaceDestroyed(SurfaceHolder holder) { 30 } 31 32 @Override 33 public boolean onTouchEvent(MotionEvent event) { 34 return super.onTouchEvent(event); 35 } 36 37 @Override 38 protected void onDraw(Canvas canvas) { 39 } 40 }
The above Code only overwrites the methods we are interested in. Except for lines 15 and 17, there is nothing special about others.
1 |
getHolder().addCallback( this ); |
This line of code sets the current class as the handler to be processed for events occurring on the actual surface
The above Code enables the game panel to get the focus, in order to get the event. We added a callback and made the view focus. We will not lose this view.
The method rewritten after 20 rows will be used, but now let them be empty
Let's create a thread, which will be our actual game loop
01 package net.obviam.droidz; 02 03 public class MainThread extends Thread { 04 05 // flag to hold game state 06 private boolean running; 07 public void setRunning(boolean running) { 08 this.running = running; 09 } 10 11 @Override 12 public void run() { 13 while (running) { 14 // update game state 15 // render state to the screen 16 } 17 } 18
You can see that it does not do much, and overwrites the run method. When the running mark is true, an infinite loop is made.
The current process is not instantiated. When the screen is loaded, let's run it.
Let's take a look at the modified maingamepanel class.
01 package net.obviam.droidz; 02 03 import android.content.Context; 04 import android.graphics.Canvas; 05 import android.view.MotionEvent; 06 import android.view.SurfaceHolder; 07 import android.view.SurfaceView; 08 09 public class MainGamePanel extends SurfaceView implements 10 SurfaceHolder.Callback { 11 12 private MainThread thread; 13 14 public MainGamePanel(Context context) { 15 super(context); 16 getHolder().addCallback(this); 17 18 // create the game loop thread 19 thread = new MainThread(); 20 21 setFocusable(true); 22 } 23 24 @Override 25 public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { 26 } 27 28 @Override 29 public void surfaceCreated(SurfaceHolder holder) { 30 thread.setRunning(true); 31 thread.start(); 32 } 33 34 @Override 35 public void surfaceDestroyed(SurfaceHolder holder) { 36 boolean retry = true; 37 while (retry) { 38 try { 39 thread.join(); 40 retry = false; 41 } catch (InterruptedException e) { 42 // try again shutting down the thread 43 } 44 } 45 } 46 47 @Override 48 public boolean onTouchEvent(MotionEvent event) { 49 return super.onTouchEvent(event); 50 } 51 52 @Override 53 protected void onDraw(Canvas canvas) { 54 } 55 }
We added the following code lines:
Row 12 declares that the thread is private.
1 |
private MainThread thread;
|
19 rows. We instantiate this thread.
1 |
thread = new MainThread(); |
InsurfaceCreated
Method We setRunningFlag
TrueAnd we start up the thread (lines 30 and 31). By the time the this method is called the surface is already created and the game loop can be safely started.
Take a look atsurfaceDestroyed
Method.
In the surfacecreated method, we set running to true, and then let the thread start running (lines 30 and 31 ). When the surface is created, the game loop can start running safely.
Let's take a look at the surfacedestroy method.
01 public void surfaceDestroyed(SurfaceHolder holder) { 02 // tell the thread to shut down and wait for it to finish 03 // this is a clean shutdown 04 boolean retry = true; 05 while (retry) { 06 try { 07 thread.join(); 08 retry = false; 09 } catch (InterruptedException e) { 10 // try again shutting down the thread 11 } 12 } 13 }
This method is called before the surface is destroyed. This is not the place where the running mark is set, but the code here ensures that the thread is cleanly closed. We just block the thread and wait for its death.
If we run it on a simulator, we won't be able to see it at all, but we can test it with some logs. Don't worry, I will tell you what is going on later, for more information, see Android site.
Add and screen interaction
We close the program. When we press below the screen, If we click somewhere else, we just record the coordinates.
Add the following lines to the mainthread class:
1 private SurfaceHolder surfaceHolder; 2 private MainGamePanel gamePanel; 3 public MainThread(SurfaceHolder surfaceHolder, MainGamePanel gamePanel) { 4 super(); 5 this.surfaceHolder = surfaceHolder; 6 this.gamePanel = gamePanel; 7 }
We declared the variables gamepanel and surfaceholder, and instantiated them in the constructor.
It is very important for us to own them, not just gamepanel, because we need to lock the surface for drawing, and this operation can only be performed through surfaceholder
Change the method in the constructor
1 |
thread = new MainThread(getHolder(), this ); |
We passed the current holder and panel, so the thread can access them. We will create a new game update function in the game Panel later, and it will be triggered in the thread, but now we keep the status quo
The tag constant is the first parameter of the android log function.
Log note
Open the log view,
Now you should see the logcat view. this is nothing more than a console where you can follow Android's log. it's a great tool as you can filter for logs containing a specific text or logs with a certain tag which is quite useful.
Back to the Code, mainthread. Java is now like this
01 package net.obviam.droidz; 02 03 import android.util.Log; 04 import android.view.SurfaceHolder; 05 06 public class MainThread extends Thread { 07 08 private static final String TAG = MainThread.class.getSimpleName(); 09 10 private SurfaceHolder surfaceHolder; 11 private MainGamePanel gamePanel; 12 private boolean running; 13 public void setRunning(boolean running) { 14 this.running = running; 15 } 16 17 public MainThread(SurfaceHolder surfaceHolder, MainGamePanel gamePanel) { 18 super(); 19 this.surfaceHolder = surfaceHolder; 20 this.gamePanel = gamePanel; 21 } 22 23 @Override 24 public void run() { 25 long tickCount = 0L; 26 Log.d(TAG, "Starting game loop"); 27 while (running) { 28 tickCount++; 29 // update game state 30 // render state to the screen 31 } 32 Log.d(TAG, "Game loop executed " + tickCount + " times"); 33 } 34 }
In line 8, we define the log tag
In the run function, we define tickcount. When the game loop is executed, it will add 1
Let's go back to the maingamepanel. Java class. Let's modify ontouchevent to process the touch message.
01 public boolean onTouchEvent(MotionEvent event) { 02 if (event.getAction() == MotionEvent.ACTION_DOWN) { 03 if (event.getY() > getHeight() - 50) { 04 thread.setRunning(false); 05 ((Activity)getContext()).finish(); 06 } else { 07 Log.d(TAG, "Coords: x=" + event.getX() + ",y=" + event.getY()); 08 } 09 } 10 return super.onTouchEvent(event); 11 }
Also, droidzactivity is modified.
01 package net.obviam.droidz; 02 03 import android.app.Activity; 04 import android.os.Bundle; 05 import android.util.Log; 06 import android.view.Window; 07 import android.view.WindowManager; 08 09 public class DroidzActivity extends Activity { 10 /** Called when the activity is first created. */ 11 12 private static final String TAG = DroidzActivity.class.getSimpleName(); 13 14 @Override 15 public void onCreate(Bundle savedInstanceState) { 16 super.onCreate(savedInstanceState); 17 // requesting to turn the title OFF 18 requestWindowFeature(Window.FEATURE_NO_TITLE); 19 // making it full screen 20 getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); 21 // set our MainGamePanel as the View 22 setContentView(new MainGamePanel(this)); 23 Log.d(TAG, "View added"); 24 } 25 26 @Override 27 protected void onDestroy() { 28 Log.d(TAG, "Destroying..."); 29 super.onDestroy(); 30 } 31 32 @Override 33 protected void onStop() { 34 Log.d(TAG, "Stopping..."); 35 super.onStop(); 36 } 37 }
Run the program, click a few times in the upper part of the program, and then click the lower part. The program should exit.
Logcat
Current Tasks
1. Created a full screen program.
2. There is an independent thread control program
3 parse basic gestures, such as touch gestures
4. Close the program elegantly
You can download the code here.