一、游戏玩法介绍:
- 跳一跳使用手指按压屏幕蓄力;
- 根据力量大小控制小 i 来跳跃;
- 跳到下一个盒子上后积分累加;
- 落到下一个盒子之外游戏结束。
二、新建项目:
1. 新建 EUI 项目:
2. 游戏场景分析:
3. 加入图片资源。
三、创建游戏开始场景:
4. 分别在 resource 目录和 src 目录创建 scene 文件夹,并创建 EUI 组件 BeginScene:
5. 游戏开始场景 BeginScene 的布局
四、创建游戏场景界面:
6. 创建 EUI 组件 GameScene.ts:
7. 在 GameScene.exml 中实现布局:
-
image 组件设置背景图 bg_png,并填充上下左右; -
添加容器组件 Group,设置 ID:blockPanel,同样填充上下左右: -
在容器内添加 Label 组件,这是 ID:scoreLabel; -
在容器内添加 image 组件,这是 ID:player;
8. 创建场景控制器 SceneManager类,并把它设计成单例:
private static shared: SceneManager;
public static Shared(): SceneManager {
if(!SceneManager.shared) {
SceneManager.shared = new SceneManager();
}
return SceneManager.shared;
}
private beginScene: BeginScene;
private gameScene: GameScene;
- 修改 SceneMangager 控制器为容器,以便于在 Main.ts 的 createGameScene 创建场景界面添加此控制器:
class SceneManager extends egret.Sprite{}
- 在 Main.ts 的 createGameScene() 方法内添加场景控制器:
protected createGameScene(): void {
this.addChild(SceneManager.Shared());
}
- 在 SceneManger.ts 中实现初始化方法,实现数据初始化:
public constructor() {
super(); this.init();
}
private init() {
this.beginScene = new BeginScene();
this.gameScene = new GameScene();
this.addChild(this.beginScene);
}
public changeScene(type) {
if(type == 'gameScene') {
this.beginScene.release();
}
this.removeChildren();
this.addChild(this.gameScene);
}
- 注意:在 BeginScene.ts 内,release 方法是用来解绑按钮点击事件:
public release() {
if(this.beginBtn.hasEventListener(egret.TouchEvent.TOUCH_TAP)) {
this.beginBtn.removeEventListener(
egret.TouchEvent.TOUCH_TAP,
this.tapHandler,
this);
}
}
9. 为游戏开始场景绑定点击方法,在 BeginScene.ts 中复制自定义粘贴开始按钮:
public beginBtn:eui.Button;
protected childrenCreated():void {
super.childrenCreated();
this.init();
}
private init() {
this.beginBtn.addEventListener(
egret.TouchEvent.TOUCH_TAP,
this.tapHandler,
this
);
}
private tapHandler() {
SceneManager.Shared().changeScene('gameScene');
}
10. 在 GameScene.ts 中复制自定义属性:
public blockPanel:eui.Group;
public scoreLabel:eui.Label;
public player:eui.Image;
- 使用工厂设计模式来创建盒子方块(回收 / 复用):
private blockSourceNames: Array<string> = [];
private blockArr: Array<eui.Image> = [];
private reBackBlockArr: Array<eui.Image> = [];
private createBlock(): eui.Image {
var blockNode: eui.Image = null;
if(this.reBackBlockArr.length) {
blockNode = this.reBackBlockArr.splice(0,1)[0];
}else {
blockNode = new eui.Image();
}
let n = Math.floor(Math.random() * this.blockSourceNames.length);
blockNode.source = this.blockSourceNames[n];
this.blockPanel.addChild(blockNode);
blockNode.anchorOffsetX = 222;
blockNode.anchorOffsetY = 78;
this.blockArr.push(blockNode);
return blockNode;
}
- 初始化方法,定义音频变量,在初始化方法里加载音频:
private pushVoice: egret.Sound;
private jumpVoice: egret.Sound;
- 绑定手指按下屏幕和放开的事件;
- 设置玩家的锚点,选中底部圆心点的位置为锚点;
protected childrenCreated():void {
super.childrenCreated();
this.init();
}
private init() {
this.blockSourceNames = ['block1_png','block2_png','block3_png'];
this.pushVoice = RES.getRes('push_mp3');
this.jumpVoice = RES.getRes('jump_mp3');
this.blockPanel.touchEnabled = true;
this.blockPanel.addEventListener(
egret.TouchEvent.TOUCH_TAP,
this.onKeyDown,
this
);
this.blockPanel.addEventListener(
egret.TouchEvent.TOUCH_END,
this.onKeyUp,
this
);
this.player.anchorOffsetX = this.player.width / 2;
this.player.anchorOffsetY = this.player.height - 20;
}
public direction: number = 1;
public reset() {
this.blockPanel.removeChildren();
this.blockArr = [];
let blockNode = this.createBlock();
blockNode.touchEnabled = false;
blockNode.x = 200;
blockNode.y = this.height / 2 + blockNode.height;
this.currentBlock = blockNode;
this.player.x = this.currentBlock.x;
this.player.y = this.currentBlock.y;
this.blockPanel.addChild(this.player);
this.blockPanel.addChild(this.scoreLabel);
this.direction = 1;
this.addBlock();
}
public tanAngle: number = 0.55604719640118;
private targetPos: egret.Point;
private addBlock() {
let blockNode = this.createBlock();
let distance = this.minDistance + Math.random()*(this.maxDistance - this.minDistance);
if(this.direction > 0) {
blockNode.x = this.currentBlock.x + distance;
blockNode.y = this.currentBlock.y - distance*this.tanAngle;
}else {
blockNode.x = this.currentBlock.x - distance;
blockNode.y = this.currentBlock.y - distance*this.tanAngle;
}
this.currentBlock = blockNode;
}
private onKeyDown() {
this.pushSoundChannel = this.pushVoice.play(0,1);
egret.Tween.get(this.player).to({
scaleY: 0.5
}, 3000);
this.isReadyJump = true;
}
private onKeyUp() {
if(!this.isReadyJump) {
return;
}
if(!this.targetPos) {
this.targetPos = new egret.Point();
}
this.blockPanel.touchEnabled = false;
this.pushSoundChannel.stop();
this.jumpVoice.play(0,1);
egret.Tween.removeAllTweens();
this.blockPanel.addChild(this.player);
this.isReadyJump = false;
this.targetPos.x = this.player.x + this.jumpDistance * this.direction;
this.targetPos.y = this.player.y + this.jumpDistance * (this.currentBlock.y - this.player.y)/(this.currentBlock.x - this.player.x) * this.direction;
egret.Tween.get(this).to({factor: 1}, 500).call(() => {
this.player.scaleY = 1;
this.jumpDistance = 0;
});
this.player.anchorOffsetY = this.player.height / 2;
egret.Tween.get(this.player).to({rotation: this.direction > 0 ? 360 : -360}, 200).call(() => {
this.player.rotation = 0;
}).call(() => {
this.player.anchorOffsetY = this.player.height - 20;
});
}
五、小人跳跃轨迹:
11. 运动轨迹的表示:
public get factor(): number {
return 0;
}
public set factor(value: number) {
this.player.x = (1-value)*(1-value) * this.player.x + 2 * value * (1-value)*(this.player.x + this.targetPos.x) / 2 + value * value * (this.targetPos.x);
this.player.y = (1-value)*(1-value) * this.player.y + 2 * value * (1-value)*(this.player.y - 300) / 2 + value * value * (this.targetPos.y);
}
对应 onKeyUp方法里执行跳跃动画的变量 factro:
egret.Tween.get(this).to({factor: 1}, 500).call(() => { …… });
12. 判断是否跳跃成功:
private judgeResult(){
if(Math.pow(this.currentBlock.x - this.player.x, 2) + Math.pow(this.currentBlock.y - this.player.y, 2) <= 70*70) {
this.score++;
this.scoreLabel.text = this.score.toString();
this.direction = Math.random() > 0.5 ? 1 : -1;
var blockX, blockY;
blockX = this.direction > 0 ? this.leftOrigin.x : this.rightOrigin.x;
blockY = this.height / 2 + this.currentBlock.height;
var playerX, playerY;
playerX = this.player.x - (this.currentBlock.x - blockX);
playerY = this.player.y - (this.currentBlock.y - blockY);
this.update(this.currentBlock.x - blockX, this.currentBlock.y - blockY);
egret.Tween.get(this.player).to({
x: playerX,
y: playerY
}, 1000).call(() => {
this.addBlock();
this.blockPanel.touchEnabled = true;
})
console.log("x" + this.currentBlock.x);
}else {
console.log("游戏失败!");
this.overPanel.visible = true;
this.overScoreLabel.text = this.score.toString();
}
}
private update(x, y) {
egret.Tween.removeAllTweens();
for(var i: number = this.blockArr.length - 1; i >= 0; i--) {
var blockNode = this.blockArr[i];
if(blockNode.x + (blockNode.width - 222) < 0 ||
blockNode.x - 222 > this.width || blockNode.y - 78 > this.height) {
this.blockPanel.removeChild(blockNode);
this.blockArr.splice(i,1);
this.reBackBlockArr.push(blockNode);
}else {
egret.Tween.get(blockNode).to({
x: blockNode.x - x,
y: blockNode.y - y
}, 1000)
}
}
}
- 调用 judgeResult 来判断当前跳跃是否成功在 onKeyUp 方法里:
egret.Tween.get(this).to({factor: 1}, 500).call(() => {
this.player.scaleY = 1;
this.jumpDistance = 0;
this.judgeResult();
});
-
导入第三方库(使用 egret build -a 命令导入): -
导入第三方库到工程文件目录中,将该文件夹下的内容拷贝到所创建的 egret 项目文件目录中,命名为 game -
在项目中的 egretProperties.json 文件中加入 game 文件名和路径 -
在项目编辑器的终端输入 egret build -e 命令,等待编译成功 -
使用第三方库 game 里的Ticker 心跳计时器,用来计时手指按下屏幕的时间长度,通过时间长度来计算跳跃的距离
egret.Ticker.getInstance().register(function(dt){
dt /= 1000;
if(this.isReadyJump) {
this.jumpDistance += 300 * dt;
}
}, this)
13. 跳跃失败的游戏结束界面:
|