http://www.gamefromscratch.com/post/2014/09/08/Guest-Tutorial-Making-Flappy-Bird-using-Overlap2D-and-LibGDX.aspx
github:https://github.com/azakhary/OverlappyBird
The following is a guest tutorial by Avetis showing how to use LibGDX and Overlap2D to create an Angry Birds like game. Overlap2D is a level and UI editor handy for separating game coding from content creation. Keep in mind, Overlap2D is fairly young, currently at 0.0.4 version. Now, on with the tutorial!
Making Flappy Bird with Overlap2D – Overlappy Tutorial
Agenda
In this tutorial we are going to create a FlappyBird clone game (for learning purposes only) using Java, LibGDX framework and accelerate it all by moving our UI, Level, and Asset management into Overlap2D Editor. One thing I figured while coding is that you can’t make a quick tutorial about a flappy bird clone, ever. It’s going to be long if we want details. It is easier though to use the explain approach instead of step by step guide. So I am going to share all the sources and resources, and then go with you through setting this all up, show how things work, and hopefully this all will make sense.
Prerequisites
Java knowledge, basic LibGDX experience, computer, time. Make sure you use latest Overlap2D editor and runtimes (v 0.0.4 or higher)
Get latest LibGDX project setup here: http://bitly.com/1i3C7i3 ( Details here )
Get latest Overlap2D editor here: http://overlap2d.com
First - Get Game Assets (Resources)
First let’s download the assets. I made a small pack of images I found on the internet with Flappy Bird images, animations and font. You can get it here: http://overlap2d.com/?p=236
Setting up Your Overlap2D Project
Unzip your Overlap2D zip file, and run the Overlap2D.jar.
First things first, you are currently viewing demo project, so go to File and Create New Project. Call it OverlappyBird and then create the scene size, let it be 480 width, 800 in height. It’s a standard small mobile device resolution, and since Flappy Bird is a portrait game, it should be just right. Click Create Project.
You have now created an empty project and it’s ready for setup, now you need to import the assets. Here we have 3 types of assets, first is just image textures, and second is a sprite animation for bird itself, and lastly the TTF font for score label. I have separated them in folders so you can import easily. Click on File, import to library.
First click on “…” button near the import images text field to select your images; locate them, select all. When done click on import and they all will get imported to your assets area on the right middle panel. Then open same the dialog again, and this time find Import Sprite Animations (note: not spine, but sprite) Click on “…” button there and locate bird.atlas file. Click Import, and it will get added to your assets list as well.
Lastly open import dialog again, and import font, by locating ttf file.
Your project setup is ready.
Making The Main Scene
First let’s see how main scene looks in Overlap2D when it is finished:
I decided to make several layers to have things organized, bg layer for background image that is not moving, default layer for pipes and bird itself, ground layer for moving the ground that is covering pipes, ui layer for “get ready” popups and score labels, and finally dlg layer for end game dialog. The reason I am not putting dialog inside ui layer is that I can position it in its layer correctly, and later hide that layer so it will not intervene with my work. So, go ahead and create this layers in the order I described from bottom to top. (bg layer goes below them all, and you can rearrange them by drag-and-dropping)
I also recommend you to open my example project (provided with resources). Open it with Overlap2D and see how things are positioned and grouped. (To open a project, click file, open, and then locate .pit file inside project.)
Compose your own project like I did,. Put background on bg layer, and add bird on default layer. Make sure it looks like the picture above.
The ground is going to be a moving part, so we need to have 2 of this near each other for seamless movement. Put two grounds near each other and then group them into composites, like on this picture, do not forget to give identifier to it for later use.
For the pipes we are going to do the following trick. First of all we are going to put pipes on top of each other with a gap, and convert them into composite, and then add to library to have kind of a prefab for a pipe column. Later in code we are going to pre-load 3 of this because there is never more than 3 columns of pipes visible on screen, so we can re-use the ones that are left of the screen for next pipe iteration.
Now some of the pipes are going to vary in position on Y axis. So there are a minimum and maximum values that it should not be below or above. To avoid having this values in code, I just put 2 of pipe columns on screen: one at the lowest point and the other at the highest, and give them identifiers in order to read those values from code later.
Next click on bird in properties box and add 2 custom variables, by clicking on custom variables button. First is jump_speed=400, and second is gravity=1000 (so you can later tweak game from editor not from code)
Next up, put a “hint” and “get ready” assets convert them into composite as they always go together and give them id to hide show from game. They should go to ui layer.
Making Menu Scene
This one is easier: click on File, Scenes, Create New Scene, and choose MenuScene as name.
Make sure to put up all things just like on this picture. And note that you should make a composite for ground agai n (as we do not yet share prefabs between the scenes).
Put a Play button as image and give it an id to add listeners later in your code.
Here is how it should look:
Overlap2D Part DONE!
Looks pretty good! Both scenes are set up and ready for some coding. Most importantly your scene and UI are very flexible and code-independent.
Setting up LibGDX Project and Getting Ready to Code:
Download the LibGDX setup application and setup an empty project (make sure to have checked box2d and freetype fonts), import it to your eclipse or other IDE, run the desktop app to make sure it works, then strip it from LibGDX picture and make it just a black screen.
Make sure your desktop launcher has code to specify screen size of 480x800 (config variables in launcher).
We are going to render everything using a simple LibGDX Stage, so the code structure will be the following: GameStage extending Stage that will load all the Overlap2D data and display it; Main class that will be rendering GameStage in its render method.
For all the rest we are going to use iScript functionality of Overlap2D. Let me go a bit in depth for that. Overlap2D runtime provides an interface that you can implement to create a “brain” of any composite item. Basically it is your way of attaching logic to an object. In this example we are going to create 3 iScripts, one is going to get attached to entire mainScreen and be a GameScreenScript with all game logic, other will be MenuScreenScript for menu, and the last one will be BirdScript that we will attach to the bird. It is important to mention that you cannot attach script to an image, or sprite animation, so I have converted bird animation to composite item in order to do it (right click, convert into composite).
You can find the full project on my github: https://github.com/azakhary/OverlappyBird
Here are the well commented sources:
OverlappyBird.java
package com.underwater.demo.overflappy; import com.badlogic.gdx.ApplicationAdapter; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.graphics.GL20; import com.badlogic.gdx.graphics.Texture; import com.badlogic.gdx.graphics.g2d.SpriteBatch; /* * This is our ApplicationListener the main thing that things start in libGDX */ public class OverflappyBird extends ApplicationAdapter { /* * GameStage will be holding both menu and main game */ private GameStage stage; @Override public void create () { stage = new GameStage(); } @Override public void render () { // Clearing the screen before each render Gdx.gl.glClearColor(0, 0, 0, 1); Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); // calling stage act method and passing delta time passed since last call stage.act(Gdx.graphics.getDeltaTime()); // drawing all actors stage.draw(); } }
GameStage.java
package com.underwater.demo.overflappy; import java.io.File; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.scenes.scene2d.Stage; import com.uwsoft.editor.renderer.DefaultAssetManager; import com.uwsoft.editor.renderer.SceneLoader; /* * GameStage */ public class GameStage extends Stage { // Speed of pixels per second of how fast things move left (required both for menu and the game, thus put here) public float gameSpeed = 200; // Overlap2D provides this easy asset manager that loads things as they are provided by default when exporting from overlap private DefaultAssetManager assetManager; public GameStage() { super(); // Set this is input processor so all actors would be able to listen to touch events Gdx.input.setInputProcessor(this); // Initializing asset manager assetManager = new DefaultAssetManager(); // providing the list of sprite animations which is one in this case, to avoid directory listing coding assetManager.spriteAnimationNames = new String[1]; assetManager. spriteAnimationNames[0] = "bird"; // loading assets into memory assetManager.loadData(); // Menu goes first initMenu(); } public void initMenu() { clear(); // Creating Scene loader which can load an Overlap2D scene SceneLoader menuLoader = new SceneLoader(assetManager); // loading MenuScene.dt from assets folder menuLoader.loadScene(Gdx.files.internal("scenes" + File.separator + "MenuScene.dt")); // Initializing iScript MenuSceneScript that will be holding all menu logic, and passing this stage for later use MenuScreenScript menuScript = new MenuScreenScript(this); // adding this script to the root scene of menu which is hold in menuLoader.sceneActor menuLoader.sceneActor.addScript(menuScript); // Adding root actor to stage addActor(menuLoader.sceneActor); } public void initGame() { clear(); // Creating Scene loader which can load an Overlap2D scene SceneLoader mainLoader = new SceneLoader(assetManager); // loading MainScene.dt from assets folder mainLoader.loadScene(Gdx.files.internal("scenes" + File.separator + "MainScene.dt")); // Initializing iScript GameSceneScript that will be holding all game, and passing this stage for later use GameScreenScript gameScript = new GameScreenScript(this, mainLoader); // adding this script to the root scene of game which is hold in mainLoader.sceneActor mainLoader.sceneActor.addScript(gameScript); // Adding root actor to stage addActor(mainLoader.sceneActor); } }
GameScreenScript.java
package com.underwater.demo.overflappy; import java.util.ArrayList; import com.badlogic.gdx.math.MathUtils; import com.badlogic.gdx.math.Vector2; import com.badlogic.gdx.scenes.scene2d.InputEvent; import com.badlogic.gdx.scenes.scene2d.Touchable; import com.badlogic.gdx.scenes.scene2d.actions.Actions; import com.badlogic.gdx.scenes.scene2d.actions.AddAction; import com.badlogic.gdx.scenes.scene2d.utils.ClickListener; import com.uwsoft.editor.renderer.SceneLoader; import com.uwsoft.editor.renderer.actor.CompositeItem; import com.uwsoft.editor.renderer.actor.LabelItem; import com.uwsoft.editor.renderer.script.IScript; /* * iScript for entire game logic */ public class GameScreenScript implements IScript { /* * reference to GameStage */ private GameStage stage; /* * Main actor that holds root of game screen */ private CompositeItem game; // Screen loader reference to be later used to retrieve prefabs from library private SceneLoader loader; // Game over Dialog actor private CompositeItem gameOverDlg; /* * this will be holding 2-ground system composite item */ private CompositeItem groundRotator; /* * Instead of holding bird actor we are going to hold birdscript that will provide all bird logic and methods. * Also it will have bird actor inside */ private BirdScript bird; // Hint Box actor the one that shown in begining of game private CompositeItem hintBox; // some helping booleans private boolean gameStarted = false; private boolean groundStop = false; // going to hold what is the possible low and high position for a pipe column private float minPipe; private float maxPipe; private int gameScore = 0; private LabelItem scoreLbl; // Going to hold 3 pipes here to reuse as pipe pool private ArrayList<CompositeItem> pipes = new ArrayList<CompositeItem>(); public GameScreenScript(GameStage stage, SceneLoader loader) { this.stage = stage; this.loader = loader; } @Override public void init(CompositeItem gameItem) { game = gameItem; gameScore = 0; // Creating and holding BirdScript that will hold entire bird logic. bird = new BirdScript(stage); game.getCompositeById("bird").addScript(bird); groundRotator = game.getCompositeById("groundRotator"); hintBox = game.getCompositeById("hintBox"); scoreLbl = game.getLabelById("scoreLbl"); // Adding listeners to listen for taps to make bird jump game.addListener(new ClickListener() { public boolean touchDown (InputEvent event, float x, float y, int pointer, int button) { return true; } public void touchUp (InputEvent event, float x, float y, int pointer, int button) { // screen tap was done screenTap(); } }); // Loading min/max positions from level editor minPipe = game.getCompositeById("minPipe").getY(); maxPipe = game.getCompositeById("maxPipe").getY(); // Retrieving 3 pipe columns from library putting them into array, // and adding on screen in minus coordinates so the will becom "availible" for(int i = 0; i < 3; i++) { CompositeItem pipe = loader.getLibraryAsActor("pipeGroup"); pipe.setX(-pipe.getWidth()); game.addItem(pipe); pipes.add(pipe); } // Making sure first pipe will be added not sooner then 3 seconds from now game.addAction(Actions.sequence(Actions.delay(3.0f), Actions.run(new Runnable() { @Override public void run() { putPipe(); } }))); // hiding game over dialog gameOverDlg = game.getCompositeById("gameOverDlg"); // it should not listen for taps gameOverDlg.setTouchable(Touchable.disabled); gameOverDlg.setVisible(false); } @Override public void act(float delta) { // if game is not yet started or started (but most importantly not ended, ground is moving) if(!groundStop) { groundRotator.setX(groundRotator.getX() - delta * stage.gameSpeed); if(groundRotator.getX() < -groundRotator.getWidth()/2) groundRotator. setX(0); } // if game is started, so first tap fone, then we dhould check for collisions and move pipes if(gameStarted) { for(int i = 0; i < pipes.size(); i++) { // get pipe CompositeItem pipe = pipes.get(i); // move it if it has positive coordinate if(pipe.getX() > -pipe.getWidth()) { // if pipe was right of thebird, and will now become left of the bird, add to score if(pipe.getX() >= bird.getBirdCenter().x && pipe.getX() - delta * stage.gameSpeed < bird.getBirdCenter().x) { gameScore++; } pipe.setX(pipe.getX() - delta * stage.gameSpeed); } //check for collision with bird collisionCheck(); } } // update scorel label scoreLbl.setText(gameScore+""); } /* * Check for bird versus pipe row collision */ private void collisionCheck() { // iterate through all 3 pipes for(int i = 0; i < pipes.size(); i++) { CompositeItem pipe = pipes.get(i); // to make it easy going to think about bird as circle with 5 radius Vector2 birdPoint = bird.getBirdCenter(); // Is there collision? if yes stop the game and allow bird to fall if(birdPoint.x+5 > pipe.getX() && birdPoint.x - 5 < pipe.getX() + pipe. getWidth() && (pipe.getY() + 532 > birdPoint.y - 5 || pipe.getY()+ 701 < birdPoint.y + 5)) { stopGame(); } // Did bird hit the ground? not only stop the game but also // disable gravity to keep from further falling, and consider bird dead ( animations stop ) if(birdPoint.y-5 < groundRotator.getY()+groundRotator.getHeight()) { if(!groundStop) { stopGame(); } bird.disableGravity(); bird.getBird().setY(groundRotator.getY()+groundRotator.getHeight()+5) ; // killitwithfire bird.die(); } } } /* * Stops the game */ private void stopGame() { gameStarted = false; groundStop = true; game.clearActions(); // show end game dialog showEndDialog(); } /* * showing end game dialog */ public void showEndDialog() { // enabling touch back, showing gameOverDlg.setTouchable(Touchable.enabled); gameOverDlg.setVisible(true); // setting transparency to full gameOverDlg.getColor().a = 0; // and fading it in gameOverDlg.addAction(Actions.fadeIn(0.4f)); // setting play button listener to replay the game gameOverDlg.getImageById("playBtn").addListener(new ClickListener() { public boolean touchDown (InputEvent event, float x, float y, int pointer, int button) { return true; } public void touchUp (InputEvent event, float x, float y, int pointer, int button) { stage.initGame(); } }); } /* * Called when screen is tapped */ private void screenTap() { // if ground is not moving then bird is dead no actin required on tapp if(groundStop) return; // if game started just jump the bird if(gameStarted) { bird.jump(); } else { // if game is not yet started, start the game and jump the bird gameStarted = true; hintBox.addAction(Actions.fadeOut(0.3f)); // and also enable gravity from now on bird.enableGravity(); bird.jump(); } } /* * get's availible pipe * availible pipe is any pipe that is left of screen and not visible */ public CompositeItem getAvailablePipe() { for(int i = 0; i < pipes.size(); i++) { if(pipes.get(i).getX() <= -pipes.get(i).getWidth()) { return pipes.get(i); } } return null; } /* * this is called every X time to put a new pipe on the right */ public void putPipe() { // getting availible pipe CompositeItem pipe = getAvailablePipe(); // when you die at bad moment, it can be null sometimes if(pipe == null) return; // put pipe column on the random hight from min to max range pipe.setX(stage.getWidth()); pipe.setY(MathUtils.random(minPipe, maxPipe)); // schedule next pipe to be put in 1.3 seconds game.addAction(Actions.sequence(Actions.delay(1.3f), Actions.run(new Runnable() { @Override public void run() { // call itself putPipe(); } }))); } }
MenuScreenScript.java
package com.underwater.demo.overflappy; import com.badlogic.gdx.math.MathUtils; import com.badlogic.gdx.scenes.scene2d.InputEvent; import com.badlogic.gdx.scenes.scene2d.utils.ClickListener; import com.uwsoft.editor.renderer.actor.CompositeItem; import com.uwsoft.editor.renderer.actor.ImageItem; import com.uwsoft.editor.renderer.actor.SpriteAnimation; import com.uwsoft.editor.renderer.script.IScript; /* * iScript for menu logic */ public class MenuScreenScript implements IScript { /* * reference to GameStage */ private GameStage stage; /* * this is the main root menu actor to work with */ private CompositeItem menu; /* * this will be holding 2-ground system composite item */ private CompositeItem groundRotator; /* * this will be the bird sprite animation displayed in center of screen */ private SpriteAnimation bird; // this variables are used to wiggle bird up and down with sin function private float iterator = 0; private float birdInitialPos; public MenuScreenScript(GameStage stage) { this.stage = stage; } public void init(CompositeItem menuItem) { menu = menuItem; // Finding playButton by id and storing in variable ImageItem playBtn = menuItem.getImageById("playBtn"); // Finding ground composite and storing in variable groundRotator = menuItem.getCompositeById("groundRotator"); // Finding bird and storing in variable bird = menuItem.getSpriteAnimationById("bird"); // let's remember where bird was initially birdInitialPos = bird.getY(); // Adding a Click listener to playButton so we can start game when clicked playBtn.addListener(new ClickListener() { // Need to keep touch down in order for touch up to work normal (libGDX awkward ness) public boolean touchDown (InputEvent event, float x, float y, int pointer, int button) { return true; } public void touchUp (InputEvent event, float x, float y, int pointer, int button) { // when finger is up, ask stage to load the game stage.initGame(); } }); } /* * This is called every frame */ public void act(float delta) { // moving ground left with game speed multiplied by delta as delta shows what part of second was passed since last call groundRotator.setX(groundRotator.getX() - delta * stage.gameSpeed); // if ground rotator got half way left, we can just put it back to 0, and to eye it will look like it endlessly moves if(groundRotator.getX() < -groundRotator.getWidth()/2) groundRotator.setX( 0); // Now this part is to wiggle bird up and down, we are going change iterator based on time passed iterator += delta*400; // Then figure out the bird offset from it's original position based on iterator which is based on time passed, and do it with sinus function float birdOffset = MathUtils.sinDeg(iterator)*5; // put bird on it's original pos + offset bird.setY(birdInitialPos + birdOffset); } }
BirdScript.java
package com.underwater.demo.overflappy; import com.badlogic.gdx.math.MathUtils; import com.badlogic.gdx.math.Vector2; import com.uwsoft.editor.renderer.actor.CompositeItem; import com.uwsoft.editor.renderer.actor.SpriteAnimation; import com.uwsoft.editor.renderer.script.IScript; /** * Bird Script * @author azakhary * This is brain of the bird, it's physics and everything */ public class BirdScript implements IScript { /* * reference to GameStage */ private GameStage stage; // Bird composite item actor private CompositeItem bird; // Inside bird composite actor there is the bird sprite animation actor private SpriteAnimation birdAnimation; // used to wiggle the bird in the air using Sine function private float iterator = 0; // current vertical velocity of the bird private float currVerticalVelocity = 0; // boolean to know if gravity is enabled or not private boolean isGravityEnabled = false; // to avoid jumping to rotation bird will try to always rotate a bit towards desired rotation private float desiredRotation; // is it alive? private boolean isAlive = true; public BirdScript(GameStage stage) { this.stage = stage; } @Override public void init(CompositeItem item) { bird = item; // find animation from the composite birdAnimation = bird.getSpriteAnimationById("birdAnimation"); // set origin of the bird in it's center, so it will rotate normally bird.setOrigin(bird.getWidth()/2, bird.getHeight()/2); // set desired rotation to current rotation which is 0 desiredRotation = bird.getRotation(); } @Override public void act(float delta) { if(!isGravityEnabled && isAlive) { // Wiggling when no gravity only iterator += delta*400; float birdOffset = MathUtils.sinDeg(iterator)*5; birdAnimation.setY(birdOffset); } // aplying gravity every frame gravity(delta); // moving to new position based on current vertical velocity bird.setY(bird.getY() + delta*currVerticalVelocity); // manage bird rotation based on it's vertical speed manageRotation(delta); } /* * manage bird rotation based on it's vertical speed * this is a part of code that is not interesting boring and whatever.. */ private void manageRotation(float delta) { if(isGravityEnabled) { if(currVerticalVelocity > -200) { float rotation = currVerticalVelocity+200; desiredRotation = rotation/15f; } if(currVerticalVelocity <= -200) { float rotation = currVerticalVelocity+200; if(rotation < -400) rotation = -400; desiredRotation = rotation/4.4f; } if(desiredRotation != bird.getRotation()) { if(desiredRotation > bird.getRotation()) { bird.setRotation(bird.getRotation() + 900*delta); if(desiredRotation < bird.getRotation()) bird.setRotation( desiredRotation); } if(desiredRotation < bird.getRotation()) { bird.setRotation(bird.getRotation() - 900*delta); if(desiredRotation > bird.getRotation()) bird.setRotation( desiredRotation); } } } } public void enableGravity() { isGravityEnabled = true; } public void disableGravity() { isGravityEnabled = false; } public void jump() { // if bird is dead do not jump (I think I checked it somewhere already) if(!isAlive) return; // if bird is higher then screen then do not jump if(bird.getY() > stage.getHeight()) return; // if jumped get the custom variable jump_speed from bird actor and set it as current vertical velocity currVerticalVelocity = bird.getCustomVariables().getFloatVariable( "jump_speed"); } /* * Apply gravity each frame (get's delta time since last frame) */ private void gravity(float delta) { if(isGravityEnabled) { // change curernt velocity based on gravity (gravity changes velocity every second by gravity amount) currVerticalVelocity -= delta*bird.getCustomVariables(). getFloatVariable("gravity"); } } public CompositeItem getBird() { return bird; } // get's the bird center coordinates as vector 2 needed for collision detection in GameScreenScript public Vector2 getBirdCenter() { Vector2 vec = new Vector2(bird.getX() + bird.getWidth()/2, bird.getY() + bird.getHeight()/2); return vec; } // Kills the bird, for reals public void die() { currVerticalVelocity = 0; isAlive = false; desiredRotation = 0; bird.setRotation(0); birdAnimation.pause(); } }
相关推荐
《Libgdx版本FlappyBird:使用Libgdx引擎创建移动游戏》 Libgdx是一个强大的开源游戏开发框架,专为跨平台游戏设计,支持Windows、Linux、Mac OS X、Android以及HTML5等多个平台。本项目"Libgdx版本FlappyBird"是一...
在《简单小游戏Flappy Bird制作》的相关博客中,开发者可能会详细讲解如何将这些图像和音频资源集成到游戏引擎中,如使用Unity、Cocos2d-x或者纯HTML5 Canvas等。他们会介绍如何设置精灵(Sprite)和动画,如何处理...
《Flappy Bird游戏素材解析:图像与音效的全方位探讨》 Flappy Bird,这款曾经风靡全球的小游戏,以其简单却极具挑战性的玩法吸引了无数玩家。在学习游戏开发的过程中,掌握并理解游戏素材——尤其是图像和音效——...
《flappy bird》是一款由来自越南的独立游戏开发者Dong Nguyen所开发的作品,游戏于2013年5月24日上线,并在2014年2月突然暴红。2014年2月,《Flappy Bird》被开发者本人从苹果及谷歌应用商店撤下。2014年8月份正式...
《Flappy Bird游戏素材解析与应用》 Flappy Bird是一款风靡全球的休闲游戏,以其简单易上手的操作和极具挑战性的玩法深受玩家喜爱。在本文中,我们将深入探讨这款游戏中的一些关键素材,并通过提供的压缩包文件,...
在这个名为“OpenCv制作的FlappyBird”的项目中,开发者利用OpenCV技术实现了一个经典游戏FlappyBird的版本。下面我们将详细探讨OpenCV在该项目中的应用以及相关知识点。 首先,我们要理解OpenCV的基本概念。OpenCV...
《Flappy Bird源代码、贴图与音效详解——Unity游戏开发深度剖析》 Flappy Bird,这款在2014年风靡全球的小游戏,以其简单却极具挑战性的玩法吸引了无数玩家。对于长安大学的学生,尤其是那些正在学习游戏动画开发...
《Flappy Bird基于Cocos2d-x 3.8的游戏开发详解》 Flappy Bird是一款在移动设备上风靡一时的简单却极具挑战性的游戏,它的成功在于其极简的设计和难以掌握的游戏机制。本教程将详细介绍如何使用Cocos2d-x 3.8框架来...
《Flappy Bird游戏资源与开发解析》 在游戏开发领域,Unity引擎因其强大的功能和易用性而备受青睐,尤其对于初学者来说,它是一个极好的起点。本篇将深入探讨利用Unity进行游戏开发,以Flappy Bird为案例,同时延伸...
经典网红游戏FlappyBird美术及音频素材下载,包含音频和图片素材,仅用于学习和交流。Godot版FlappyBird开发教程CSDN地址:https://blog.csdn.net/ttm2d/article/details/104516098
《Flappy Bird游戏素材与源码解析》 Flappy Bird是一款简单却极具挑战性的移动平台游戏,由越南开发者Dong Nguyen开发。它以其独特的游戏机制和极高的难度在全球范围内引起了热潮。在这里,我们拥有的是自己制作的...
《Flappy Bird游戏制作资源素材详解》 Flappy Bird,这款简单却又极具挑战性的手机游戏,在全球范围内引发了一股热潮。对于游戏开发者来说,了解并掌握其制作资源和素材是至关重要的一步。本资源包主要包含了Flappy...
《FlappyBird游戏源码解析》 FlappyBird是一款风靡全球的休闲小游戏,以其简单易上手的操作和高难度的挑战性吸引了大量玩家。本文将深入探讨cocos2dx和Unity两个版本的游戏源码,解析其背后的编程原理和技术实现。 ...
《Flappy Bird游戏开发:深度解析素材与学习资源》 Flappy Bird,这款看似简单却让人上瘾的小游戏,自2013年发布以来,就吸引了无数玩家和开发者的眼球。它的成功在于其直观的操作方式和极具挑战性的游戏机制。本篇...
Flappy Bird的像素艺术图形是通过Java的Graphics2D类进行绘制的。动画效果如鸟的翅膀摆动和管道的滚动,通过改变图像的位置来实现,这种技术称为“精灵动画”(Sprite Animation)。 四、物理模拟 虽然Flappy Bird...
《Flappy Bird游戏素材资源详解》 在游戏开发领域,Flappy Bird是一款极其经典且具有极高人气的小游戏,它的简洁设计和挑战性吸引了无数玩家。本资源包是针对这款热门游戏——Flappy Bird的素材资源集合,包含了...
flappybird游戏资源,图片+音效
flappy bird 图片素材,就没有放代码了,这是我初学时候的素材。 flappy bird是一款简易却难度极高的休闲游戏。简单并不粗糙的8比特像素画面、超级玛丽游戏中的绿色通道、眼神有点呆滞的小鸟和几朵白云便构成了游戏...
本实训报告详细阐述了基于Android平台的《FlappyBird》小游戏的开发过程,旨在提升学员在移动游戏开发和多媒体技术应用方面的能力。游戏设计简单,玩家通过点击屏幕控制小鸟飞行,避开不断出现的固定间距管道,得分...
在本项目"Libgdx(包含box2d)开发的PC版、Android版Flappy Bird"中,开发者使用了Libgdx来重制经典游戏Flappy Bird,以展示Libgdx的功能和Box2D物理引擎的应用。 首先,我们来了解一下Libgdx。Libgdx是一个用Java...