开发一个 Flappy Bird 需要多少行代码,多少时间?
84 个回答
网上找到一篇文章,主场景300左右行代码,一天时间做出来,你信么?
原文链接: flappy bird游戏源代码揭秘和下载
————————————————————————————————————
背景:
最近火爆全球的游戏flappy bird让笔者叹为观止,于是花了一天的时间山寨了一个一模一样的游戏,现在把游戏的思路和源码分享出来,代码是基于javascript语言,cocos2d-x游戏引擎,cocos2d-x editor手游开发工具完成的,请读者轻砸;
ps:运行demo必须配置好cocos2d-x editor,暂不支持其他工具;
还有demo是跨平台的,可移植运行android,ios,html5移动系统等,csdn博客里会介绍代码如何移植,请持续关注;
Android Apk下载演示:
暂时先移植到android平台
下载地址: http:// share.weiyun.com/cac18d 8c58d40bf2401b3fdeeb6bcb2f
代码下载:
csdn下载: http:// download.csdn.net/detai l/touchsnow/6912707
百度云盘: http:// pan.baidu.com/s/1pJnWDb 9
金山快盘 : http://www. kuaipan.cn/file/id_2534 8935635745384.htm?source=1
代码如何移植到各平台:
Android: http:// blog.csdn.net/touchsnow /article/details/19176091
html5: http:// blog.makeapp.co/? p=245
效果图:


开发工具:
cocos2dx editor,它是开发跨平台的手机游戏工具,运行window/mac系统上,javascript脚本语言,基于cocos2d-x跨平台游戏引擎, 集合代码编辑,场景设计,动画制作,字体设计,还有粒子,物理系统,地图等等的,而且调试方便,和实时模拟;
cocos2dx editor下载,介绍和教程: http:// blog.csdn.net/touchsnow /article/details/19070665 ;
cocos2dx editor官方博客: http:// blog.makeapp.co/? cat=8 ;
思路和源码:
1 场景设计MainLayer.ccbx,如下图;主要分三层,开始场景、主场景、游戏结束场景,通过显示隐藏控制三个场景的切换。
MainLayer.ccbx代码
<?xml version="1.0" encoding="UTF-8"?>
<Document
jsControlled="true"
jsController="MainLayer"
resolution="default"
<Resolutions>
<Resolution centeredOrigin="false" ext="iphone" height="1280" width="720" name="default" scale="1"/>
<Resolution centeredOrigin="false" ext="iphone" height="720" width="1280" name="default1" scale="1"/>
</Resolutions>
<Animations>
<Animation autoPlay="true"
id="0"
name="Default Timeline"
length="10"
chainedId="0"
offset="0.0"
position="0.0"
resolution="30"
scale="128">
<CallbackChannel>
</CallbackChannel>
<SoundChannel>
</SoundChannel>
</Animation>
</Animations>
<Layer
positionX="0" positionY="0.0"
sizeType="Percent"
width="100" height="100"
anchorPointX="0.5" anchorPointY="0.5" ignoreAnchorPoint="true"
scaleX="1" scaleY="1"
<Sprite positionType="LeftBottom" width="720.0" height="1280.0" positionX="0" positionY="0" anchorPointX="0"
anchorPointY="0" src="Resources/bg.png" name="" var="" target="None" scaleX="1" scaleY="1" visible="true"/>
<LayerColor positionType="LeftBottom" width="720" height="1280" positionX="0" positionY="0" anchorPointX="0"
anchorPointY="0" color="#fff2e8ff" visible="false"/>
<Menu positionType="LeftBottom" width="40" height="40" positionX="356.0" positionY="237.0" anchorPointX="0.5"
anchorPointY="0.5" scaleX="2.4" scaleY="1.725">
</Menu>
<Sprite positionType="LeftBottom" width="840.0" height="281.0" positionX="0" positionY="0" anchorPointX="0"
anchorPointY="0" src="Resources/ground.png" var="ground" target="Doc"/>
<Node positionType="LeftBottom" width="40" height="40" positionX="800" positionY="250" anchorPointX="0"
anchorPointY="0" var="hoseNode" target="Doc">
<Sprite positionType="LeftBottom" width="86.0" height="60.0" positionX="-500" positionY="400" anchorPointX="0.5"
anchorPointY="0.5" src="Resources/flappy_packer.plist/bird3.png" var="test" target="Doc" visible="false"/>
<Sprite positionType="LeftBottom" width="86.0" height="60.0" positionX="-550" positionY="500" anchorPointX="0.5"
anchorPointY="0.5" src="Resources/flappy_packer.plist/bird1.png" var="bird" target="Doc" scaleX="1" scaleY="1" rotation="0" visible="true"/>
</Node>
<Node positionType="LeftBottom" width="40" height="40" positionX="303.0" positionY="500" anchorPointX="0.5"
anchorPointY="0.5" var="readyNode" target="Doc" visible="true">
<Sprite positionType="LeftBottom" width="508.0" height="158.0" positionX="95.0" positionY="584.0" anchorPointX="0.5"
anchorPointY="0.5" src="Resources/flappy_packer.plist/getready.png"/>
<Sprite positionType="LeftBottom" width="286.0" height="246.0" positionX="73.0" positionY="236.0" anchorPointX="0.5"
anchorPointY="0.5" src="Resources/flappy_packer.plist/click.png"/>
</Node>
<Node positionType="LeftBottom" width="40" height="40" positionX="300" positionY="500" anchorPointX="0.5"
anchorPointY="0.5" var="overNode" target="Doc" visible="true">
<Sprite positionType="LeftBottom" width="590.0" height="298.0" positionX="72.0" positionY="219.0" anchorPointX="0.5"
anchorPointY="0.5" src="Resources/flappy_packer.plist/base.png">
<Sprite positionType="LeftBottom" width="508.0" height="158.0" positionX="286.0" positionY="458.0" anchorPointX="0.5"
anchorPointY="0.5" src="Resources/flappy_packer.plist/gameover.png"/>
</Sprite>
<Menu positionType="LeftBottom" width="40" height="40" positionX="0" positionY="0" anchorPointX="0.5"
anchorPointY="0.5">
<MenuItem positionType="LeftBottom" width="290" height="176" positionX="-65.0" positionY="-92.0" anchorPointX="0.5"
anchorPointY="0.5" normalImage="Resources/flappy_packer.plist/start.png" target="Doc" onClick="onStartClicked"/>
<MenuItem positionType="LeftBottom" width="290" height="176" positionX="230.0" positionY="-92.0" anchorPointX="0.5"
anchorPointY="0.5" target="Doc" normalImage="Resources/flappy_packer.plist/grade.png" onClick="onGradeClicked"/>
</Menu>
</Node>
</Layer>
</Document>
2 代码编写MainLayer.js
首先,小鸟在向前飞,其实是底部的路和水管在向左移动,相对的你就感觉小鸟在向右飞了;路循环移动代码:
MainLayer.prototype.groundRun = function ()
var action1 = cc.MoveTo.create(0.5, cc.p(-120, 0));
var action2 = cc.MoveTo.create(0, cc.p(0, 0));
var action = cc.Sequence.create(action1, action2);
this.ground.runAction(cc.RepeatForever.create(action));
}
初始化高低不同的水管,每一关卡都由上下两水管和空隙组成。总长度相同,空隙也一定,随机取下面水管的长度,就形成错落有致的水管关卡;
MainLayer.prototype.newHose = function (num)
var hoseHeight = 830;
var acrossHeight = 300;
var downHeight = 100 + getRandom(400);
var upHeight = 1100 - downHeight - acrossHeight;
var hoseX = 400 * num;
var HoseName = FP_MAIN_TEXTURE.HOSE;
var ccSpriteDown = cc.Sprite.createWithSpriteFrameName(HoseName[0]);
ccSpriteDown.setZOrder(1);
ccSpriteDown.setAnchorPoint(cc.p(0, 0));
ccSpriteDown.setPosition(cc.p(hoseX, 0));
ccSpriteDown.setScaleY(downHeight / hoseHeight);
var ccSpriteUp = cc.Sprite.createWithSpriteFrameName(HoseName[1]);
ccSpriteUp.setZOrder(1);
ccSpriteUp.setAnchorPoint(cc.p(0, 0));
ccSpriteUp.setPosition(cc.p(hoseX, downHeight + acrossHeight));
ccSpriteUp.setScaleY(upHeight / hoseHeight);
this.hoseNode.addChild(ccSpriteDown);
this.hoseNode.addChild(ccSpriteUp);
this.hoseSpriteList.push(ccSpriteDown);
this.hoseSpriteList.push(ccSpriteUp);
return null;
}
一开始进入游戏让底部路不断移动,初始化水管,显示准备游戏场景;
MainLayer.prototype.onEnter = function ()
cc.AnimationCache.getInstance().addAnimations("Resources/flappy_frame.plist");
this.groundRun();
this.ground.setZOrder(10);
this.birdReadyAction();
this.bird.setZOrder(20);
this.readyNode.setVisible(true);
this.overNode.setVisible(false);
for (var i = 0; i < 30; i++) {
this.newHose(i);
}
点击屏幕,小鸟向上飞60dp,然后更快的速度下落(移动动画),同时闪动翅膀(帧动画);
MainLayer.prototype.birdRiseAction = function ()
var riseHeight = 60;
var birdX = this.bird.getPositionX();
var birdY = this.bird.getPositionY();
var time = birdY / 600;
var actionFrame = cc.Animate.create(cc.AnimationCache.getInstance().getAnimation("fly"));
var flyAction = cc.Repeat.create(actionFrame, 90000);
var riseAction1 = cc.MoveTo.create(0.2, cc.p(birdX, birdY + riseHeight));
var riseAction2 = cc.RotateTo.create(0, -30);
var riseAction = cc.Spawn.create(riseAction1, riseAction2);
var fallAction1 = cc.MoveTo.create(time, cc.p(birdX, 50));
var fallAction2 = cc.Sequence.create(cc.DelayTime.create(time / 6), cc.RotateTo.create(0, 30));
var fallAction = cc.Spawn.create(fallAction1, fallAction2);
this.bird.stopAllActions();
this.bird.runAction(cc.Spawn.create(
cc.Sequence.create(riseAction, cc.DelayTime.create(0.1), fallAction),
flyAction)
}
检测碰撞,如果小鸟碰到地面和水管,发生碰撞,这里碰撞直接用cocos2d-x 里面的图片和图片交叉函数 cc.rectIntersectsRect;
MainLayer.prototype.checkCollision = function ()
if (this.bird.getPositionY() < 60) {
cc.log("floor");
this.birdFallAction();
return;
for (var i = 0; i < this.hoseSpriteList.length; i++) {
var hose = this.hoseSpriteList[i];
if (!this.isInScreen(hose)) {
// continue;
if (cc.rectIntersectsRect(hose.getBoundingBox(), this.bird.getBoundingBox())) {
cc.log("hose positionX==" + hose.getBoundingBox().x);
cc.log("this.bird positionX==" + this.bird.getBoundingBox().x);
cc.log("i==" + i);
cc.log("birdFallAction");
this.birdFallAction();
return;
}
碰撞后,小鸟先下落,游戏结束场景显示;
MainLayer.prototype.birdFallAction = function ()
this.gameMode = OVER;
this.bird.stopAllActions();
this.ground.stopAllActions();
var birdX = this.bird.getPositionX();
var birdY = this.bird.getPositionY();
var time = birdY / 2000;
this.bird.runAction(cc.Sequence.create(
cc.DelayTime.create(0.1),
cc.Spawn.create(cc.RotateTo.create(time, 90), cc.MoveTo.create(time, cc.p(birdX, 50))))
this.overNode.setVisible(true);
}
游戏的难度主要在于多个水管的移动,小鸟触摸动画,检测碰撞;
再次提示代码下载地址:
csdn下载: http:// download.csdn.net/detai l/touchsnow/6912707
百度云盘: http:// pan.baidu.com/s/1pJnWDb 9
金山快盘 : http://www. kuaipan.cn/file/id_2534 8935635745384.htm?source=1
楼下有求图片的,地址: http:// share.weiyun.com/d73228 232bc0b1ff99f553afff58b7a2
更多内容: http:// blog.csdn.net/touchsnow /article/details/19071961
官方博客: http:// blog.makeapp.co/
联系笔者: zuowen@makeapp.co (邮箱)
想了解其他游戏开发可关注: 消灭星星(Popstar)游戏是怎么开发实现的?难不难?经常看到有人玩这个,很好奇里面的逻辑,拜求高手解答!
附录:其他游戏例子学习 http:// blog.csdn.net/touchsnow /article/details/19070665 ;





谢邀,如果使用我的那个简易引擎的话,只需要52行代码。
手机贴代码,回教室改成代码块。
(评论区居然有人问这是什么语言?还有人说是Scala?我吓到了,Scala不是def main吗啥时候变成fun main了)
引擎是我自己写的,Kotlin的,下面这段都是合法的Kotlin代码。具体怎么写,请参考我的发布文章。
引擎GitHub:
GitHub - icela/FriceEngine: An easy, light, native game engine running on JVMimport org.frice.dsl.game
fun main(args: Array<String>) = game {
title = "flappy bird demo by ice1000"
bounds {
x = 100
y = 100
width = 400
height = 500
whenExit { closeWindow() }
whenClicked {
tell("BlankJ") {
stop()
velocity { y = -300.0 }
accelerate { y = 10.0 }
oval {
name("BlankJ")
x = 30.0
y = 80.0
height = 50.0
width = height
color = BLUE
traits("block") {
x = 350.0
y = -50.0
width = 50.0
height = 200.0
velocity { x = -120.0 }
whenColliding("BlankJ") {
kill("BlankJ")
text { include("text") }
traits("text") {
x = 200.0
y = 200.0
text = "you lost"
every(1800) {
rectangle {
include("block")
height = 50 randomTo 250
rectangle {
include("block")
y = 300 randomTo 450
}
缩进已经补上了
代码结构层次非常清晰,引擎可以在我的文章列表里面看到
再贴一段和Flappy bird无关的代码,也是基于我的那个引擎的DSL系统的,我用它来讽刺中文编程:
import org.frice.dsl.*
* Created by ice1000 on 2016/10/29.
* @author ice1000
fun main(args: Array<String>) {
创建一个游戏窗口 {
一定要把尺寸设置成这样才好看(300, 300)
你特么给我把标题栏文字改成("我简直不知道中文编程有什么好玩的")
你特么倒是给我添加一个椭圆啊 {
name("老司机")
x = 60.0
y = 40.0
前进前进不择手段地前进 {
x = 10.0
y = 20.0
你特么倒是给我添加一个按钮啊 {
x = 20.0
y = 10.0
你特么倒是给我添加一个长方形啊 {
name("真·老司机")
当我被鼠标点击时千万不要忘记 {
告诉这个傻逼("老司机") {
每隔这么多秒一定要好好执行这个代码块喔(2000) {
弹出一个傻逼一样的提示窗口然后再傻逼地显示("我简直日了狗了")
当我退出历史的舞台时一定要记得 {
鎏金哇卡雅酷烈("真·老司机")
把它给我带来一顿痛日("老司机")
狗日的把这个傻逼的窗口给关了