Going out of the J2ME game development labyrinth - J2ME game development framework and implementation

xiaoxiao2021-03-06  13

Going out of the J2ME game development maze - J2ME game development framework and implementation

Today's mobile phone's power has far exceeded the category of "service in human communications and communication". When the mobile phone operating system begins to provide increasingly powerful platform features, various mobile apps should have begun to enrich people's lives. In the face of the five-flowers of mobile phone application development platform, as a developer of mobile app, of course, I hope that the application you provide can run in a variety of mobile phones. Very fortunate, J2ME makes this possible possible. From MIDP1.0 to MIDP2.0, J2ME platform has provided a convenient API for mobile applications, and only API is not enough to form a perfect application, how to design application frameworks and implement the perfect application's soul and power.

This article will show how to design a game framework with an application of a maze game, and achieve graphical operation, artificial interaction, and the most simple artificial intelligence on this framework. The game framework will be based on MIDP 1.0, as a former version of MIDP2.0, MIDP 1.0 provides a more limited API (MIDP2.0 provides a GAME API), and it has excellent compatibility on different phones. Sex, depending on the nature of the article, MIDP1.0 will be more beneficial to readers, and this paper assumes that readers have basic understanding of MIDP1.0. If there is no relevant knowledge, they can find relevant support in the article.

Game frame

As a game's development designer, or as a gaming company designer, it will not design a development framework for each game project, which is too high, usually, is for a type of game (such as RPG, ACT, etc.), or a few types of games offer a unified development framework, and developers can only choose the corresponding development framework (may need to be changed slightly), they can be skilled after the developer takes over to a new game design. The development implementation of the game is performed based on the framework, and some old code can be reused. So, let us think about a maze game with a designer's angle, how to design.

First of all, for a maze game, we can list the following basic needs:

1) The game needs to have an initial introductory interface;

2) The game needs to be able to randomly generate maze;

3) The game needs to have different difficulty levels;

4) The game needs can be involved in players;

5) The player can choose a robot in the game.

What else? Yes, if there are more than these needs, then this game should have a gaming menu, which is the sixth basic needs. Also ... Yes, there will be a lot, but let us temporarily hit, remember? Our game company has just been established, our first task is to design a game development framework, which is too fine at this time.

With the above demand list, we have begun to consider which part of the game consists, in other words, what stage, we learn from the player's perspective, of course, the designer needs to consider more factors, after discussion, We have drawn the following stages.

1) Initial phase of the game: For the player, it is an initial interface. For designers, the initialization of many game data will be completed here;

2) The game setting phase: For the player, it is the menu selection interface. For designers, the settings that will be made here will affect the performance of the game entity.

3) The game running phase: This is a paradise or hell for the player. For designers, it is necessary to perform carefully designed coding according to the game content, type, plot, etc.

3) The game ending stage: For the player, it is a game telling yourself whether Winner or LOSER. For designers, you need to summarize the game and players, and may also need to explain or thank.

These stages are very specific for players, and for the designer, every part is enough, if there is no game frame, the above four phases are likely to be merged, or it may be split, so that each new game Development projects have become a new long protester. Therefore, we will perform our game frame design in these four phases. So, we finally started to come into contact with MIDP1.0.

Each J2ME application must have a class inheritance implementation javax.microedition.midlet.mIdlet This abstraction class, which can also be operated by the application management software to perform lifecycle management. Although the status of this class is very important, it is not part of our game frame. Yes, each game project can generate this class according to its own special needs, such as a unique name, unique start-up behavior, unique exit behavior, and more. After all, the core of the game is not here. So is the core of the game? For J2ME, we can think that javax.microedition.lcdui.canvas is best suited for this heavy, game graphics and text performance, and the player's interactive response can be taken by this class, and there are also many J2ME mobile game companies. Sub-category implementation to complete all our four phases mentioned above. But direct consequences are all code in a class file, not easy to encode, implement, and manage, require strong process language to write capacity, basically abandon the object-oriented characteristics of Java languages. Especially for beginners, it is not easy to learn and maintain.

These disadvantages mentioned above are also the advantages of our learning in the development of game development. In all mobile devices, the available resources are always limited. Taking the NOKIA's S40 series equipment as an example, the application can use memory to 210kb, and the release JAR file for each J2ME application cannot be greater than 64KB, the CPU speed is far Do not have a desktop PC, these restrictions determine the J2ME application we have completed in order to achieve as powerful functions:

1) Keep the number of categories in J2ME applications as small as possible;

2) Use process methods as much as possible;

3) If possible, reuse objects that can reassign the value.

However, the game frames mentioned herein are not prepared in extreme way, so there is four phases we have previously discussed earlier, and they segment the entire game process, decreased The complexity of management implementation is simultaneous as much as possible as possible in the stage. In our framework, these four phases can be available according to the needs of the application, and they all represent the four parts of relatively independent process. From the following Figure 1 we can finally see this complete and simple game framework.

Figure 1: Game framework and maze game implementation class diagram

It should be noted that only two classes in this class are elements that make up the game frame, com.savorjava.game.Action and com.savorjava.game.corecanvas. Other classes are to realize maze games, thereby based on the necessary ingredients of the frame. Is it that the composition of the frame is too simple? For the design of the PC application, it is incredible for the framework of two classes, but for mobile J2ME applications, it is not yet. This frame does not include MIDlets, so we can call it half-production framework, in this framework, we only care about two work: the work of each different stage and if the schedule is switched. For the J2ME mobile app development of restricted resources, this is the function we can accept and the resource consumption allowed. com.savorjava.game.Action As an abstract class, declaring two interfaces: Runnable and CommandListener, and provide two main behavior methods:

Public Void Perform (Graphics G) operates the incoming Graphics object, is the main process body, pockery application operation, and results to draw public void interrupt (int key) respond to the button activity received by Canvas. And change the application operation

By both methods and two interfaces that require implementation we can see a certain stage in the game, that is, the processing of a certain process is processed by the action, and the processing of the processing includes graphic text performance and the player's interactive response. At this point, everyone can know that in the maze game we are about to design, there will be only four anctions implement subclasses, corresponding to the four phases of our above.

At the same time, com.savorjava.game.Action also provides two class variables:

Protected Corecanvas Canvas = NULL; All Action's subclasses need to hold a reference boilean acting = true; Acting determines whether the action should continue to run, generally decide whether to end the thread in the RUN method of the thread

Next, let's take a look at Com.Savorjava.game.corecanvas, which is a subclass of javax.microedition.lcdui.canvas, in our game frame, it is not responsible for graphic text performance and the core of the player's interaction response, Instead, it is responsible for dispatching the Action subclass of the four phases (if present). In other words, Corecanvas decides that only one stage of action is running at a certain moment, which determines the schedule of the Action by passing information between the action. Therefore, Corecanvas itself also declares that the Runnable interface is implemented, and its operation will run through the life cycle of the entire game. The following is a thread part code in Corecanvas:

/ ** * core allocation: switch actions according to game status while status is changed * / public void run () {while (true) {if (statusChanged) {switch (gameStatus) {case GS_INITIAL:.! {If (initialAction = NULL) {statuschanged = false; currentaction = INIALAlation; initialthread.start ();} else {gameestatus = GS_Start;} Break;} case gs_start: {if (StartAction! = Null) {statuschanged = false; currentaction = startaction; startthread.start ();} else {gameestatus = GS_RUN;

} Break;} case GS_RUN: {if (! RunAction = null) {statusChanged = false; currentAction = runAction; runThread.start ();} else {gameStatus = GS_END;} break;} case GS_END: ​​{if (runAction =! NULL) { Statuschanged = false; currentaction = endaction; endthread.start ();} Break;}}} Try {thread.sleep (SleepTime);} catch (interruptedException IE) {}}}

This code is based on all scheduling mechanisms, simply and effective. In the Run thread method, we can see that the thread will not end automatically, in its infinite loop, complete the following: 1) If the StatusChanged flag is changed to see if the game is changed, if there is a change, it processes 2 Otherwise, processing 5;

2) What an Action in the four phases should be activated according to GameStatus, if the action exists, otherwise processing 4;

3) Set StatusChanged to false and set the action to the current Action and start its thread;

4) Automatically go to the next stage Action process, so that the GameStatus is set to the next state.

5) Scheduling threads go to the designated time.

Corecanvas provides the following callback methods in order to be able to communicate with the registered ACTION:

public void setGameStatus (int gameStatus) {// stop current action currentAction.setActing (false); this.gameStatus = gameStatus; // time to garbage collect System.gc (); // notice core allcation cavas:.. status have been Changed. statuschanged = true;}

When an Action considers the work of its own phase, it is necessary to call this method to inform Corecanvas to perform the next scheduling work. In order to do this, Corecanvas performs the following processing in this method:

1) Set the acting of the current action to false, notify the relevant thread to terminate;

2) Switch GameStatus to the new stage value required by the Action;

3) Garbage collection, release the memory occupied by the action of the action;

4) Notify the scheduled thread needs to schedule work.

It is important to emphasize here that in J2ME applications are very important in time and when garbage recovery, the basic principle is to recover as soon as possible but do not choose to cause too much loss to the user response.

Game maze

At this point, we have basically understood the composition and operation of this game frame, then the rest of the job is how to achieve all phases of the game. According to Figure 1, we know that in this upcoming maze game, there is only three phases of action, which is the mazeinitialArtAction, and mazerunAction. Yes, the flexibility of the frame allows us to implement several stages in the four phases, and even do not implement an action of any stage, of course, this is meaningless.

According to the needs of the maze and the frame design, we now need to complete the design and implementation of the three anctions. What kind of order and way to carry out the work of these three Actions depends on the structure of the team, human hand, may also involve personal interests. I personally think that the core of the game, that is, the design of the MazerunAction phase is the most important because in the design implementation of this phase may produce dependence and influence on other phases. And our virtual company's human hand is really too small, and it should be a top base for the labyrinth. According to the second point in the demand: the game needs to be randomly generated by the maze. Then let's take a good study of the maze generation algorithm. For a two-dimensional quadruple labyrinth, its essence is composed of n * m's quadruple rooms. Each two adjacent small rooms are separated by walls, as shown in Figure 2 is a 5 * 5 initial maze, and there is no passage between all rooms and is completely separated by the wall.

Figure 2: Initial maze

How to ensure a randomly different real maze in this initial maze every time? Here, we give the labyrinth a relatively complete definition: the maze consists of a set of rooms, there is only one path between any two rooms. Is this a little familiar? Yes, the depth of the minimal bonus is priority (width priority, but the generated labyrinth is not ideal) algorithm can generate a real maze to such an initial maze, of course, in order to achieve random production, we need to use random number. The following is the steps required to complete this algorithm:

1) Find a starting room in the initial labyrinth;

2) Find a room that has not been accessed in the neighborhood of this housing;

3) If you are found, you will move into the new room and push down the wall between the two rooms; if you don't find it, return it to the previous room;

4) Repeat 2 and 3 until all rooms are accessed.

It looks very simple, isn't it? When all the rooms have been accessed, our maze also generates, and there is only one path between each two rooms. Thus, there is two methods in MazerunAction:

/ ** * Initial all rooms in the maze accounting to size of maze, * Walls and borders Will be up which present by 1. * / private void initialrooms () {int xsize = canvas.getwidth (); int = canvas. GetHeight (); short minsize = (us); maxGrid = (short); roys = new int [grid] [Grid]; // initial All the rooms: no visited and all the wall up. for (int i = 0; i

Param x * @Param Y * @return * / private int [] getrandomneighbor (int x, int x, int y) {int direction = random.nextINT ()% 4; if (Direction <0) {Direction = -direction;} int [] neighbor = null; for (int i = 0; i <4; i ) {switch (Direction) {case 0: // EAST {IF ((x 1

(Rooms [x] [y] & 0x0020) == 0) {neighbor = new int [2]; neighbor [0] = x; neighbor [1] = y 1; rooms [x] [y] & = ~ South; rooms [x] [y 1] & = ~ north;} Break;} case 2: // west {= (x - 1> = 0) && (Rooms [x - 1] [y] & 0x1000 ) == 0 && (Rooms [x] [y] & 0x0040) == 0) {neighbor = new int [2]; neighbor [0] = x - 1 Neighbor [1] = Y; Rooms [x] [y] & = ~ west; rooms [x - 1] [y] & = ~ East;} Break;} case 3: // north {= f ((y - 1> = 0) && (Rooms [x] [Y - 1] & 0x1000) == 0 &

& (Rooms [x] [y] & 0x0080) == 0) {neighbor = new int [2]; neighbor [0] = x; neighbor [1] = y - 1; rooms [x] [y] & = ~ North; rooms [x] [y - 1] & = ~ South;} Break;}} f (neighbor! = Null) {Break;} if ( Direction> = 4) {Direction = 0;}} Return Neighbor;} INITIALROOMS method is used to generate an initial maze according to the specified size, while Getrandomneighbor It is based on the specified room to get the next correlation and unused room. These two methods are mainly dealing with integers related to the information about the room. Here, we use an integer to represent a room, rather than using a new object class to describe the room, the reason has been mentioned earlier: Decrease the number of classes as much as possible; reduce memory consumption as much as possible. If you want your N * N maze n to be as big as possible, the integer and bit operation is your best choice. In the Java language, an integer consists of 32 bits, and we need to define what meanings represents this 32 bits.

Location description 0 ~ 3 bits represent the wall of the four directions of the room, South, west, north, 0 indicates that the wall does not exist, 1 means that there are 4 to 7 digits represent the room East, South, West, North Whether the walls in the four directions are located on the edge of the labyrinth, the outer walls of these edges are not pushing, we don't want the waters of the labyrinth around the walls 8 ~ 11 record players in East, South, West, North, North After 12 to 15 digits of this room, 12 of the players visited whether the room was visited. 13 said that the robot visited the room, the other two reserved, in fact, 12 and 13 in the process of 12 and 13 have not needed 16 ~ 19 The bit is the same as 8 ~ 11, but the record is that the path of the robot is 20 ~ 31 for the future extension. After the above-mentioned sense of the above, how we need to complete how to respond to the player's operation, let the player's representative The image is correct in the maze instead of wearing a wall. I believe you still remember the Interrupt method in the action, Corecanvas no longer processes the button events received by themselves, but simply sends it to the current Action deal. Therefore, in MazerunAction, we need to handle these buttons, and the content is nothing more than modifying the integer values ​​of the relevant room. The processing threads of MazerunAction will continue to operate the Canvas to draw graphics.

The robot's action is basically no need to process the incident, which is the most simple artificial intelligence to handle the labyrinth of the MazerunAction. The principle is also very simple: starting from the starting point, according to the order of the four directions in East, South, West, and North, finding the way, finding forward, all the four directions can not be found or have been to the previous one room. The labyrinth graphics are also operated by the MazerunAction processing thread.

In order to facilitate management and control, you can divide the sub-stage in this action, and use different status to identify, we are doing this, in the following code, the robot is displayed in different states, thereby Everyone can understand that the handling code of the player is also similar.

Private vid robotrun () {// Robot Stop Running While Arrived Terminal Point. if (Robot [0] == Grid - 1 && Robot [1] == Grid - 1) {RUNINGFLAG = false; robotmemory.removeAllelements (); system .gc (); return;} // go to easy neighbor if Possible. IF ((Rooms [Robot [0]] [Robot [1]] & East) == 0 && Robot [2] == East && Robot [ 3]! = EAST) {// change room information. Rooms [Robot [0]] [Robot [1]] | = 0x10000; Rooms [Robot [0] 1] [Robot [1]] | = 0x40000; / / record path Which Robot Walk Through. RobotMemory.push (New Short [] {Robot [0], Robot [1], Robot [2], Robot [3]}); // Record Room W Hich Need Be Re-Drawn RoomsneedDraw.push (new int in); robot [0] ; robot [2] = East; robot [3] = West;} else IF ((ROOMS [Robot [0]] [Robot [1]] & South) == 0 && Robot [2] == South && Robot [3]! = South) {Rooms [Robot [0]] [Robot [ 1]]] | = 0x20000; Rooms [Robot [0]] [Robot [1] 1] | = 0x80000;

RobotMemory.push (new short [] {robot [0], robot [1], robot [2], robot [3]}); roomsneeddraw.push (new int in {{robot [0], robot [1]} ); Robot [1] ; robot [2] = East; robot [3] = north;} else} ((Rooms [Robot [0]] [Robot [1]] & west) == 0 && robot [ 2] == West && Robot [3]! = West) {Rooms [Robot [0]] [Robot [1]] | = 0x40000; Rooms [Robot [0] - 1] [Robot [1]] | = 0x10000 RobotMemory.push (new short [] {robot [0], robot [1], robot [2], robot [3]}); roomsneeddraw.push (new int]) (new int]) }); Robot [0] -; robot [2] = East; Robot [3] = East;} else} else} ((Rooms [Robot [0]] [Robot [1]] & north) == 0 && robot [2] == North && Robot [3]! = north) {Rooms [Robot [0]] [Robot [1]] | = 0x80000; Rooms [Robot [0]] [Robot [1] - 1] | = 0x20000; RobotMemory.push (New Short [] {Robot [0], Robot [1], Robot [2], Robot [3]}; roomsneeddraw.push (new int in in {robot [0], robot [1]}; robot [1 ] -; robot [2] = East; robot [3] = South;

} else {// go to next direction if current direction is available; // go back to last room if no direction is available in this room. Robot [2] << = 1; while (robot [2]> north) { // Clean Current Room's Solution By Robot. Rooms [Robot [0]] [Robot [1]] & = ~ 0xF0000; roomsneedDraw.push (new int]) (new int]) {robot [0], robot [1]}); // Get Last Room Location of Robot and Clean The Solution with Current Room. Robot = (Short []) RobotMemory.pop (); if ((((((Robot [2] & East) == East) {Rooms [Robot [0]] [ Robot [1]] & = ~ 0x10000;} else IF ((Robot [2] & South) == South) { Rooms [Robot [0]] [Robot [1]] & = ~ 0x20000;} else if ((Robot [2] & West) == West) {Rooms [Robot [0]] [Robot [1]] & = ~ 0x40000;} else if ((Robot [2] & north) == north) {Rooms [Robot [0]] [Robot [1]] & = ~ 0x80000;} Robot [2] << = 1;} }

What is needed in the above code is the content of the one-dimensional array of Robot, which has four elements, respectively, respectively: 1) The X coordinate of the robot's current room;

2) The y coordinate of the robot's current room;

3) The robot will leave from the direction of the room;

4) Which direction from the robot enters the room of the coordinate.

With the above algorithm foundation, we can get the following rendering:

Figure 3: Different levels of maze renderings

After completing the design and implementation of MazerunAction, the design and implementation of the initial phase and the setting phase are needed. In the maze game, the content of these two phases is very simple, and it is also very representative, limited to the limited space, here Briefly illustrate it.

In the initial stage, you need to complete MazeInitialAlament, which is simply loaded into a PNG picture. After three seconds, it will end automatically, and notify Corecanvas to switch the game status to START and enter the setup phase. It is important to be important in the initial stage, or is very important for the entire game, it is the art. The packaging is not universal, but there is no packaging is not possible. The following is the two covers that I have drawn when I designated this game. Which one will make the game more attractive is self-evident.

Figure 4: Game cover design

For the setting phase, you need to complete the MazeStartAction, which provides a gaming menu to the user, allowing users to do game-related settings, and we mainly provide the following menu options:

1) Human: Single game, robot will not be activated;

2) human vs robot: fighting against the robot;

3) Config: Control the level of the game, Easy, Normal, and Impossible correspond to the three levels of Figure 3;

4) Help: Information about game operations and designers;

5) EXIT: Exit the game.

The following is a game startup, setting effect diagram.

Figure 5: Game start settings renderings

More, we introduce the frame design based on MIDP1.0, and the main content of a maze game is implemented based on this framework. Since this article is not a MIDP 1.0 API gate document, it is a certain Java practice. And the MIDP 1.0 API has a preliminary developer, thus a lot of problems that need to be paying attention to using the API development process, as well as some common techniques, such as dual buffering technologies drawn. But as compensation, I will list some useful resources at the top of the article for your reference. At the same time, the labyrinth game developed in this article is Savormaze, which has passed on a variety of models such as Nokia, Siemens, Sony Ericsson, etc., which is completed by Savorjava, as an open source code, Savorjava has applied for open source to SourceForge Project, therefore, all source code and runable mobile phone release are available on SourceForge or article published website, there should be some J2ME developers to learn from the part, we cannot list all source code here. , Please understand, please check the last reference information for details.

Reference Information

1. All Source Codes in this article Savormaze on SourceForge can run JAR files and JAD files as follows: (See attachments: savormaze.jar, savormaze.jad); 2. At http://forum.nokia. Com.cn can find a lot of information about J2ME development;

转载请注明原文地址:https://www.9cbs.com/read-47917.html

New Post(0)