Android Surfaceview take you to play flabby bird (on)

Source: Internet
Author: User
Tags bit set

Reprint please indicate the source: http://blog.csdn.net/lmj623565791/article/details/42965779, this article from: "Zhang Hongyang Blog" 1, overview

Ha, remember previously written Android Surfaceview to build the lottery turntable, the same belongs to the Surfaceview series, the basic can learn from this blog post Surfaceview usage, as well as the use of Surfaceview to do lottery turntable. But the lack of a part of the knowledge point, is the interface with the user interaction changes, so today to everyone to bring this blog how to do flabby bird this game, although the game is not difficult, but also for its author earned a lot of money, everyone in the learning, can play their own creative, Do your own game, maybe the next fire is you.

OK, then first up and down:


Another dynamic:


Due to the maximum upload image limit is 2M, so do a compression processing, do not look at it ~ ~ ~


2. Analysis

Careful observation of the game, you need to draw: background, flooring, birds, pipes, fractions;

When the game starts:

The floor gives a feeling of wanting to move to the left;

The pipe moves at the same speed as the floor to the left;

Bird default drop;

When the user touches the screen, the bird rises a distance and drops;

It is necessary to determine the position relationship between the pipe and the bird, whether the contact is touching or not, and the score needs to be calculated.

Well, that's about it, so let's start thinking about drawing first ~ ~ ~


3, the general wording of Surfaceview

Next, we first write the general wording of the following surfaceview:

Package Com.zhy.view;import Android.content.context;import Android.graphics.canvas;import Android.graphics.pixelformat;import Android.util.attributeset;import Android.view.surfaceholder;import Android.view.surfaceholder.callback;import Android.view.surfaceview;public class Gameflabbybird extends SurfaceView Implements Callback, Runnable{private surfaceholder mholder;/** * Canvas surfaceholder bound with */private canvas mcanvas;/** * The thread used to draw the */private thread t;/** * Control Switch */private boolean isrunning;public Gameflabbybird (context context) {This (context , null);} Public Gameflabbybird (context context, AttributeSet Attrs) {Super (context, attrs); mholder = Getholder (); Mholder.addcallback (this); Setzorderontop (true);//Set Canvas background transparent Mholder.setformat (pixelformat.translucent);// Set to get Focus setfocusable (TRUE); Setfocusableintouchmode (true);//Set solid This.setkeepscreenon (true);} @Overridepublic void surfacecreated (Surfaceholder holder) {//Open thread isrunning = true;t = new Thread (this); T.start ();} @Overridepublic void surfaceChanged (surfaceholder holder, int format, int width,int height) {//TODO auto-generated method stub} @Overridepublic void Su Rfacedestroyed (Surfaceholder holder) {//notification shutdown thread isrunning = false;} @Overridepublic void Run () {while (isrunning) {Long start = System.currenttimemillis ();d Raw (); Long end = System.currenttimemillis (); Try{if (End-start <) {Thread.Sleep (-(End-start))}} catch (Interruptedexception e) {E.printstacktrace ();}}} private void Draw () {try{//gets canvasmcanvas = Mholder.lockcanvas (); if (Mcanvas! = null) {//drawsomething.}} catch (Except Ion e) {} finally{if (Mcanvas! = null) mholder.unlockcanvasandpost (Mcanvas);}}

This basic class, in the Android Surfaceview actual combat to build the lottery turntable has appeared, not much to say, we later write Surfaceview related procedures, can be copied directly, on this basis to write.


4. Drawing


1. Draw the background

The simplest of course is the background, direct Drawbitmap can.

We add the required member variables, initialize some parameters, then add the Drawbg method, and finally call DRAWBG in draw;

public class Copyofgameflabbybird extends Surfaceview implements callback,runnable{/** * Current view dimensions */private int mwidth;p rivate int mheight;private RECTF mgamepanelrect = new RECTF ();/** * Background */private Bitmap mbg;public Copyofgameflabbybird (Co ntext context, AttributeSet attrs) {//omitted a lot of code initbitmaps ();} /** * Initialize picture */private void Initbitmaps () {mBg = Loadimagebyresid (R.DRAWABLE.BG1);} private void Draw () {//omitted a lot of code DRAWBG ();//omitted a lot of code}/** * Draw background */private void Drawbg () {mcanvas.drawbitmap (mBg, NULL, Mgamepanelrect, null);} /** * Initialize Dimension related */@Overrideprotected void onsizechanged (int w, int h, int oldw, int oldh) {super.onsizechanged (W, H, OLDW, OL DH); mwidth = W;mheight = H;mgamepanelrect.set (0, 0, W, h);} /** * Load Picture according to RESID *  * @param resId * @return */private Bitmap loadimagebyresid (int resId) {return Bitmapfactory.decoder Esource (Getresources (), resId);}}

The basic is to add member variables, and then initialize, and then draw, the above code has been truncated, and posted are different from the previous basic code of the section, you can fill the code.

Well, now that the background map is drawn, next, we draw the bird ~ ~ ~


2. Draw Bird

The bird in our screen, the initialization needs a position, X, must be centered, Y on the height we take 2/3;

For Bird, we create a separate class:

Package Com.zhy.view;import Android.content.context;import Android.graphics.bitmap;import Android.graphics.Canvas; Import Android.graphics.rectf;public class bird{/** * Bird at 2/3 position of screen height */private static final float radio_pos_height = 2/3f; /** * Bird width 30dp */private static final int bird_size = 30;/** * Bird's axis */private int x;/** * Bird's ordinate */private int y;/** * Bird's width */private int mwidth;/** * Bird height */private int mheight;/** * Bird Bitmap */private Bitmap bitmap;/** * Bird drawn range */private Rec TF rect = new RECTF ();p ublic Bird (context context, int gamewith, int gameheight, Bitmap Bitmap) {this.bitmap = bitmap;//bird bit Set x = GAMEWITH/2-Bitmap.getwidth ()/2;y = (int) (gameheight * radio_pos_height);//Calculates the width and height of the bird mwidth = util.dp2px (Contex T, bird_size); mheight = (int) (Mwidth * 1.0f/bitmap.getwidth () * bitmap.getheight ());} /** * Draw yourself * * @param canvas */public void draw (canvas canvas) {rect.set (x, y, x + mwidth, y + mheight); Canvas.drawbitmap ( Bitmap, NULL, rect, NULL);} public int GetY () {return y;} public void sety (int y) {this.y = y;} public int getwidth () {return mwidth;} public int getheight () {return mheight;}}

Defines a class that represents our bird, as well as a bunch of member variables, and provides a draw method to the outside;

In Gameflabbybird, only need, initialize our bird, in draw inside call Bird.draw can;

Partial screen Post code:

public class Copyofgameflabbybird extends Surfaceview implements callback,runnable{/** * ********* birds related ***************** */private Bird mbird;private Bitmap mbirdbitmap;/** * Initialize picture */private void Initbitmaps () {mBg = Loadimagebyresid (r.dr AWABLE.BG1); mbirdbitmap = Loadimagebyresid (R.DRAWABLE.B1);} private void Draw () {//drawsomething. DRAWBG ();d rawbird ();} private void Drawbird () {Mbird.draw (Mcanvas);} /** * Initialize Dimension related */@Overrideprotected void onsizechanged (int w, int h, int oldw, int oldh) {//Initialize Mbirdmbird = new Bird (Getcon Text (), Mwidth, Mheight, Mbirdbitmap);}}
is not very simple, the following look at this time:

You can call this in the activity:

Package Com.zhy.surfaceviewdemo;import Com.zhy.view.gameflabbybird;import Android.app.activity;import Android.os.bundle;import Android.view.window;import Android.view.windowmanager;public class MainActivity extends Activity{gameflabbybird mgame; @Overrideprotected void OnCreate (Bundle savedinstancestate) {super.oncreate ( Savedinstancestate); GetWindow (). SetFlags (WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); requestwindowfeature (window.feature_no_title); mgame = new Gameflabbybird (this); Setcontentview (Mgame);}}

Anyway, our bird is already in the designated position ~ ~ ~ There is a little bit of excitement in the wood ~ ~

Start adding floor below;

3. Draw the floor

Draw the floor compared to a bit more difficult, because we need to consider how to let the floor movement, at first I intercepted two large pictures, I hope that through the two charts constantly change, produce animation effect, but, animation of the card, there is jumping sense;

So, I suddenly thought of a thing to do, I put the basic diagram into this:

A very small piece of graph, regardless of motion, how to fill into our goal effect?

Do you remember a class called Bitmapshader? We can use it to populate.

Relevant knowledge can be consulted: Android Bitmapshader real-round, rounded picture

First, we're still defining a floor class: floors

Package Com.zhy.view;import Java.util.concurrent.timeunit;import Com.zhy.surfaceviewdemo.config;import Android.content.context;import Android.graphics.bitmap;import Android.graphics.bitmapshader;import Android.graphics.canvas;import Android.graphics.paint;import Android.graphics.paint.style;import Android.graphics.shader.tilemode;public class floor{/* * Floor position Game Panel height 4/5 to bottom */private static final float Floor_y_pos_ RADIO = 4/5f; Height of 4/5/** * x coordinate */private int x;/** * y coordinate */private int y;/** * Filler */private bitmapshader mfloorshader;private int mgamewidth;private int mgameheight;public floor (int gamewidth, int gameheight, Bitmap floorbg) {mgamewidth = Gamewidth ; mgameheight = Gameheight;y = (int) (gameheight * floor_y_pos_radio); mfloorshader = new Bitmapshader (FLOORBG, TileMode.RE Peat,tilemode.clamp);} /** * Draw Yourself * * @param mcanvas * @param mpaint */public void Draw (Canvas Mcanvas, Paint mpaint) {if (-x > Mgamewidth) {x = x% Mgamewidth;} Mcanvas.save (Canvas.matrix_save_flag);//Move toThe specified position is mcanvas.translate (x, y); Mpaint.setshader (Mfloorshader); mcanvas.drawrect (x, 0,-X + mgamewidth, mgameheight-y, Mpaint); Mcanvas.restore (); Mpaint.setshader (null);} public int GetX () {return x;} public void SetX (int x) {this.x = x;}}

Define a bunch of member variables, the core is that we pass in the floor background of the filler, and then initialize our mfloorshader, transverse repetition, longitudinal stretching (here the stretch refers to, the last pixel of the longitudinal repeatedly).

We announced the draw method, to the canvas, we first call Canvas.save (), and then move the canvas to the specified position, and then draw our rectangle, the rectangle's fill is our floor ~ ~;

Here, notice that we used a variable x here instead of 0; Because our floor needs to take advantage of this x movement.

So how can we move now?

First we define a variable in Gameflabbybird, which represents the moving speed mspeed, and then constantly update in draw Mfloor x coordinates: MFLOOR.SETX (Mfloor.getx ()-mspeed);

Such a painting, each time we draw the starting point of the floor, will move to the left mspeed position, it formed the effect of the operation; Can not always be reduced, or ultimately our x is not a negative infinity, how much to draw it?

So we:

if (-x > Mgamewidth)
{
x = x% Mgamewidth;
}

If the positive value of x is greater than the width, we take more than a minute ~ ~

In the end, our drawing range is:

Mcanvas.drawrect (x, 0,-X + mgamewidth, mgameheight-y, Mpaint);

OK, post the screening Gameflabbybird code:

Package Com.zhy.view;import Android.content.context;import Android.graphics.bitmap;import Android.graphics.bitmapfactory;import Android.graphics.canvas;import Android.graphics.paint;import Android.graphics.pixelformat;import Android.graphics.rectf;import Android.util.attributeset;import Android.util.log;import Android.view.surfaceholder;import Android.view.surfaceholder.callback;import Android.view.surfaceview;import Com.zhy.surfaceviewdemo.r;public class Copyofgameflabbybird extends SurfaceView Implements Callback,runnable{private Paint mpaint;/** * Flooring */private floor mfloor;private Bitmap mfloorbg;private int Mspe Ed;public Copyofgameflabbybird (Context context, AttributeSet Attrs) {Super (context, attrs); mpaint = new Paint (); Mpaint.setantialias (True); Mpaint.setdither (true); Initbitmaps ();//initialization Speed Mspeed = util.dp2px (GetContext (), 2);} /** * Initialize picture */private void Initbitmaps () {MFLOORBG = Loadimagebyresid (R.DRAWABLE.FLOOR_BG2);} private void Draw () {//drawsomething. DRAWBG ();d rawbird ();d Rawfloor ();//Update our floor drawing x-coordinate Mfloor.setx (Mfloor.getx ()-mspeed);} private void Drawfloor () {Mfloor.draw (Mcanvas, mpaint);} @Overrideprotected void onsizechanged (int w, int h, int oldw, int oldh) {//Initialize flooring Mfloor = new Floor (mwidth, Mheight, Mfloor BG);}}

In fact, it is very simple to declare a few variables, initialize it; Remember to update Mfloor x in draw.

Now the effect:


All right, finally there's a pipe left.


4. Draw Pipelines

Then it is to write a pipe class, note that our pipeline is divided into up and down, each pipe height may be different, so there will be more member variables;

Package Com.zhy.view;import Java.util.random;import Android.content.context;import android.graphics.bitmap;import Android.graphics.canvas;import android.graphics.rectf;/** * pipeline divided into upper and lower * * @author Zhy * */public class pipe{/** * distance between upper and lower pipe  */private static final Float Radio_between_up_down = 1/5f;/** * Maximum height of pipe on */private static final float radio_max_height = 2/5f;/** * Minimum height of upper pipe */private static final float radio_min_height = 1/5f;/** * Pipe's horizontal axis */private int x;/** * Upper Pipe height */ private int height;/** * distance between top and bottom pipe */private int margin;/** * pipe picture */private Bitmap mtop;/** * Bottom pipe picture */private Bitmap Mbot Tom;private static Random random = new random ();p ublic Pipe (context context, int gamewidth, int gameheight, Bitmap top,bit Map bottom) {margin = (int) (gameheight * radio_between_up_down);//default appears from leftmost x = Gamewidth;mtop = Top;mbottom = Bottom;rando Mheight (gameheight);}  /** * Randomly generates a height */private void randomheight (int gameheight) {height = random.nextint ((int) (Gameheight * (Radio_max_height- Radio_min_Height = (int) (height + gameheight * radio_min_height);} public void Draw (Canvas Mcanvas, RECTF rect) {mcanvas.save (Canvas.matrix_save_flag);//rect is the entire pipeline, assuming the full pipe is 100, you need to draw 20, Then offset 80mcanvas.translate (x,-(Rect.bottom-height)); Mcanvas.drawbitmap (mtop, NULL, rect, NULL);//Lower pipe, low volume, upper pipe height + Marginmcanvas.translate (0, (rect.bottom-height) + height + margin); Mcanvas.drawbitmap (Mbottom, NULL, rect, NULL); Mcanvas.restore ();} public int GetX () {return x;} public void SetX (int x) {this.x = x;}}

We look directly at the draw method, our incoming rect is a fixed rectangle, and our upper and lower pipes are all completely drawn in this rect;

Then, according to the height, to offset the canvas y, let rect show the height portion, mainly because, this can ensure that each pipe looks the same (if the use of different rect according to height, will produce scaling);

The pipe is written ~ ~ We need to use it in Gameflabbybird, but consider that the pipeline in the game is not like a bird or a ground, there are many, and it is constantly generating new in the Run ~ ~ ~

So we keep the Pipe, at least it's a list<pipe>.

The code after the screening:

public class Gameflabbybird extends Surfaceview implements Callback, runnable{/** * ********* piping related **********************  *//** * Pipe */private Bitmap mpipetop;private Bitmap mpipebottom;private RECTF mpiperect;private int mpipewidth;/** * Pipe width 60DP */private static final int pipe_width = 60;private list<pipe> mpipes = new arraylist<pipe> ();p ublic Game Flabbybird (context context, AttributeSet Attrs) {Super (context, attrs); mpipewidth = util.dp2px (GetContext (), Pipe_ WIDTH);} /** * Initialize picture */private void Initbitmaps () {; mpipetop = Loadimagebyresid (R.DRAWABLE.G2); mpipebottom = Loadimagebyresid ( R.DRAWABLE.G1);} private void Draw () {DRAWBG ();d rawbird ();d rawpipes ();d Rawfloor (); /** * Draw pipe */private void Drawpipes () {for (pipe pipe:mpipes) {Pipe.setx (Pipe.getx ()-Mspeed);p Ipe.draw (Mcanvas, Mpiperec t);}} /** * Initialize Dimension related */@Overrideprotected void onsizechanged (int w, int h, int oldw, int oldh) {super.onsizechanged (W, H, OLDW, OL DH);//Initialize the pipe range mpiperect = new RECTF (0, 0, mpipewidth, mheight); Pipe PIPE = new pipe (GetContext (), W, H, Mpipetop, Mpipebottom); Mpipes.add (Pipe);}} 

We initialized a pipe in the onsizechanged, added it to the mpipes, and then in draw, dynamically changing the pipe X to Pipe.setx (Pipe.getx ()-mspeed);

Here's a look at the effect:


Our pipeline enters the interface from the right, then disappears on the left side ~

Of course, there is much to be written about the pipeline, such as how far the pipeline is to generate one, and not allow infinite generation, when the pipeline from the interface should be removed from the mpipes;

And judging the collision of pipes and birds, these are placed in the next blog narrative ~ ~


5. Draw Fractions

The score is relatively simple to draw, I have prepared 10 graphs, corresponding to 0-9

No separate definition class, directly write ~ ~

The code after the screening:

public class Gameflabbybird extends Surfaceview implements callback,runnable{/** * Score */private final int[] mnums = new in T[] {r.drawable.n0, r.drawable.n1,r.drawable.n2, R.drawable.n3, R.drawable.n4, R.drawable.n5,r.drawable.n6, R.drawable.n7, R.drawable.n8, r.drawable.n9};p rivate bitmap[] mnumbitmap;private int mgrade = 100;/** * The height of a single digit 1/15 */PR Ivate static final Float radio_single_num_height = 1/15f;/** * Width of single digit */private int msinglegradewidth;/** * height of single digit */p rivate int msinglegradeheight;/** * Single number range */private RECTF msinglenumrectf;/** * Initialize picture */private void Initbitmaps () {MNumB Itmap = new Bitmap[mnums.length];for (int i = 0; i < mnumbitmap.length; i++) {Mnumbitmap[i] = Loadimagebyresid (MNums[i]) ;}} private void Draw () {//drawsomething. DRAWBG ();d rawbird ();d rawpipes ();d Rawfloor ();d rawgrades (); /** * Plot score */private void Drawgrades () {String grade = Mgrade + ""; Mcanvas.save (Canvas.matrix_save_flag); Mcanvas.translate (MWIDTH/2-grade.length () * MSINGLEGRADEWIDTH/2,1F/8 * Mheight);//Draw single num one by onefor (int i = 0; i < grade.length (); i++) {String numstr = grade.substring (i, i + 1); int num = integer.valueof (NUMSTR); Mcanvas.drawbitmap (Mnumbitmap[num], NULL, MSINGLENUMRECTF, NULL); Mcanvas.translate (msinglegradewidth, 0);} Mcanvas.restore ();} /** * Initialize Dimension related */@Overrideprotected void onsizechanged (int w, int h, int oldw, int oldh) {super.onsizechanged (W, H, OLDW, OL DH);//Initialize fraction msinglegradeheight = (int) (h * radio_single_num_height); msinglegradewidth = (int) (Msinglegradeheight * 1.0f /Mnumbitmap[0].getheight () * Mnumbitmap[0].getwidth ()) MSINGLENUMRECTF = new RECTF (0, 0, Msinglegradewidth, msinglegradeheight);}}

We define the range of a single number, and then assume that now is 100 points, notice in the drawing, the direct extraction of numbers, the number as subscript, to find the picture to draw;

Before drawing, according to the number of digits, the canvas is offset to the center position, and then drawn; During the drawing process, each drawing completes a number that offsets the width of a number;

Now the effect:


OK, so far, we have finished all the things we need to draw ~ ~ Because of the reason for space, the next article, will be on this basis to improve all the rest of the content ~ ~ ~

Interested, you can try to write directly on this basis ~ ~ ~



SOURCE Click to download



I built a QQ group, convenient for everyone to communicate. Group number:423372824

----------------------------------------------------------------------------------------------------------

Bo Master part of the video has been online, if you do not like boring text, please poke (first record, look forward to your support):

Video Directory Address: I recorded a video tutorial














Android Surfaceview take you to play flabby bird (on)

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.