IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 游戏开发 -> 仿跳一跳小游戏 -> 正文阅读

[游戏开发]仿跳一跳小游戏

一、游戏玩法介绍:

  • 跳一跳使用手指按压屏幕蓄力;
  • 根据力量大小控制小 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; 

// 小 i 
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;  
	
	// 把新建的 block 添加进入 blockArr 里  
	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');   
	
	// 打开 touchEnabled 属性  
	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; 
}
  • 添加方向变量,往右添加是正值1,往左是负值-1:
// 下一个盒子方向(1 靠右侧出现 / -1 靠左侧出现) 
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();  
}

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • tan 的角度并声明落脚点
// tanθ 角度值 
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. 运动轨迹的表示:

在这里插入图片描述

// 添加 factor 的 set,get 方法,注意使用 public  
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. 判断是否跳跃成功:

// 根据 this.jumpDistance 来判断跳跃是否成功 
private judgeResult(){     
	// pow 函数用于求幂      
	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. 跳跃失败的游戏结束界面:

在这里插入图片描述

  游戏开发 最新文章
6、英飞凌-AURIX-TC3XX: PWM实验之使用 GT
泛型自动装箱
CubeMax添加Rtthread操作系统 组件STM32F10
python多线程编程:如何优雅地关闭线程
数据类型隐式转换导致的阻塞
WebAPi实现多文件上传,并附带参数
from origin ‘null‘ has been blocked by
UE4 蓝图调用C++函数(附带项目工程)
Unity学习笔记(一)结构体的简单理解与应用
【Memory As a Programming Concept in C a
上一篇文章      下一篇文章      查看所有文章
加:2021-11-26 09:10:11  更:2021-11-26 09:11:16 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/27 23:57:37-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码