In a antecedent tutorial, I absolved you through the action of authoritative your aboriginal “2D game.” We congenital a simple calligraphy which would let a appearance sprite animation about the screen. From there, I adumbrated it wouldn’t be too abundant assignment to about-face that into a abounding game.
I was cogent the truth! You could analysis out this commodity to add sensor abutment to your code and ascendancy your appearance by angry the phone and maybe go afterwards collectables on the screen. Or you could stick a billy at the bottom, some artery up top and accomplish a blemish game.
If the abstraction of developing a abounding bold still seems a little daunting, accede this your official allotment two. I’m action to appearance you how you can about-face this simple bold bend into a bold of Flappy Bird. Sure, I’m about three years late, but that’s appealing abundant my M.O..
This action is a little added avant-garde than what we’ve tackled recently, so body up to it. I acclaim our Java tutorial for beginners, and maybe this attainable algebraic bold to start. If you’re up for the challenge, let’s dive in. The end accolade will hopefully be commodity absolutely fun to comedy with lots of abeyant for added development. Getting there will accommodate some abundant acquirements opportunities.
See Also: hack instagramNote: The abounding cipher for this action can be begin here. If you would like to alpha from the banal 2D agent that we created aftermost time, again you can grab that cipher here.
For this post, the ahead mentioned commodity and video should be advised appropriate reading/viewing. To briefly recap, we congenital ourselves a canvas on which to draw our sprites and shapes, and we fabricated a abstracted cilia to draw to that afterwards blocking up the capital thread. This is our “game loop.”
We accept a chic alleged CharacterSprite which draws a 2D appearance and gives it some animated movement about the screen, we accept GameView which created the canvas, and we accept MainThread for the thread.
Go aback and apprehend that column to advance the basal agent for your game. If you don’t appetite to do that (well, aren’t you contrary?), you could aloof apprehend through this to apprentice some added skills. You could additionally arise up with your own band-aid for your bold bend and sprites. For instance, you can accomplish commodity agnate with a custom view.
In the update() adjustment of our CharacterSprite class, there’s an algorithm to animation the appearance all about the screen. We’re action to alter that with commodity abundant simpler:
If you recall, we had authentic yVelocity as 5, but we could change this to accomplish the appearance abatement faster or slower. The variable y is acclimated to ascertain the position of the amateur character, which agency it will now abatement slowly. We don’t appetite the appearance to move appropriate anymore, because we’re action to be scrolling the apple about ourselves instead.
This is how Flappy Bird is declared to work. By borer the screen, we can accomplish our appearance “flap” and thereby achieve some height.
As it happens, we already accept an overwritten onTouchEvent in our GameView class. Remember, this GameView is a canvas apparent in abode of the accepted XML blueprint book for our activity. It takes up the accomplished screen.
Pop aback into your CharacterSprite class and accomplish your yVelocity and your x and y coordinates into attainable variables:
This agency those variables will now be attainable from alfresco classes. In added words, you can admission and change them from GameView.
Now in the onTouchEvent method, artlessly say this:
Now wherever we tap our canvas, the appearance is action to acceleration by ten times the acceleration at which it is falling anniversary update. It’s important we accumulate this flappy-ness agnate to the abatement speed, so we can accept to change the force of force afterwards and accumulate the bold balanced.
I additionally added a few little touches to accomplish the bold a bit added Flappy Bird-like. I swapped out the blush of the accomplishments for dejected with this line:
I additionally drew myself a new bird appearance in Illustrator. Say hello.
He’s a alarming monstrosity.
We additionally charge to accomplish him decidedly smaller. I adopted a adjustment for shrinking bitmaps from user jeet.chanchawat on Stack Overflow.
Then you can use this band to amount the abate bitmap into your CharacterSprite object:
Finally, you may appetite to change the acclimatization of your app to landscape, which is accustomed for these types of games. Aloof add this band to the action tag in your manifest:
While this is all still appealing basic, we’re now starting to get commodity that looks a bit like Flappy Bird!
This is what coding looks like a lot of the time: about-face engineering, borrowing methods from conversations online, allurement questions. Don’t anguish if you aren’t accustomed with every Java statement, or if you can’t amount commodity out yourself. It’s generally bigger not to reinvent the wheel.
Now we accept a bird which avalanche to the basal of the awning unless we tap to fly. With the basal artisan sorted, all we charge to do is to acquaint our obstacles! To do that we charge to draw some pipes.
Since this is the aforementioned aqueduct adverse both ways, it is accessible to cast it by application the adjustment we adopted beforehand (we aloof set acme to a bare number). To accumulate things simple, we may as able-bodied use two abstracted images.
Now we charge to actualize a new chic and this chic is action to assignment aloof like the CharacterSprite class. This one is action to be alleged “PipeSprite.” It’s action to cede both pipes on the awning — one at the top and one at the bottom.
In Flappy Bird, pipes arise at altered heights and the claiming is aerial the bird up to fit through the gap for as continued as you can.
The acceptable account is that a chic can actualize assorted instances of the aforementioned object. In added words, we can accomplish as abounding pipes as we like, all set at altered heights and positions and all application a distinct allotment of code. The alone arduous allotment is administration the algebraic so we apperceive absolutely how ample our gap is! Why is this a challenge? Because it needs to band up accurately behindhand of the admeasurement of the awning it’s on. Accounting for all this can be a bit of a headache, but if you adore a arduous puzzle, this is area programming can absolutely get absolutely fun. It’s absolutely a acceptable brainy workout!
We fabricated the Flappy Bird appearance itself 240 pixels high. With that in mind, I anticipate 500 pixels should be a acceptable abundant gap — we could change this later.
If we now accomplish the aqueduct and the backward aqueduct bisected the acme of the screen, we can again abode a gap of 500 pixels amid them (pipe A will be positioned at the basal of the awning 250p, while aqueduct B will be at the top of the awning – 250p).
This additionally agency we accept 500 pixels to comedy with in added acme on our sprites. We can move our two pipes bottomward by 250 or up by 250 and the amateur won’t be able to see the edge. Maybe you ability appetite to accord your pipes a little added movement, but I’m blessed with befitting things nice and easy.
Now, it would be appetizing to do all this algebraic ourselves and aloof “know” our gap is 500p, but that’s bad programming. It agency we’d be application a “magic number.” Magic numbers are approximate numbers acclimated throughout your cipher which you are accepted to aloof remember. Back you arise aback to this cipher in a year’s time, will you absolutely bethink why you accumulate autograph -250 everywhere?
Instead we’ll accomplish a changeless accumulation – a amount that we won’t be able to change. We alarm this gapHeight and accomplish it according to 500. From now on, we can accredit to gapHeight or gapHeight/2 and our cipher will be abundant added readable. If we were actuality absolutely good, we’d do the aforementioned affair with our character’s acme and amplitude too.
Place this in the GameView method:
While you’re there, you could additionally ascertain the acceleration at which the bold will play:
You additionally accept the advantage to about-face that gapHeight capricious into a approved attainable integer, and accept it get abate as the bold progresses and the claiming ramps up — Your call! The aforementioned goes for the speed.
With all this in mind, we can now actualize our PipeSprite class:
The pipes will additionally move larboard on anniversary update, at the acceleration that we accept absitively for our game.
Back in the GameView method, we can actualize our article appropriate afterwards we actualize our amateur sprite. This happens in the surfaceCreated() adjustment but I’ve organized the afterward cipher into addition adjustment alleged makeLevel(), aloof to accumulate aggregate nice and tidy:
This creates three pipes in a row, set at altered heights.
The aboriginal three pipes will accept the exact aforementioned position anniversary time the bold starts, but we can randomize this later.
If we add the afterward code, again we can accomplish abiding the pipes move accurately forth and are redrawn aloof like our character:
There you accept it. There’s still a little way to go, but you aloof created your aboriginal scrolling sprites. Able-bodied done!
Now you should be able to run the bold and ascendancy your flappy bird as he flies affably accomplished some pipes. Appropriate now, they don’t affectation any absolute blackmail because we accept no blow detection.
That’s why I appetite to actualize one added adjustment in GameView to handle the argumentation and the “physics” such as they are. Basically, we charge to ascertain back the appearance touches one of the pipes and we charge to accumulate affective the pipes advanced as they abandon to the larboard of the screen. I’ve explained what aggregate does in comments:
That’s not the tidiest way of accomplishing things in the world. It takes up a lot of curve and it’s complicated. Instead we could add our pipes to a account and do this:
Not alone is this abundant cleaner code, but it additionally agency you can add as abounding altar as you like and your physics agent will still work. This will be actual accessible if you were authoritative some affectionate of platformer, in which case you’d accomplish this account attainable and add the new altar to it every time they were created.
Now run the bold and you should acquisition that it plays aloof like Flappy Bird. You’ll be able to move your appearance about the awning by borer and abstain pipes as they come. Fail to move in time and your appearance will respawn at the alpha of the sequence!
This is a absolutely anatomic Flappy Bird bold that hopefully hasn’t taken you too continued to put together. It aloof goes to appearance that Android Studio is a absolutely adjustable apparatus (that said, this tutorial shows how abundant easier bold development can be with an agent like Unity). It wouldn’t be that abundant of a amplitude for us to advance this into a basal platformer, or a bold of breakout.
If you appetite to booty this action further, there is affluence added to be done! This cipher needs added tidying. You can use that account in the resetLevel() method. You could use changeless variables for the appearance acme and width. You ability booty the acceleration and force out of the sprites and abode them in the argumentation method.
Obviously, there’s a lot added to be done to accomplish this bold absolutely fun, too. Giving the bird some drive would accomplish the gameplay far beneath rigid. Creating a chic to handle an on-screen UI with a top account would additionally help. Improving the antithesis of the claiming is a charge – maybe ramping up adversity as the bold progresses would help. The “hit box” for the appearance sprite is too ample area the angel cape off. If it were bottomward to me, I’d apparently additionally appetite to add some collectibles to the bold to actualize a fun “risk/reward” mechanic.
Recap
Making it flappy
Obstacles!
It’s alone logical
Going forward
y = yVelocity;
public int x, y; private int xVelocity = 10; public int yVelocity = 5;
characterSprite.y = characterSprite.y - (characterSprite.yVelocity * 10);
canvas.drawRGB(0, 100, 205);
public Bitmap getResizedBitmap(Bitmap bm, int newWidth, int newHeight) { int amplitude = bm.getWidth(); int acme = bm.getHeight(); float scaleWidth = ((float) newWidth) / width; float scaleHeight = ((float) newHeight) / height; // CREATE A MATRIX FOR THE MANIPULATION Cast cast = new Matrix(); // RESIZE THE BIT MAP matrix.postScale(scaleWidth, scaleHeight); // "RECREATE" THE NEW BITMAP Bitmap resizedBitmap = Bitmap.createBitmap(bm, 0, 0, width, height, matrix, false); bm.recycle(); acknowledgment resizedBitmap; }
characterSprite = new CharacterSprite(getResizedBitmap (BitmapFactory.decodeResource(getResources(),R.drawable.bird), 300, 240));
android:screenOrientation="landscape"
public changeless int gapHeigh = 500;
public changeless int acceleration = 10;
public chic PipeSprite { clandestine Bitmap image; clandestine Bitmap image2; attainable int xX, yY; clandestine int xVelocity = 10; clandestine int screenHeight = Resources.getSystem().getDisplayMetrics().heightPixels; attainable PipeSprite (Bitmap bmp, Bitmap bmp2, int x, int y) { angel = bmp; image2 = bmp2; yY = y; xX = x; } attainable abandoned draw(Canvas canvas) { canvas.drawBitmap(image, xX, -(GameView.gapHeight / 2) yY, null); canvas.drawBitmap(image2,xX, ((screenHeight / 2) (GameView.gapHeight / 2)) yY, null); } attainable abandoned update() { xX -= GameView.velocity; } }
Bitmap bmp; Bitmap bmp2; int y; int x; bmp = getResizedBitmap(BitmapFactory.decodeResource (getResources(), R.drawable.pipe_down), 500, Resources.getSystem().getDisplayMetrics().heightPixels / 2); bmp2 = getResizedBitmap(BitmapFactory.decodeResource (getResources(), R.drawable.pipe_up), 500, Resources.getSystem().getDisplayMetrics().heightPixels / 2); pipe1 = new PipeSprite(bmp, bmp2, 0, 2000); pipe2 = new PipeSprite(bmp, bmp2, -250, 3200); pipe3 = new PipeSprite(bmp, bmp2, 250, 4500);
public abandoned update() { characterSprite.update(); pipe1.update(); pipe2.update(); pipe3.update(); } @Override attainable abandoned draw(Canvas canvas) { super.draw(canvas); if(canvas!=null) { canvas.drawRGB(0, 100, 205); characterSprite.draw(canvas); pipe1.draw(canvas); pipe2.draw(canvas); pipe3.draw(canvas); } }
public abandoned logic() { //Detect if the appearance is affecting one of the pipes if (characterSprite.y < pipe1.yY (screenHeight / 2) - (gapHeight / 2) && characterSprite.x 300 > pipe1.xX && characterSprite.x < pipe1.xX 500) { resetLevel(); } if (characterSprite.y < pipe2.yY (screenHeight / 2) - (gapHeight / 2) && characterSprite.x 300 > pipe2.xX && characterSprite.x < pipe2.xX 500) { resetLevel(); } if (characterSprite.y < pipe3.yY (screenHeight / 2) - (gapHeight / 2) && characterSprite.x 300 > pipe3.xX && characterSprite.x < pipe3.xX 500) { resetLevel(); } if (characterSprite.y 240 > (screenHeight / 2) (gapHeight / 2) pipe1.yY && characterSprite.x 300 > pipe1.xX && characterSprite.x < pipe1.xX 500) { resetLevel(); } if (characterSprite.y 240 > (screenHeight / 2) (gapHeight / 2) pipe2.yY && characterSprite.x 300 > pipe2.xX && characterSprite.x < pipe2.xX 500) { resetLevel(); } if (characterSprite.y 240 > (screenHeight / 2) (gapHeight / 2) pipe3.yY && characterSprite.x 300 > pipe3.xX && characterSprite.x < pipe3.xX 500) { resetLevel(); } //Detect if the appearance has gone off the //bottom or top of the screen if (characterSprite.y 240 < 0) { resetLevel(); } if (characterSprite.y > screenHeight) { resetLevel(); } //If the aqueduct goes off the larboard of the screen, //put it advanced at a randomized ambit and height if (pipe1.xX 500 < 0) { Random r = new Random(); int value1 = r.nextInt(500); int value2 = r.nextInt(500); pipe1.xX = screenWidth value1 1000; pipe1.yY = value2 - 250; } if (pipe2.xX 500 < 0) { Random r = new Random(); int value1 = r.nextInt(500); int value2 = r.nextInt(500); pipe2.xX = screenWidth value1 1000; pipe2.yY = value2 - 250; } if (pipe3.xX 500 < 0) { Random r = new Random(); int value1 = r.nextInt(500); int value2 = r.nextInt(500); pipe3.xX = screenWidth value1 1000; pipe3.yY = value2 - 250; } } public abandoned resetLevel() { characterSprite.y = 100; pipe1.xX = 2000; pipe1.yY = 0; pipe2.xX = 4500; pipe2.yY = 200; pipe3.xX = 3200; pipe3.yY = 250; }
public abandoned logic() { Account pipes = new ArrayList<>(); pipes.add(pipe1); pipes.add(pipe2); pipes.add(pipe3); for (int i = 0; i < pipes.size(); i ) { //Detect if the appearance is affecting one of the pipes if (characterSprite.y < pipes.get(i).yY (screenHeight / 2) - (gapHeight / 2) && characterSprite.x 300 > pipes.get(i).xX && characterSprite.x < pipes.get(i).xX 500) { resetLevel(); } abroad if (characterSprite.y 240 > (screenHeight / 2) (gapHeight / 2) pipes.get(i).yY && characterSprite.x 300 > pipes.get(i).xX && characterSprite.x < pipes.get(i).xX 500) { resetLevel(); } //Detect if the aqueduct has gone off the larboard of the //screen and change added ahead if (pipes.get(i).xX 500 < 0) { Random r = new Random(); int value1 = r.nextInt(500); int value2 = r.nextInt(500); pipes.get(i).xX = screenWidth value1 1000; pipes.get(i).yY = value2 - 250; } } //Detect if the appearance has gone off the //bottom or top of the screen if (characterSprite.y 240 < 0) { resetLevel(); } if (characterSprite.y > screenHeight) { resetLevel(); } }
If you adore a arduous puzzle, this is area programming can absolutely get absolutely fun. And it's absolutely a acceptable brainy workout!
Comments
Post a Comment