Yellow Cube - Developer Guide
- yellowcube.zip (4.23MB)
Introduction
Yellow Cube is an Open GL ES-based 3D puzzle game that was developed by applying Plasma (in-app purchasing), Zirconia (license management), and AdHub (Samsung Ads), which are all included in the Samsung library. If you plan to develop applications using the Samsung library, Yellow Cube is a good example.
Yellow Cube can be downloaded and tested for free from Samsung Apps. The download URL may vary by country. We recommend going to www.samsungapps.com and searching for “YellowCube” to download the app.
How to Play
Yellow Cube is a memory game where you must remember the order in which the 16 cubes move and recreate that order. Refer to Figure A for how the game is played.
image 1 and 2 with capation
Figure A. How to play
Application Architecture
Yellow Cube was created using OpenGL ES 1.0/1.1 and Samsung libraries (in-app purchasing, license management, in-app ads) on the Android platform. Other open source or public libraries were not used. Therefore, this game provides a simple example for developers who wish to develop games using Yellow Cube as a reference.
Figure B. Application Architecture
State Transition Diagram
Yellow Cube is an FSM (Finite State Machine), and is created by defining 24 states with the game being played by switching between these states.
As shown in the above processes, each of the 24 states is defined by the enum strings within the Game.java file.
private enum E_GAME_STATE {
GS_100_OPENING_START,
GS_101_OPENING,
GS_102_OPENING_FINISH,
GS_110_DONATION_START, // when user c
GS_111_DONATION,
GS_112_DONATION_FINISH,
GS_220_GAME_PREPARING_START, // locate 4x4 cubes on the screen
GS_221_GAME_PREPARING,
GS_222_GAME_PREPARING_FINISH,
GS_230_GAME_DEMONSTRATION_START, // shows what user must push
GS_231_GAME_DEMONSTRATION,
GS_232_GAME_DEMONSTRATION_FINISH,
GS_240_GAME_USERPLAYING_START, // now user’s turn
GS_241_GAME_USERPLAYING,
GS_250_RESULT_SUCCESS_START,
GS_251_RESULT_SUCCESS,
GS_252_RESULT_SUCCESS_FINISH,
GS_260_RESULT_FAILURE_START,
GS_261_RESULT_FAILURE,
GS_262_RESULT_FAILURE_FINISH,
GS_300_QUIT, // the only case for quit is ‘license invalid’
GS_400_RESULT_HIGHSCORE_START, // high score with replay and donation button
GS_401_RESULT_HIGHSCORE,
GS_402_RESULT_HIGHSCORE_FINISH
};
Class Diagram
Figure C. Class diagram
Among the classes that make up the game, the Game class serves as the main loop for the game while creating other Game object class instances and requesting updates and draw methods.Furthermore, decoupling between classes is important. Each class is designed to function independently, with the exception of the Game class.
Source Code
Game Class
The Game class plays a central role in the game. It creates and requests instances of all other classes and makes the game playable. The constructor creates the required number of object instances in the game, such as Cube, Skybox and Spark, and initializes related values.
public Game(Context context) { super(context); this.context = context; int i; // Create Cube Instance cubes = new Cube[NUM_OF_CUBES]; for (i=0; i<NUM_OF_CUBES; i++) { cubes[i] = new Cube(i); } // Create skybox. it’s the biggest cube rotating in the background skybox = new Skybox(); //Final stage number is 16 mDemoWay = new int[16]; mDemoRingEffectDone = new int[16]; mCurStage = 4; // starts from stage 4 (it means, there are 4 cubes to rember the order) sparks = new Spark[NUM_OF_SPARKS]; for (i=0; i<NUM_OF_SPARKS; i++) { sparks[i] = new Spark(); } mCurSparkNum = 0; stars = new Star[NUM_OF_STARS]; for (i=0; i<NUM_OF_STARS; i++) { stars[i] = new Star(); } mCurStarNum = 0;Because the Game class serves as the main loop, onDrawFrame is requested in every loop. Then, the updateFrame and drawFrame methods of each object are requested sequentially within onDrawFrame, and updates and renderings take place in every frame.
public void onDrawFrame(GL10 gl) { if (!bGamePaused) { // go on if game is not paused int i; // loop counter /* * update all the game objects in every frame */ UpdateGameState(); gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT); /* * Draw Stars (behind the skycube) */ for (i=0; i<NUM_OF_STARS; i++) { stars[i].updateFrame(gl); stars[i].drawFrame(gl); } /* * Draw Skycube */ //gl.glTranslatef(0.0f, 0.0f, -10.0f); skybox.updateFrame(gl); skybox.drawFrame(gl); /* * Draw Cubes */ for (i=0; i<NUM_OF_CUBES; i++) { cubes[i].updateFrame(gl); cubes[i].drawFrame(gl); }The UpdateGameState method below is also run in every loop to update the state of the objects according to the progress of the game.
public void UpdateGameState() { switch (mGameState) { case GS_100_OPENING_START: onGameState_100_OpeningStart(); break; case GS_101_OPENING: onGameState_101_Opening(); break; case GS_102_OPENING_FINISH: onGameState_102_OpeningFinish(); break; case GS_110_DONATION_START: onGameState_110_DonationStart(); break; case GS_111_DONATION: onGameState_111_Donation(); break; case GS_112_DONATION_FINISH: onGameState_112_DonationFinish(); break; }The basic structure of the Game class was created using the skeleton code of an OpenGL ES sample from the Android developer website. Refer to the following link for more details.http://developer.android.com/guide/topics/graphics/opengl.html
Cube Class
The Cube class is for the 16 cubes used to play the game. 16 instances are created within the Game class and each created instance works independently from other Cube instances with its own 3D position coordinates and rotation coordinates, 3D modeling data and state.
Figure 2. 16 Cube instances are created.
The Cube instances are controlled by the Game class, which serves as the manager. Internally, it operates with a 10-state FSM structure, just like the Game class.
public enum E_ANIM_TYPE { // this enum will be used in Game class also AT_000_DEAD, AT_100_FLOATING, AT_101_FLOATING_SELECTED, AT_200_POPUP, // for pushed cube (that is, user already select one cube) AT_300_APPEARING, // for stage opening time only AT_400_DEMO, // for demonstration time only AT_500_DEMOWAIT, // for demonstration time only AT_600_FIREWORKS, // stage clear animation AT_700_COLLAPSED, // stage fail animation AT_800_HINT, // when hint is shown }Spark Class
The Spark class is expressed as flame-shaped particle effects throughout the game, and they are used in the scenes described below.
Used for the burning effect from behind the Big Cube in the Opening Screen.
Used as particle effects that appears with the cubes when a stage starts.
Used as particle effects along the finger trail.
Used as blowing particle effects when the player presses the cubes in the correct order.The Spark particle effect has either Normal, Rising or Radial property to be used according to the four scenes listed above. Each effect disappears after being shown for its lifetime value, which is defined in the mFrameMax variable. When the effect disappears, it means that the Spark instance is dead.
Figure 3. 3 types of particle animations
Animations of the Spark class are defined by enum strings.
public enum E_PATTERN_TYPE { // spark pattern PT_000_DEAD, PT_100_NORMAL, PT_200_RISING, // for stage clear fireworks PT_300_RADIAL, //for opening big cube } private E_PATTERN_TYPE mPatternType; private int mFrame; private int mFrameMax = 75;Star Class
The Star class provides particles that are expressed as the flowing galaxy-type effects that appear on the top and bottom of the game screen in the background. Star class instances have three states as listed below. DEAD means dead. Normal means normal speed, and Morning Star means fast speed.
Figure 4. Stars are in the red boxes.
Star objects are created with a 33% chance when the UpdateGateState method is called from inside the Game class. The maximum number of Star objects that can be created at any give time is 100, as specified by the NUM_OF_STARS variable.
private static final int NUM_OF_STARS = 100; Random r = new Random(); if (r.nextInt(3) == 0) { stars[mCurStarNum].setAlive(); mCurStarNum++; if (mCurStarNum >=NUM_OF_STARS) { mCurStarNum = 0; // if spark #0 is still showing, it could be cancled accidently } }When the setAlive method is requested from the Game class, the Star instance is placed in the top or bottom of the game screen with a 50% chance of either.
Then, 10% of them are given the MORNINGSTAR property, which speeds up movement.public void setAlive() { Random r = new Random(); mStartX = 8.20f;//-2.6f; if (r.nextInt(2)== 0) { // make upper region star mStartY = (float)(r.nextInt(750))/100.0f+5.3f; } else { // make lower region star mStartY = (float)(r.nextInt(750))/100.0f-12.3f; } if (r.nextInt(10) == 0) { setPattern(E_PATTERN_TYPE.PT_200_MORNINGSTAR); mVelX = (float)(-r.nextInt(5)-5)*0.03f; mVelY = 0.0f; } else { setPattern(E_PATTERN_TYPE.PT_100_NORMAL); mVelX = (float)(-r.nextInt(5)-5)*0.01f; mVelY = 0.0f; } }Animations of the Star class are defined by enum strings.
public enum E_PATTERN_TYPE { // spark pattern PT_000_DEAD, PT_100_NORMAL, PT_200_MORNINGSTAR }Skybox Class
The Skybox class is the large square box object that rotates in the background of the game screen. It rotates at a regular speed (ROTATING) in the background when the game begins. It starts rotating fast (ROTATINGFAST) when there is only one more cube left in the game, and it shakes (SHAKING) when a cube is pressed in the incorrect order.
Figure 5-1. The object in the red box is the Skybox object, and it continues to rotate during gameplay.
The Skybox is actually an empty cube created with six textures. The six different surfaces are shown below.
Figure 5-2. The textures for the four sides (front, back, left, right) are the same textures. Two textures for the top and bottom surfaces are added to create a cube. In the game screen, the camera rotates inside this cube.
Animations of the Skybox class are defined by enum strings.
public enum E_ANIMATION_TYPE { AT_100_ROTATING, // normal rotating AT_200_ROTATINGFAST, // when the only 1 cube remained AT_300_SHAKING // when user pushed the incorrect cube } private int mFrame; private E_ANIMATION_TYPE mType;Heart Class
The Heart Class is a class that creates the heart-shaped life system displayed on top left part of the game screen. Internally, one heart is separated into left and right parts. These parts are handled and rendered as separate instances. When the state property is DEAD, it is not displayed on the screen. When the state property is SHOW, it repeats a moving animation according to the durationLoop value defined in onPatterType_100_Show variable. Lastly, if the state property is BROKEN, it plays an animation were the heart breaks down into two pieces according to the durationLoop value defined in onPatternType_200_Broken. Then, it is set as DEAD.
Figure 6. The red box contains the Heart objects. Each heart consists of a left part and a right part.
During game playing, 1 heart disappears every second and 1 heart disappears when the player presses the wrong cube. Every time the player presses a cube in the right order, 5 hearts are added.
public enum E_PATTERN_TYPE { PT_000_DEAD, PT_100_SHOW, PT_200_BROKEN } private E_PATTERN_TYPE mPatternType; private int mFrame; private int mLeftRight; // left part? right part? (of heart) private int mIndex; // (0,1) (2,3) (3,4) -> 3 lives private int mScrIndex; // 10(total lives) - mIndexNumber Class
The Number class displays the remaining number of cubes that must be pressed and the current stage number. This game has 16 stages with bitmap textures for each of the numbers.
Figure 7. Number texture images (64x64)
If the state property is DEAD, it is not displayed on the screen. If the state property is STAGENUMBER, the number of the stage is displayed when each stage begins. Lastly, if the state property is REMAINEDNUMBER, it shows the number of remaining cubes in the game using animations.
public enum E_PATTERN_TYPE { // spark pattern PT_000_DEAD, PT_100_STAGENUMBER, // shown with ‘remember cubes’ PT_200_REMAINEDNUMBER // shown on the bottom line to show how many cubes are remained until user push it } private E_PATTERN_TYPE mPatternType; private int mShowNumber; // 1~16When you look at the animation method for the STAGENUMBER state properties, which displays the stage number in the beginning of each stage, there are three integer variables. The durationFromOutToIn value refers to the total number of frames in the animation where the number rises from the bottom to the center of the screen. durationStill refers to the total number of frames in the animation when the number is floating in the center of the screen. Lastly, the durationFromInToOut refers to the total number of frames in the animation where the number moves to the upper-left corner of the screen.
int durationFromOutToIn = 30; // phase #1 int durationStill = 50; // phase #2 int durationFromInToOut = 30; // phase #3 float temp; float x,y,z; gl.glTranslatef(0.0f, -0.15f, -4.0f); if ( (mFrame >=0) && (mFrame=durationFromOutToIn) && (mFrame= durationFromOutToIn+durationStill) && (mFrame < durationFromOutToIn+durationStill+durationFromInToOut) ) { // phase #3 } else { setNumber(E_PATTERN_TYPE.PT_000_DEAD, 0); mFrame=0; }Panel Class
The Panel class refers to the panel that is rendered behind the text to improve readability of in-game messages. When it is in the NOTHING TO SHOW state, the panel does not show images. When it is in the SLOWLY WIDER state, the panel spreads out when displaying messages. The WIDER BIGGER state is a panel used to display an error message when the game’s download license is not valid (that is, when it was not downloaded through an authorized distribution channel).
Figure 8. Shows SLOWLYWIDE Panel texture rendered behind the message “REMEMBER THE ORDER”.
3 animations are defined by enum strings.
public enum E_PANEL_TYPE { PT_100_NOTHINGTOSHOW, PT_200_SLOWLYWIDER, PT_300_WIDERBIGGER, } private E_PANEL_TYPE mPanelType; private int mFrame;Message Class
The Message class displays the necessary instructions during the game. Only the white text is displayed and the black background is not displayed using alpha blending. Each instance in the Message class has one of the five state properties defined within the Game class, and displays corresponding messages.
Figure 9. Message class texture images
The 5 messages are defined by enum strings.
public enum E_MSG_TYPE { MT_100_NOTHINGTOSHOW, MT_200_REMEMBER, MT_300_TRY, MT_400_CLEAR, MT_500_FAIL, MT_600_LICENSEERROR, // especially for license problem } private E_MSG_TYPE mMsgType;Note that the textures are saved as BMPs and the texture is inverted. This is because the BMP coordinate system and OGLES coordinate system use opposite ups and downs. This game uses a method of saving inverted texture sources rather than correcting the coordinates at runtime.
Button Class
The button class accepts the user’s input during gameplay. There are 5 types of buttons. Each button has 3 states for display (START), waiting for input (STAY) and hiding (FINISH).
public enum E_BTN_TYPE { BT_100_NOTHINGTOSHOW, BT_200_START_START, BT_201_START_STAY, BT_202_START_FINISH, BT_400_DONATE_START, // for In-app Purchased item play = donation BT_401_DONATE_STAY, BT_402_DONATE_FINISH, BT_500_REPLAY_START, BT_501_REPLAY_STAY, BT_502_REPLAY_FINISH, BT_600_DONATION_CONFIRM_START, BT_601_DONATION_CONFIRM_STAY, BT_602_DONATION_CONFIRM_FINISH, BT_700_DONATION_REJECT_START, BT_701_DONATION_REJECT_STAY, BT_702_DONATION_REJECT_FINISH }The Button class displays an animation to display buttons when they are in the *_START state. It shows another animation while waiting for user input in the *_STAY state, and another animation to remove buttons when they are in the *_FINISH state.
Just like Message class, the black parts are not displayed by using alpha blending, and only the white part of the texture is rendered on the screen.
Figure 10. Button class texture images
Score Class
The Score class displays the user’s current score on the screen. It renders the score in the lower-left corner of the screen during gameplay (SHOW), and gradually moves to the center of the screen when a user fails a stage (FINAL). When the user presses a button after failing a stage, it animates the score disappearing (FINAL_OUT).
Figure 11-1. Score class animation
3 animations are defined by enum strings.
public enum E_SHOW_TYPE { ST_000_DEAD, ST_100_SHOW, ST_200_FINAL, // to show final score when game is over ST_300_FINAL_OUT }All the numbers used to display the score are rendered using bitmap resources.
Figure 11-2. Number texture images (64x64)
BigCube Class
The BigCube class renders the giant cube in the opening screen. The Big Cube animation consists of 3 stages; RISING, when it appears on the screen; FLOATING, when the game is waiting for the user to press the Start button; and FALLING, when the cube disappears when the user presses the Start button.
Figure 12. Shows the 3 stages of Big Cube animation in the opening screen.
Each stage of the animation is defined by enum strings.
// There are several type of animation for this big cube public enum E_ANIM_TYPE { AT_000_DEAD, // show nothing AT_100_RISING, // rising from bottom area AT_200_FLOATING, // floating until user press the button AT_300_FALLING // falling down to bottom area }The Big Cube also includes an animation that responds to the tilt angle of the device. When the onSensorChanged method of the Game class sends the changed sensor values to the BigCube class, the Big Cube rotates.
public void onSensorChanged(SensorEvent event) { if (event.sensor.getType() == Sensor.TYPE_ORIENTATION) { Log.d(TAG, (int)event.values[2]+” roll / “+(int)event.values[1]+” pitch “); mCurDevPitch = (int)event.values[1]; mCurDevRoll = (int)event.values[2]; bigCube.setRotation(mCurDevRoll, mCurDevPitch); // for galaxy S } }The rotation value is reflected on the BigCube and changes the rotation coordinates.
public void setRotation(float pitch, float roll) { mDstPitch = pitch; mDstRoll = roll; }ALicenseCheck Class
The LicenseCheck class declares a listener method for checking license validity using Zirconia, a license management library for Samsung Apps. The two methods that must be declared are licenseCheckedAsValid and licenseCheckedAsInvalid. Licenses are checked by attempting to confirm license validity by using zirconia.checkLicense(false, false) in the onSurfaceCreated method of the Game class. If the results show that app was downloaded from an authorized distribution source, the licenseCheckedAsValid method in the LicenseCheck class is called. If the game was not downloaded from Samsung Apps, licenseCheckedAsInvalid is called.
class LicenseCheck implements LicenseCheckListener{ private int mLegitimacy = 1; // 1 = legal, 0 = illegal @Override public void licenseCheckedAsValid() { // nothing to do in here // This app assume the default value as “every app is downloaded legally” } @Override public void licenseCheckedAsInvalid() { //this app is determined as illegally downloaded app mLegitimacy = 0; } public int getLegitimacy() { return mLegitimacy; } }If the license is not valid, meaning that it wasn’t downloaded from Samsung Apps, a warning message appears after clearing the first stage and the game exits.
Figure 13. When the license is invalid, an error message is displayed after clearing the first stage and the game exits.
Ring Class
The Ring class creates the animated rings around the animated cubes.
When it’s in the DEAD state, it does not render anything. When it is in the AFFIRMATIVE state, it animates rings around the cube when the user presses the cubes in the correct order. When in the NEGATIVE state, it displays a large X when the user presses the wrong cube. In the DEMO state, it renders an animation when the cubes pop-up to show the order to the user in the beginning of the stage. It is similar to the AFFIRMATIVE state. Lastly, the AFFIRMATIVEFINAL state shows an animation that scales the texture into a large explosion when the user clears the stage.
Figure 14-2. Shows textures applied on the game screen.
Each animation is defined by enum strings.
public enum E_PATTERN_TYPE { // spark pattern PT_000_DEAD, PT_100_AFFIRMATIVE, PT_200_NEGATIVE, PT_300_DEMO, // selected at demonstration time PT_400_AFFIRMATIVEFINAL }YellowCubeActivity Class
The YellowCubeActivity class is the activity class of the game. The onWindowFocusChanged and onPause methods turn the sounds of the Hold, Back and Home buttons on and off. The onCreate method sets the layout for Samsung AdHub and initializes In-app Purchases.
The onTouchEvent method is declared in the MyView class. It sends 2D coordinates of user input on the touch screen to the findTheTouchedPos method of the Game class, and converts it into 3D coordinates within the method.protected class MyView extends GLSurfaceView{ public MyView(Context context) { super(context); } public boolean onTouchEvent(MotionEvent event) { float x = 0.0f; float y = 0.0f; switch(event.getActionMasked()) { case MotionEvent.ACTION_DOWN: case MotionEvent.ACTION_MOVE: x = event.getX(); y = event.getY(); game.findTheTouchedPos((int)x,(int)y); break; } return true; } };
Kindly note that resource files are not included into the source code.



