Thursday, February 21, 2019

Flappy bird

When Flappy bird gone viral on Play Store, there‘s many people jump in to game development industry, like gold rush. We will make it in simple way by canvas.
Prepare a small icon size 30x30, it look like a bird, you can make it by using Word, insert Shape.



Icon green bar width 30, height 125dp.
Create folder drawable below res, copy icons in to it. Create a folder name raw, put a mp3 sound file length one minute, the sound when bird hit the bar.


In file Androidmanifest.xml of class Main, add two lines.
android:screenOrientation="landscape"
android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
We set game to lanscape and full screen.


When you set screen lanscape, x index will be the horizon length, y will be vertical height.


The origin co-ordinate 0,0 at top left screen corner.
Create a class name gameview below class Main.
Copy these lines to above last bracket.
public class gameview extends View {
public gameview(Context context) {
               super(context);
}        
          @SuppressLint({ "NewApi", "DrawAllocation" })
          @Override
          protected void onDraw(final Canvas canvas) {
               // TODO Auto-generated method stub
               super.onDraw(canvas);
invalidate();
          }   
}
Copy to below class Main open bracket.
String record = "";
private gameview game;
Comment the line setContentView, copy to below that comment.
game = new gameview(this);
game.setBackgroundColor(Color.WHITE);
setContentView(game);
Run to see blank screen white.
Copy to below public class gameview extends View {
private Paint paint;
private Bitmap bird, bar, bar2;         
int y;        
int xbar, xbar2, ybar,xcount; 
int count;               
Boolean hit = false;     
Boolean finger = false;
Boolean run = true;
int soky = 0;
private SoundPool soundPool;
int soundId;        
int bump = -1;
int r, c;     
Import libraries.
Copy to below super(context);
paint = new Paint();
paint.setColor(Color.parseColor("#FF00FF"));            
paint.setTextAlign(Align.CENTER);
paint.setTypeface(Typeface.create(Typeface.DEFAULT, Typeface.BOLD));
DisplayMetrics metrics = getResources().getDisplayMetrics();           
     r = metrics.widthPixels;
     c = metrics.heightPixels;
bird = BitmapFactory.decodeResource(getResources(), R.drawable.ki);
bar = BitmapFactory.decodeResource(getResources(), R.drawable.kb);
bar2 = BitmapFactory.decodeResource(getResources(), R.drawable.kb);
xbar = r ;
xbar2 = r;
xcount=xthanh-200+thanh.getWidth()+chim.getWidth();;
y = c / 2;    
              
soundPool = new SoundPool(10, AudioManager.STREAM_MUSIC, 0);
bump = soundPool.load(context, R.raw.bump, 1);    


Import libraries, make sure icons, mp3 file name the same as you name them.
To make it simple, we first make only two bars.
Copy these lines to above last bracket.
public void read() {
          try {
          String FILE_NAME = "record.txt";        
          FileInputStream fIS = openFileInput(FILE_NAME);         
          byte[] arrayData = new byte[fIS.available()];
          if ((fIS.read(arrayData)) != -1) {
          String fileContent = new String(arrayData);
          record = fileContent;                   
          }        
          fIS.close();
          } catch (Exception e) {            
               // Log.e("Error", e.toString());
          }
     }
public void write(String d) {
          try {
               FileOutputStream fos = openFileOutput("record.txt",
                          Context.MODE_APPEND);
               OutputStreamWriter osw = new OutputStreamWriter(fos);
               osw.append(d);
               osw.flush();
               osw.close();
          } catch (FileNotFoundException e) {
               e.printStackTrace();
          } catch (IOException e) {
               e.printStackTrace();
          }
     }
This is methods to write and read the score, number times the bird fly through the bars.
Copy to below super.onDraw(canvas);
Paint paint2 = new Paint();
paint2.setColor(Color.BLACK);
paint2.setTextAlign(Align.CENTER);
paint2.setTextSize(25);            
paint2.setTextAlign(Align.CENTER);
                              
canvas.drawBitmap(bar, xbar, 0, null);
canvas.drawBitmap(bar2, xbar2, 340, null);
              
Rect touch=new Rect(200, y,200 + bird.getWidth(),y+bird.getHeight());
Rect touch1 = new Rect(xbar, 0, xbar + bar.getWidth(), bar.getHeight());
Rect touch2 = new Rect(xbar2, 340, xbar2 + bar.getWidth(), 340+bar.getHeight());
if (run == true) {
     read();
if (record.length() > 0) {
     soky = Integer.parseInt(record);
     }
     xbar = xcount - 7;
     xbar2 = xbar2 - 7;       
     xcount = xcount-7;                                
     canvas.drawText("Record: " + soky + " - " + "Score: " + count,
                                    r / 2, 20, paint2);           

          if (finger == true) {                        
          y=y-5;                        
     float rotation = -10.0f;                     
          Matrix matrix = new Matrix();
          float px = 200;
          float py = y;                      
          matrix.postRotate(rotation);
          matrix.postTranslate(px, py);
          canvas.drawBitmap(bird, matrix, null);                       
          } else {
          y=y+5;
          float rotation = 10.0f;                      
          Matrix matrix = new Matrix();
          float px = 200;
          float py = y;                           
          matrix.postRotate(rotation);
          matrix.postTranslate(px, py);
          canvas.drawBitmap(bird, matrix, null);
         }
          if (Rect.intersects(touch, touch1)) {                        
          hit=true;
          soundPool.play(bump, 0.9f, 0.1f, 1, 0, 0.7f);           
          }
          if (Rect.intersects(touch, touch2)) {                        
          hit=true;
          soundPool.play(bump, 0.9f, 0.1f, 1, 0, 0.7f);                
          }                   
          }   
Run to see the bird and two bars, but bird fall down because we can’t control now.



Let take time to look at code.
We declare paint2 to draw String Record and Score on top screen.
The line canvas.drawBitmap(bar, xbar, 0, null);draw the first bar, on super(context); we set xbar = r ; to draw it at top right edge screen.
canvas.drawBitmap(bar2, xbar2, 340, null);
We draw second bar with y = 340 to make a gap so the bird can fly through.
Rect touch draw rectangulars to surround the bird, the bars.
In command if, run == true  mean game is running, not Over.
xthanh = xthanh - 7;
xthanh2 = xthanh2 - 7;   
This make the bars move to the left screen.
 if (finger == true) { mean the user touch their finger on screen.
 y=y-5;make the bird fly up when touch.
In command else we set y=y+5; mean when finger off screen, the bird fall down.
To make the bird lift up his’s head when fly up, we use.
float rotation = -10.0f;      
Matrix matrix = new Matrix();
float px = 200;
float py = y;                      
matrix.postRotate(rotation);
matrix.postTranslate(px, py);
canvas.drawBitmap(chim, matrix, null);  
To make the bird lower his head when fall down, in else we change float rotation = -10.0f; to float rotation = 10.0f;   
if (Rect.intersects(touch, touch1)) {
In this command, we set what happen when bird hit bars. We set hit=true;
To make sure our rectangulars draw at true position, add these lines to below rect touch.
canvas.drawRect(200, y,200 + bird.getWidth(),y+bird.getHeight(),paint);
canvas.drawRect(xbar, 0,xbar + bar.getWidth(),bar.getHeight(),
                     paint);      
canvas.drawRect(xbar2, 340, xbar2 + bar.getWidth(), 340+bar.getHeight(),paint);  


Run to see the bars, the bird were surround by pink rectangulars.
Now make them become comments, we just need them to check positions.
Copy to below invalidate() one close bracket }
@SuppressLint("ClickableViewAccessibility")       
          @Override
          public boolean onTouchEvent(MotionEvent event) {             
               switch (event.getAction() & MotionEvent.ACTION_MASK) {       
               case MotionEvent.ACTION_UP:
               finger = false;
               break;        
               case MotionEvent.ACTION_DOWN:
               finger=true;  
               if (run == false) {
               run = true;
               hit=false;
               y=c/2;
               count = 0;
               xbar = r - bar.getWidth();
               xbar2 = r - bar.getWidth();
               xcount=xcount-200+bar.getWidth()+bird.getWidth();
               }                             
               break;
               }
               return true;
          }


These line allow us control the bird by touch screen phone.
When user touch screen, that is case MotionEvent.ACTION_DOWN:
We set finger=true;,on the code above, we set if finger=true;make the bird fly up.
 if (run == false) { that mean Game Over we make everything to be initial position.
When user lift their finger off screen, that is case MotionEvent.ACTION_UP: we set finger = false;
In code above, command else make the bird fall down.
Run to see we can control the bird, but the bar run over just one time.
To make the bars return, add these lines above invalidate()
if (xbar < -bar.getWidth()) {
     xbar = r;
     xbar2 = r;
     xcount=xbar-200+bar.getWidth()+bird.getWidth();;
     }
if (y >c) {
     run=false;
}
if (y <0) {
     y=0;
}
if(xcount<0){
     xcount=r;
     count=count+1;
     }
if (hit == true) {
finger = false;
run=false;
y = y + 10;
float rotation = 30.0f;                      
Matrix matrix = new Matrix();
float px = 200;
float py = y;                      
matrix.postRotate(rotation);
matrix.postTranslate(px, py);
canvas.drawBitmap(bird, matrix, null);
}        
if (run == false) {
if (count > soky) {
deleteFile("record.txt");
write(String.valueOf(count));
paint.setTextAlign(Align.CENTER);
paint.setTextSize(30);
canvas.drawText("New record: " + count + " ", r / 2, 30,
                                    paint);
          }
  paint.setTextSize(60);
                    
canvas.drawText("Game Over", r / 2, 100, paint);             
canvas.drawText("Tap to replay!", r / 2, c / 2 + 70, paint);
                     paint.setTextSize(35);
canvas.drawText("Score: " + dem, r / 2, 160, paint);                   
               }
First if mean when the bar go in to left edge, we move it to right edge.
if (y >c) { mean when bird fall down over bottom edge, game over.
if (y <0) { to keep the bird can’t move over top edge screen.
if (hit == true) { we set every values to false, make game over, increase falling bird by line y = y + 10;
We also make the bird lower his head when falling down.
 if (run == false) { when game over, we check the times bird fly through the bars, if it’s bigger than last time, we call method write() to write it and show inform new record.
To know last record, when game open, in command if (run == true){ we call method read(); and change value received to interger.
if (record.length() > 0) {
soky = Integer.parseInt(record);
}
The first time run game, soky =0.
The line paint.setTextSize(60); to set big font to draw String Game Over, Tap to replay and number score.
One last problem is how to count the time the bird fly through bars.
We use two variables xcount and count.
When initial,  xcount=xbar-200+bar.getWidth()+bird.getWidth(); this make the xcount go to left edge when the bar pass over the bird. To make sure the bird has fly over bars, we plus the widths of both bar and bird.
After that we use
if(xcount<0){
xcount=r;
count=count+1;
}
To make xcount run parallel with x index of bars, we set xcount = xcount-7;
When bars return, we also set xcount to initial value.
xcount=xbar-200+bar.getWidth()+bird.getWidth();
When Game over, we set xcount  with same value, and set count=0 to count again.
Below is the entire code game flappy bird.
public class MainActivity extends Activity {
     String record = "";
     private gameview game;
     @Override
     protected void onCreate(Bundle savedInstanceState) {
          super.onCreate(savedInstanceState);
          // setContentView(R.layout.activity_main);
          game = new gameview(this);
          game.setBackgroundColor(Color.WHITE);
          setContentView(game);
     }
     public class gameview extends View {
          private Paint paint;
          private Bitmap bird, bar, bar2;
          int y;
          int xbar, xbar2, xcount;
          int count;
          Boolean hit = false;
          Boolean finger = false;
          Boolean run = true;
          int soky = 0;
          private SoundPool soundPool;
          int soundId;
          int bump = -1;
          int r, c;
          public gameview(Context context) {
               super(context);
               paint = new Paint();
               paint.setColor(Color.parseColor("#FF00FF"));
               paint.setTextAlign(Align.CENTER);
     paint.setTypeface(Typeface.create(Typeface.DEFAULT, Typeface.BOLD));
          DisplayMetrics metrics = getResources().getDisplayMetrics();
               r = metrics.widthPixels;
               c = metrics.heightPixels;
     bird = BitmapFactory.decodeResource(getResources(), R.drawable.ki);
     bar = BitmapFactory.decodeResource(getResources(), R.drawable.kb);
     bar2 = BitmapFactory.decodeResource(getResources(), R.drawable.kb);
               xbar = r;
               xbar2 = r;
               xcount = xbar - 200 + bar.getWidth() + bird.getWidth();
               y = c / 2;

               soundPool = new SoundPool(10, AudioManager.STREAM_MUSIC, 0);
               bump = soundPool.load(context, R.raw.bump, 1);
          }
          @SuppressLint({ "NewApi", "DrawAllocation" })
          @Override
          protected void onDraw(final Canvas canvas) {
               // TODO Auto-generated method stub
               super.onDraw(canvas);
               Paint paint2 = new Paint();
               paint2.setColor(Color.BLACK);
               paint2.setTextAlign(Align.CENTER);
               paint2.setTextSize(25);
               paint2.setTextAlign(Align.CENTER);

               canvas.drawBitmap(bar, xbar, 0, null);
               canvas.drawBitmap(bar2, xbar2, 340, null);

     Rect touch = new Rect(200, y, 200 + bird.getWidth(), y
                          + bird.getHeight());
     Rect touch1 = new Rect(xbar, 0, xbar + bar.getWidth(),
                          bar.getHeight());
     Rect touch2 = new Rect(xbar2, 340, xbar2 + bar.getWidth(),
                          340 + bar.getHeight());
               // canvas.drawRect(200, y,200 +
               // bird.getWidth(),y+bird.getHeight(),paint);
               // canvas.drawRect(xbar, 0,xbar +
               // bar.getWidth(),bar.getHeight(),
               // paint);
               // canvas.drawRect(xbar2, 340, xbar2 + bar.getWidth(),
               // 340+bar.getHeight(),
               // paint);
               if (run == true) {
                     read();
                     if (record.length() > 0) {
                          soky = Integer.parseInt(record);
                     }
                     xbar = xbar - 7;
                     xbar2 = xbar2 - 7;
                     xcount = xcount - 7;
          canvas.drawText("Record: " + soky + " - " + "Score: " + count,
                               r / 2, 20, paint2);

                     if (finger == true) {
                          y = y - 5;
                          float rotation = -10.0f;
                          Matrix matrix = new Matrix();
                          float px = 200;
                          float py = y;
                          matrix.postRotate(rotation);
                          matrix.postTranslate(px, py);
                          canvas.drawBitmap(bird, matrix, null);
                     } else {
                          y = y + 5;
                          float rotation = 10.0f;
                          Matrix matrix = new Matrix();
                          float px = 200;
                          float py = y;
                          matrix.postRotate(rotation);
                          matrix.postTranslate(px, py);
                          canvas.drawBitmap(bird, matrix, null);
                     }
                     if (Rect.intersects(touch, touch1)) {
                          hit = true;
                          soundPool.play(bump, 0.9f, 0.1f, 1, 0, 0.7f);
                     }
                     if (Rect.intersects(touch, touch2)) {
                          hit = true;
                          soundPool.play(bump, 0.9f, 0.1f, 1, 0, 0.7f);
                     }
               }
               if (xbar < -bar.getWidth()) {
                     xbar = r;
                     xbar2 = r;
                     xcount = xbar - 200 + bar.getWidth() + bird.getWidth();
               }
               if (y > c) {
                     run = false;
               }
               if (y < 0) {
                     y = 0;
               }
               if (xcount < 0) {
                     xcount = r;
                     count = count + 1;
               }
               if (hit == true) {
                     finger = false;
                     run = false;
                     y = y + 10;
                     float rotation = 30.0f;
                     Matrix matrix = new Matrix();
                     float px = 200;
                     float py = y;
                     matrix.postRotate(rotation);
                     matrix.postTranslate(px, py);
                     canvas.drawBitmap(run, matrix, null);
               }

               if (run == false) {
                     if (count > soky) {
                          deleteFile("record.txt");
                          write(String.valueOf(count));
                          paint.setTextAlign(Align.CENTER);
                          paint.setTextSize(30);
          canvas.drawText("New record: " + count + " ", r / 2, 30,
                                    paint);
                     }
                     paint.setTextSize(60);
                     canvas.drawText("Game Over", r / 2, 100, paint);
          canvas.drawText("Tap to replay!", r / 2, c / 2 + 70, paint);
                     paint.setTextSize(35);
                     canvas.drawText("Score: " + count, r / 2, 160, paint);
               }
               invalidate();
          }
          @SuppressLint("ClickableViewAccessibility")
          @Override
          public boolean onTouchEvent(MotionEvent event) {
               switch (event.getAction() & MotionEvent.ACTION_MASK) {
               case MotionEvent.ACTION_UP:
                     finger = false;
                     break;
               case MotionEvent.ACTION_DOWN:
                     finger = true;
                     if (run == false) {
                     run = true;
                    hit = false;
                     y = c / 2;
                     count = 0;
                     xbar = r - bar.getWidth();
                     xbar2 = r - bar.getWidth();
               xcount = xbar - 200 + bar.getWidth() + bird.getWidth();
                     }
                     break;
               }
               return true;
          }
     }
     public void read() {
          try {
               String FILE_NAME = "record.txt";
               FileInputStream fIS = openFileInput(FILE_NAME);
               byte[] arrayData = new byte[fIS.available()];
               if ((fIS.read(arrayData)) != -1) {
                     String fileContent = new String(arrayData);
                     record = fileContent;
               }
               fIS.close();
          } catch (Exception e) {
               // Log.e("Error", e.toString());
          }
     }
     public void write(String d) {
          try {
               FileOutputStream fos = openFileOutput("record.txt",
                          Context.MODE_APPEND);
               OutputStreamWriter osw = new OutputStreamWriter(fos);
               osw.append(d);
               osw.flush();
               osw.close();
          } catch (FileNotFoundException e) {
               e.printStackTrace();
          } catch (IOException e) {
               e.printStackTrace();
          }
     }

}

No comments:

Post a Comment