fly flappy bird现在是一点都不新鲜了,当初热遍全球的时候,还是有好多人在仿制,各种语言都有……除了对技术的兴趣,还有的应该就是“看,我也有水平做出一个火遍世界的游戏,只是没动手罢了”这点小心思吧,(●’◡’●)
记得曾经在网上看过js版本的,用的库也各式各样,按说我这里有很多pygame的教程,用pygame写一个是正统,诚然也不难,但是我现在越来越觉得pygame过于底层,是的,没有精灵,没有动画,没有碰撞,甚至连基本的场景管理也没有,对于理解游戏底层原理挺合适,但是恐怕真的不适合现代化的游戏开发吧。
工作上,我前后端都做,html5和js接触颇多,虽说html5的效率一直被诟病,还还是有很多粉丝对h5的未来充满希望,个人虽然没有那么那么的乐观,但是看到h5能做的事情越来越多,还是很高兴的,尤其是h5开发游戏也慢慢变得实际起来了。
说到h5的游戏引擎,国内最热的应该是cocos2D-html5吧,还有就是原生DOM操作了……但是因为cocos2D用的人太多了,完全没有我们外行插足的余地,所以我选择了一个相对冷门的引擎“Phaser”来完成今天的功课。若问为什么选这个?因为Github上赞数1.2W啊(cocos才2k多的说)!
这次只有60行的版本,并不完整,只有一个游戏中的状态,没有开始和结束,但是只是为了演示,所以就这样吧,要求不能太高。
首先是html的骨架:
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Fly flappy bird</title>
<style>html,body{margin:0;padding:0}</style>
<script type="text/javascript" src="../libs/phaser.min.js"></script>
</head>
<body>
<script type="text/javascript" src="main.js"></script>
</body>
</html>
其次就是main.js的全部内容了,因为不少注释,看起来挺多,其实有效代码就60行左右。
// 初始化游戏,这里是游戏大小,并不一定与显示大小一致
var game = new Phaser.Game(768, 1024);
var gameState = {
preload: function() {
// 加载各种图像资源
game.load.spritesheet('bird', '../assets/flappy/bird.png', 92, 64);
game.load.image('pipe', '../assets/flappy/pipe.png');
game.load.image('background', '../assets/flappy/background.png');
game.load.image('ground', '../assets/flappy/ground.png');
},
create: function() {
// 设置背景
game.add.image(0, 0, 'background');
// 游戏画面在浏览器界面中居中
game.scale.scaleMode = Phaser.ScaleManager.SHOW_ALL;
game.scale.pageAlignHorizontally = true;
game.scale.pageAlignVertically = true;
// 开启物理引擎
game.physics.startSystem(Phaser.Physics.ARCADE);
// 初始化小鸟和其精灵动画
this.bird = game.add.sprite(game.world.centerX - 92, game.world.centerY, 'bird');
this.bird.anchor.setTo(-0.1, .5);
this.bird.animations.add('fly', [0, 1, 2]);
this.bird.animations.play('fly', 5, true);
// 开启碰撞
game.physics.arcade.enable(this.bird);
// 设置中立加速度
this.bird.body.gravity.y = 1000;
// 为所有的管子准备容器
this.pipes = game.add.group();
// 监听空格事件
var spaceKey = game.input.keyboard.addKey(Phaser.Keyboard.SPACEBAR);
spaceKey.onDown.add(this.jump, this);
// 显示得分(这里简单的使用增加列管道加一分的策略,所以有一分的延迟)
this.score = -1;
this.labelScore = game.add.text(380, 100, "0", { font: "bold 50pt Arial", fill: "#ffffff", aligen: 'center' });
this.labelScore.setShadow(5, 5, '#000000', 0);
// 增加移动的地面
this.ground = game.add.tileSprite(0, 896, 768, 128, 'ground');
// 定时增加管道
this.timer = game.time.events.loop(2500, this.addPipeRow, this);
},
jump: function() {
// 给小鸟一个向上的速度
this.bird.body.velocity.y = -400;
// 修正鸟头向上
game.add.tween(this.bird).to({angle: -20}, 100).start();
},
addPipe: function(x, y, d) {
// 增加管道的函数
var pipe = game.add.sprite(x, y, 'pipe');
// 管道有两个方向,我们只有一张图片,所以使用flip来制作开头向下的管道
if (d == 1) {
pipe.anchor.setTo(0, .5);
pipe.scale.y = -1;
pipe.y -= 396;
}
// 假如管道容器并开启碰撞检测,向左定速移动
this.pipes.add(pipe);
game.physics.arcade.enable(pipe);
pipe.body.velocity.x = -200;
// 管道在离开画面后自动销毁
pipe.checkWorldBounds = true;
pipe.outOfBoundsKill = true;
},
addPipeRow: function() {
// 随机生成障碍管道
var below = Math.round(Math.random() * 550) + 300;
this.addPipe(768, below);
this.addPipe(768, below - 250, 1);
// 增加并显示得分
this.score += 1;
this.labelScore.text = this.score;
},
restartGame: function() {
// 开始游戏
game.state.start('game');
},
// 每帧调用
update: function() {
// 判断太高太低的生死
if (this.bird.y < -100 || this.bird.y > 900) this.restartGame();
// 默认鸟头往下
if (this.bird.angle < 30) this.bird.angle += 1;
// 地面移动动画
this.ground.tilePosition.x -= 200 * (game.time.elapsed / 1000);
// 鸟与管道的碰撞检测,这里碰到了简单重新开始游戏
game.physics.arcade.overlap(this.bird, this.pipes, this.restartGame, null, this);
}
};
// 增加游戏状态并开始执行
game.state.add('game', gameState);
game.state.start('game');
链接一点开,小鸟儿就开始掉落了,请及时按空格拯救它……