This chapter describes how to add actions to a game.
In general, there are many Java examples.ProgramLike to directlyCodeAdd:
Button. addactionlistener (New actionlistener () {public void upload maction (event e ){}});
Such code. This is not good, because it does not conform to the single responsibility principle. The actionlistener should be independent and separate into classes. In this way, it is easy to find when a problem occurs. There are two forms: one is the form of separate classes used in this article, and the other is to declare internal classes in the corresponding object. For example:
Class mybutton. actionlistener {}.
In general, we will add:
Startactionlistener, clearactionlistener, exitactionlistener, and ballactionlistener classes are bound to objects. Next, refine each action. During this period, we found that the jlabel of the small ball cannot be added to the actionlistener, So we changed it to a jbutton. This is very common in coding, that is, the design cannot be perfect during detailed design, problems can only be detected during encoding. This is also why we advocate that detailed design is not required. For details, refer to the waste in the software development process-Detailed Design
The process of binding and joining is omitted.
The first one is start. Start the game when you click Start. And the start button changes to restart, which indicates that the current Bureau is restarted.
The actions after start are as follows:
Generate a random ball game. getinstance (). Shuffle ();
Layout to game. getinstance (). gamepad. Main. Render ();
Clear the current score game. getinstance (). Score. Current = 0;
Game. getinstance (). Score. Selected = 0;
Refresh the score to display game. getinstance (). gamepad. helper. Render ();
Change the text of the Start button to restart game. getinstance (). gamepad. Control. Start. settext ("restart ");
According to the above Code, the following compilation problems will occur:
1. game does not contain the gamepad object.
2. Many variables are not public and cannot be accessed.
3. The render method is not declared in mainframe and helperframe.
4. The shuffle () method is not declared.
Indeed.Self-expressing code claims to first write the required operations in self-expressing mode, and then implement these operationsInstead of implementing some operations and then calling them.
In addition, the Code extracts game. getinstance () as a local variable.
However, we found that listener tries to update both the model layer and the view layer, and increases the code access permission. This is not a good method. Although the entire code can be implemented by following this method, the written method will combine the originally opened MVC structure. Therefore, in order to maintain separation, we do not adopt the above method, but introduce the message mechanism to send the message update UI when data is updated. When talking about this message mechanism, we should also mention that we should not abuse the message mechanism. message transmission is used for everything, because although the message mechanism can decouple code, it also reduces readability and comprehension.
So here, let's talk about it first. The message mechanism is only used for UI update.
Distribution explanation,
The code for startactionlistener is as follows:
1 Package Org. Stephen. bubblebreaker. listener; 2 3 Import Java. AWT. event. actionevent; 4 Import Java. AWT. event. actionlistener; 5 6 Import Org. Stephen. bubblebreaker. Control. eventdispatcher; 7 Import Org. Stephen. bubblebreaker. model. event; 8 Import Org. Stephen. bubblebreaker. model. game; 9 10 Public Class Startactionlistener Implements Actionlistener { 11 12 @ Override 13 Public Void Actionreceivmed (actionevent e ){ 14 Game = Game. getinstance (); 15 Game. Shuffle (); 16 Game. Score. clearcurrentscore (); 17 Game. State = Game. state. Playing; 18 19 Eventdispatcher. Send (event. update_bils ); 20 Eventdispatcher. Send (event. update_scores ); 21 Eventdispatcher. Send (event. update_buttons ); 22 } 23 }
Game. Shuffle () indicates that a random ball is generated.
The Code is as follows:
1 Public Void Shuffle (){ 2 For ( Int Y = 0; y <12; y ++ ){ 3 For ( Int X = 0; x <12; X ++ ){ 4 Grid. bils [y] [x] = New Ball (); 5 Grid. bils [y] [X]. Color = ball. color. Values ()[( Int ) (Math 6 . Random ()* Ball. color. Values (). Length)]; 7 Grid. bils [y] [X]. x = X; 8 Grid. bils [y] [X]. Y = Y; 9 Grid. bils [y] [X]. State = Ball. state. normal; 10 } 11 } 12 }
However, ball. color changes are involved. Because the range of ball color values is limited, the color is changed to the custom internal enumeration color.
This enumeration is defined:
1 Public EnumColor {2 Red, green, blue, yellow, purple;3PublicImageicon getimageicon (){4Return NewImageicon ("image/" + name (). tolowercase () + ". PNG");5 }6}
It can be seen that the selected value range is red, green, blue, yellow, and purple, and each color is matched with an image. When you rearrange the image, you can obtain the relevant image by name and display it.
Then there is clearcurrentscore () of the score ();
1 Public VoidClearcurrentscore (){2Selected = 0;3Current = 0;4}
Then, game. State, which is an intermediate variable used to notify button changes, will also take effect at the end of the game.
1 Public EnumState {2 Stand_by, playing, game_over;3}
Followed by event and eventdispatcher
1 Package Org. Stephen. bubblebreaker. model; 2 3 Public Class Event { 4 Public Static Final Int Update_bils = 0x1000 ; 5 Public Static Final Int Update_scores = 0x1001 ; 6 Public Static Final Int Update_buttons = 0x1002 ; 7 }
1 Package Org. Stephen. bubblebreaker. Control; 2 3 Import Org. Stephen. bubblebreaker. model. event; 4 Import Org. Stephen. bubblebreaker. model. game; 5 Import Org. Stephen. bubblebreaker. View. gamepad; 6 7 Public Class Eventdispatcher { 8 9 Public Static Void Send ( Int Event ){ 10 Gamepad = Game. getinstance (). gamepad; 11 Switch (Event ){ 12 Case Event. update_bils: 13 Gamepad. Main. Render (); 14 Break ; 15 Case Event. update_scores: 16 Gamepad. helper. Render (); 17 Break ; 18 Case Event. update_buttons: 19 Gamepad. Control. Render (); 20 Break ; 21 } 22 } 23 }
Then start running, debugging, and find that there are still many bugs. First, the button boundary displayed at the start is not required and relevant code is deleted.
Then, the variables should be initialized during game initialization.
1PrivateGame (){2Grid =NewGrid ();3Score =NewScore ();4State =State. stand_by;5}
Game. gamepad should be assigned a value during gamepad initialization.
1PublicGamepad (){2Game. getinstance (). gamepad =This;3}
The variable declaration in grid should also be initialized.
1 PackageOrg. Stephen. bubblebreaker. model;2 3 Public ClassGrid {4 5PublicBall [] [] bballs =NewBall [12] [12];6}
Then the implementation of each render
Mainframe. Render ()
1 Public Void Render (){ 2 Ball [] [] bballs = Game. getinstance (). Grid. bils; 3 For ( Int Y = 0; y <12; y ++ ){ 4 For ( Int X = 0; x <12; X ++ ){ 5 This . Bils [y] [X]. seticon (bils [y] [X]. color. getimageicon ()); 6 This . Bils [y] [X]. invalidate (); 7 } 8 } 9 }
Helperframe. Render ()
1 Public Void Render (){ 2 Score = Game. getinstance (). Score; 3 Current. settext (string. valueof (score. Current )); 4 Selected. settext (string. valueof (score. Selected )); 5 Highest. settext (string. valueof (score. Highest )); 6 Average. settext (string. valueof (score. Average )); 7 Playcount. settext (string. valueof (score. playcount )); 8 }
At the same time, we found that the selected value in the old Code is not correctly assigned and modified together.
Controlframe. Render ()
1Public VoidRender (){2Game. State state =Game. getinstance (). State;3If(State =Game. state. Playing ){4Start. settext ("restart");5}Else{6Start. settext ("START");7 }8}
Then debug and correct the error.
Click Start on the following page:
In the next chapter, we will explain the implementation of ballactionlistener.