写在前面

EUI是一套基于Egret核心显示列表的UI扩展库,它封装了大量的常用UI组件,能够满足大部分的交互界面需求,即使更加复杂的组件需求,您也可以基于EUI已有组件进行组合或扩展,从而快速实现需求。

为了展示EUI的功能,我借助白鹭官网中的一个卡牌游戏DEMO,从0开始编写完成这个DEMO。其实这并不是一个完整的游戏,只是一个演示DEMO,亲自实现这个DEMO之后,应该能熟悉大部分的EUI操作,并且增加对egret游戏开发的理解。

演示地址

点进去之后可以体验一下,把所有地方都点一点,感受一下所有的功能,接下来我们就要自己去动手实现了。(这里可以下载源码素材)不过这里的源码是编译之后的并不是源代码,不过我们只需要用到里面的素材,具体实现就让我一步一步自己来吧~~~初始化

新建好EUI项目(480 * 800),把刚刚下载的文件里面的source > resource > art 这个文件夹放在我们自己新建的项目中

按照之前的流程,现在删除新建的项目中多余的代码

上面还有个函数的调用要记得一起删掉

现在项目干净了~

Let's do it

场景搭建

EUI最方便的地方就是能快速的搭建界面,只需要用鼠标拖动就可以搭建静态的界面

先来把游戏的素材放到加载组里

打开default.res.json

新建两个资源组分别放hero_goods和loading,其他的都放到preload组就好

现在稍微分析一下

这个游戏一共有五个场景:

主场景

玩家场景

英雄场景

物品场景

关于场景

loading

在主场景之前,其实还有一个loading需要先显示出来,这样用户就不会看到一片黑乎乎的加载过程,提高用户体验

根据我们之前设置的几个资源组,preload是游戏初始化需要加载的资源,我们的loading则需要在它之前就加载好,这样用户就能先看到loading页,so现在去写个loading

项目其实自带了一个很简陋的loading,我们可以再这个基础上来写

打开main.ts

先加载这个资源组里面的资源,然后再把loadingView添加到舞台

打开loadingUi.ts

class LoadingUI extends egret.Sprite implements RES.PromiseTaskReporter {public constructor() {super();// 当被添加到舞台的时候触发 (被添加到舞台,说明资源组已经加载完成)this.addEventListener(egret.Event.ADDED_TO_STAGE, this.createView, this)}private textField: egret.TextField; // 文本private bgImg: egret.Bitmap // 背景图private loadImg: egret.Bitmap // loading图标private createView(): void {this.width = this.stage.stageWidththis.height = this.stage.stageHeight// 背景图this.bgImg = new egret.Bitmap()this.bgImg.texture = RES.getRes('loading_jpg')this.addChild(this.bgImg)// loading图标this.loadImg = new egret.Bitmap()this.loadImg.texture = RES.getRes('loading2_png')this.loadImg.anchorOffsetX = this.loadImg.width / 2this.loadImg.anchorOffsetY = this.loadImg.height / 2this.loadImg.x = this.width / 2this.loadImg.y = this.height / 2this.addChild(this.loadImg)// 文本this.textField = new egret.TextField();this.addChild(this.textField);this.textField.width = 480;this.textField.height = 20this.textField.y = this.height / 2 - this.textField.height / 2;this.textField.size = 14this.textField.textAlign = "center";// 监听帧事件,每帧都让loading图片转动this.addEventListener(egret.Event.ENTER_FRAME, this.updata, this)}private updata() {// 旋转this.loadImg.rotation += 5}// 这个函数在加载中会自动调用public onProgress(current: number, total: number): void {// 计算百分比let per = Math.floor((current / total) * 100)this.textField.text = `${per}%`;}
}

loading实现完成~现在调试看看,在终端输入egret run -a(-a 表示修改代码保存后自动编译,你只需要在浏览器刷新就可以看到修改后的效果)

能看到loading页面了~

主场景

主场景就是我们进入游戏的时候看到的第一个场景,其他的四个场景就是在点击下面不同的按钮的时候添加到当前的主场景上就好啦~

首先我们来把几个场景的组件搞定。

  1. 在resource目录下新建一个skins目录,用来存放我们创建的皮肤
  2. 在scr目录下单击右键,新建一个EUI组件

创建主场景

相对于我们之前先创建exml再创建对应的ts文件要方便很多,而且这样不需要在ts文件中指定skinName,因为直接创建EUI组件的时候它在配置文件中已经帮你指定好了。

可以在default.thm.json文件里面看到

现在点开自动生成的MainScene.exml

设置好宽高480 * 800

把图片拖进来,然后再快捷约束里面点击左对齐和上对齐,图片就自动调整好了

现在需要去设置场景下方的四个按钮

每个按钮都有两种状态,正常和按下。 这里需要单独去新建单个按钮的皮肤,下面以玩家按钮为例

新建mbtnPlayer.exml ,设置宽高111 * 80

点击下面状态旁边的+ 号,给这个皮肤设置不同的状态

up是正常状态,down是按下状态,disabled是禁用状态

这里我们先设置up状态

在up状态中,把正常状态的背景图和按钮图片拖进来。

同理,把按下状态也搞定。(记得按下状态的背景图不一样)

现在我们得到了一个自定义的组件皮肤

回到MainScene.exml

为了更好管理四个按钮,所以先拖进来一个Group,并给他一个id Group_mbtn

给这个Group设置好布局,一会儿里面的按钮就会自动排列好,不用手动去拖动

往Group中放置一个ToggleButton ,把皮肤换成我们刚刚自定义的mbtnPlayer

照葫芦画瓢,把其他三个都搞定吧~

主场景搭建完毕

做完了主场景,现在开始写一些关于主场景的逻辑

上面忘了说要记得给那几个按钮设置id

打开MainScene.ts

class MainScene extends EUI.Component implements  EUI.UIComponent {public Group_mbtn:EUI.Group;
public mgtnPlayer:EUI.ToggleButton;
public mbtnHero:EUI.ToggleButton;
public mbtnGoods:EUI.ToggleButton;
public mbtnAbout:EUI.ToggleButton;public constructor() {
super();
}protected partAdded(partName:string,instance:any):void
{
super.partAdded(partName,instance);
}protected childrenCreated():void
{
super.childrenCreated();// 让Group可以点击
this.Group_mbtn.touchEnabled = true// 事件委托, 点击按钮的时候触发toggleBtn
this.Group_mbtn.addEventListener(egret.TouchEvent.TOUCH_TAP, (e)=> {
let theBtn = <EUI.ToggleButton>e.target
// 在点击触发这个事件的时候,点击的那个btn已经变成了选中状态
// 判断theBtn是否存在theBtn.selected属性且为true
if (theBtn.selected && theBtn.selected != undefined) {
this.toggleBtn(theBtn)
} else {
// 当selected为false的时候,说明按钮在点击之前就是选中状态
// 点击后变成了false,所以这里改回选中状态
theBtn.selected = true
}
}, this)
}/**
* 切换按钮
*/
public toggleBtn(btn:EUI.ToggleButton) {
// 先把所有的按钮都设置为不选中
for (let i = 0; i < this.Group_mbtn.numChildren; i++) {
let theBtn = <EUI.ToggleButton>this.Group_mbtn.getChildAt(i)
theBtn.selected = false
}
// 把传进来的btn设置为选中状态
btn.selected = true
}
}

在Main.ts里,把主场景添加到舞台

protected createGameScene(): void {this.addChild(new MainScene())}

现在运行就可以看到切换按钮的效果

玩家场景

现在开始创建 玩家场景PlayerScene组件

设置宽高680*800, 拖拽图片和button

注意红色框的是button

这三个按钮在点击的时候会变大,这个效果我们可以在制作皮肤的时候就完成

首先用鼠标点中返回按钮,然后点击左上方的 源码

这一段就是那个返回按钮的源码,修改成下图

width.down = "100%" 表示当按钮按下的时候宽度为100%,其他情况下宽度90%

horizontalCenter="0" verticalCenter="0" 表示让图片以中心放大

可以看到红框部分是一个可以拖动的窗口,所以我们需要放置一个scroller

把scroller里面自带的group删掉,加上一个数据容器list

现在创建list里面的某一个子项的皮肤zhuangbeiItem.exml

宽高设为87*130 ,拖入一张图片和一个labl控件还有一个image控件,设置好label的样式

这个皮肤里面的label和image控件的值都是需要我们去提供的

需要在标签里面写{data.xx} 其实很像js里面某些框架的插值写法

给label 的标签写上{data.name} , 给image 的资源名写上{data.image}

装备item完成,回到刚刚的PLayerScene, 把list的条目皮肤设置为刚刚创建的装备item

把list布局设置成水平布局

给scroller和list都取个id,便于后面使用

这个scroller只需要左右拖动,所以我们去 ‘所有属性’ 打开它的水平滚动,关掉垂直滚动

打开PLayerScene.ts

class PlayerScene extends EUI.Component implements  EUI.UIComponent {public btn_return:EUI.Button;
public btn_zhuangbei:EUI.Button;
public btn_qianghua:EUI.Button;
public scr_zhuangbei:EUI.Scroller;
public list_zhuangbei:EUI.List;public constructor() {
super();
}protected partAdded(partName:string,instance:any):void
{
super.partAdded(partName,instance);
}protected childrenCreated():void
{
super.childrenCreated();
// 数组数据
let dataArr:any[] = [
{image:"resource/art/profile/skillIcon01.png",name:"旋龙幻杀"},
{image:"resource/art/profile/skillIcon02.png",name:"魔魂天咒"},
{image:"resource/art/profile/skillIcon03.png",name:"天魔舞"},
{image:"resource/art/profile/skillIcon04.png",name:"痴情咒"},
{image:"resource/art/profile/skillIcon05.png",name:"无间寂"},
{image:"resource/art/profile/skillIcon06.png",name:"霸天戮杀"},
{image:"resource/art/profile/skillIcon07.png",name:"灭魂狂飙"}
]
// 把数组数据转成EUI数组
let EUIArr:EUI.ArrayCollection = new EUI.ArrayCollection(dataArr)
// 把EUI数组作为list的数据源
this.list_zhuangbei.dataProvider = EUIArr
// 隐藏进度条
this.scr_zhuangbei.horizontalScrollBar.autoVisibility = false}}

到这里,  玩家场景也创建完成啦~

场景管理类

我们有了两个场景,可以来做场景之间的切换了

还记得之前说的思路吗,舞台上先有一个主场景,然后点击不同按钮的时候把对应的场景添加到主场景上

这里有个需要注意的地方,子场景添加进来默认层级是高于主场景的,所以会把主场景给挡住了,而我们需要点击主场景的按钮。所以我们需要把主场景中放置按钮的Group的层级提高。

我用一个场景管理类来管理这些场景

新建一个SceneManager.ts,采用的是单例模式,要使用这个类的时候不要new SceneManager实例,而是用SceneManager.instance来获取到这个类的实例

这样可以保证场景管理类有且只有一个实例,便于管理操作

(使用static修饰的方法都是静态方法,简单的说就是调用的时候不是通过实例调用,而是直接用类名来调用, 类名.方法名)

下面是一个基础的场景管理类,现在来逐步完善它的功能

/**
* 场景管理类
*/
class SceneManager {private _stage:egret.DisplayObjectContainer // 设置所有场景所在的舞台(根)private mainScene:MainScene //主场景private playerScene:PlayerScene //玩家场景// 在构造函数中创建好场景,保存到属性constructor() {this.mainScene = new MainScene()this.playerScene = new PlayerScene()}/*** 获取实例*/static sceneManager:SceneManagerstatic get instance(){if(!this.sceneManager) {this.sceneManager =  new SceneManager()} return this.sceneManager}/*** 设置根场景*/public setStage(s:egret.DisplayObjectContainer) {this._stage = s}// 这里补充代码……}

首先需要管理的场景是主场景,SceneManager.instance.mainScene是获取到主场景的实例

SceneManager.instance获取到场景管理类的实例

然后再.mainScene 获取到构造方法constructor中的 this.mainScene = new MainScene() 得到的主场景 的实例

 /*** 主场景*/static toMainScene() {let stage:egret.DisplayObjectContainer = this.instance._stage // (根) 舞台let mainScene = SceneManager.instance.mainScene // 主场景// 判断主场景是否有父级(如果有,说明已经被添加到了场景中)if(!mainScene.parent){// 未被添加到场景// 把主场景添加到之前设置好的根舞台中stage.addChild(mainScene)} }

现在到main.ts中使用场景管理类来加载主场景

在到main.ts中使用场景管理类来加载主场景/*** 创建场景界面* Create scene interface*/protected createGameScene(): void {// 把this设置为场景管理器的根舞台SceneManager.instance.setStage(this)// 调用SceneManager的静态方法SceneManager.toMainScene()}

现在运行,可以看到主场景已经被添加到舞台中了

现在只有一个场景,需要把第二个场景也加进来,并实现切换

在场景管理类中再添加一个静态方法

/*** 玩家场景*/static toPlayerScene() {let stage:egret.DisplayObjectContainer = this.instance._stage// 把玩家场景添加到主场景中this.instance.mainScene.addChild(this.instance.playerScene)}

当在主场景点击玩家按钮的时候,调用这个方法,切换到玩家场景

这里需要稍微改动一下之前的点击函数

打开MainScene.ts

/**
* 切换按钮
* @param btn 参数是EUI.ToggleButton的时候切换按钮, 参数是0的时候设置为全部不选中
*/
public toggleBtn(btn:EUI.ToggleButton | number) {
// 先把所有的按钮都设置为不选中
for (let i = 0; i < this.Group_mbtn.numChildren; i++) {
let theBtn = <EUI.ToggleButton>this.Group_mbtn.getChildAt(i)
theBtn.selected = false
}
if(btn===0){
return
}
// 把传进来的btn设置为选中状态
btn = <EUI.ToggleButton>btn
btn.selected = true// 获取当前点击的按钮的下标, 用来实现不同按钮对应的功能
// 0 1 2 3 对应 玩家, 英雄, 物品, 关于
let index = this.Group_mbtn.getChildIndex(<EUI.ToggleButton>btn)
switch (index) {
case 0:
// 调用静态方法切换到玩家场景
SceneManager.toPlayerScene()
// 把按钮的层级提高
// this.numChildren表示所有的子元素数量
this.setChildIndex(this.Group_mbtn, this.numChildren)
break
default:
break
}
}
点击玩家按钮就可以正常切换到玩家场景了,现在来实现其中的返回按钮
点击返回按钮,回到主场景,并且下面的按钮全都变成未选中状态
打开PlayerScene.ts
// 给返回按钮添加事件
this.btn_return.addEventListener(egret.TouchEvent.TOUCH_TAP, this.returnMain, this)
/**
* 回到主场景
*/
private returnMain() {
SceneManager.toMainScene()
}
点击按钮跳转回到主场景,其实就是删除掉当前覆盖在主场景上的玩家场景,主场景就能显示出来了
so,打开SceneManager.ts,完善一下刚刚的函数
/*** 主场景*/static toMainScene() {let stage:egret.DisplayObjectContainer = this.instance._stage // (根) 舞台let mainScene = SceneManager.instance.mainScene // 主场景// 取消所有按钮的选中状态mainScene.toggleBtn(0)// 判断主场景是否有父级(如果有,说明已经被添加到了场景中)if(!mainScene.parent){// 未被添加到场景// 把主场景添加到之前设置好的根舞台中stage.addChild(mainScene)} // 判断玩家场景是否有父级(是否在场景中)if(SceneManager.instance.playerScene.parent) {// 如果有就删除玩家场景mainScene.removeChild(SceneManager.instance.playerScene)}}

保存文件

去浏览器里就能看到效果了~

英雄场景

开始制作英雄场景HeroScene.exml

到源码部分,修改一下两个按钮的效果

在中间放置一个Scroller,然后里面放一个List,

跟之前玩家场景其实差不多啦,现在去创建heroListItem.exml

这里需要注意,有个checkBox,用来选中某个list

把里面的数据插值写好{data.image} {data.name} {data.value}

checkBox是个例外,它的值不能用{data.xx}的方式来指定,我们需要创建一个单独的类

Herolist_item.ts

// 必须要继承自EUI.ItemRendererclassHeroList_itemextendsEUI.ItemRenderer{// 选择框publicce_select:EUI.CheckBox;publicconstructor() {super()// 把这个 类和皮肤 联系起来this.skinName='resource/skins/skins_item/heroListItem.exml'}// 当数据改变时,更新视图protecteddataChanged() {// isSeleted 是我们提供数据的某个字段this.ce_select.selected=this.data.isSelected}}

回到HeroScene.exml, 把list的条目皮肤设置为heroListItem,并给他们设置好id

在所有属性里面把水平滚动关掉,垂直滚动打开

打开英雄场景HeroScene.ts

classHeroSceneextendsEUI.Componentimplements EUI.UIComponent{publicbtn_return:EUI.Button;publicbtn_select:EUI.Button;publicscr_hero:EUI.Scroller;publiclist_hero:EUI.List;publicconstructor() {super();}protectedpartAdded(partName:string,instance:any):void{super.partAdded(partName,instance);}protectedchildrenCreated():void{super.childrenCreated();// 原始数组letdataArr:any[] =[{image: 'resource/art/heros_goods/heros01.png', name: '亚特伍德', value: '评价: 很特么厉害, 为所欲为', isSelected: false},{image: 'resource/art/heros_goods/heros02.png', name: '亚特伍德', value: '评价: 很特么厉害, 为所欲为', isSelected: false},{image: 'resource/art/heros_goods/heros03.png', name: '亚特伍德', value: '评价: 很特么厉害, 为所欲为', isSelected: true},{image: 'resource/art/heros_goods/heros04.png', name: '亚特伍德', value: '评价: 很特么厉害, 为所欲为', isSelected: false},{image: 'resource/art/heros_goods/heros05.png', name: '亚特伍德', value: '评价: 很特么厉害, 为所欲为', isSelected: false},{image: 'resource/art/heros_goods/heros06.png', name: '亚特伍德', value: '评价: 很特么厉害, 为所欲为', isSelected: false},{image: 'resource/art/heros_goods/heros07.png', name: '亚特伍德', value: '评价: 很特么厉害, 为所欲为', isSelected: false}]// 转成EUI数组letEUIArr:EUI.ArrayCollection=newEUI.ArrayCollection(dataArr)// 把list_hero数据源设置成EUIArrthis.list_hero.dataProvider=EUIArr// 设置list_hero的项呈视器(这里直接写类名,而不是写实例)this.list_hero.itemRenderer=HeroList_item}}

现在运行一下,能看到列表已经能正确的加载,而且数组中isSeleted字段为true的第三项也被默认选中了。

现在来实现手动更改列表的选中状态

Herolist_item.ts

classHeroSceneextendsEUI.Componentimplements EUI.UIComponent{publicbtn_return:EUI.Button;publicbtn_select:EUI.Button;publicscr_hero:EUI.Scroller;publiclist_hero:EUI.List;publicconstructor() {super();}protectedpartAdded(partName:string,instance:any):void{super.partAdded(partName,instance);}protectedchildrenCreated():void{super.childrenCreated();// 原始数组letdataArr:any[] =[{image: 'resource/art/heros_goods/heros01.png', name: '亚特伍德', value: '评价: 很特么厉害, 为所欲为', isSelected: false},{image: 'resource/art/heros_goods/heros02.png', name: '亚特伍德', value: '评价: 很特么厉害, 为所欲为', isSelected: false},{image: 'resource/art/heros_goods/heros03.png', name: '亚特伍德', value: '评价: 很特么厉害, 为所欲为', isSelected: true},{image: 'resource/art/heros_goods/heros04.png', name: '亚特伍德', value: '评价: 很特么厉害, 为所欲为', isSelected: false},{image: 'resource/art/heros_goods/heros05.png', name: '亚特伍德', value: '评价: 很特么厉害, 为所欲为', isSelected: false},{image: 'resource/art/heros_goods/heros06.png', name: '亚特伍德', value: '评价: 很特么厉害, 为所欲为', isSelected: false},{image: 'resource/art/heros_goods/heros07.png', name: '亚特伍德', value: '评价: 很特么厉害, 为所欲为', isSelected: false}]// 转成EUI数组letEUIArr:EUI.ArrayCollection=newEUI.ArrayCollection(dataArr)// 把list_hero数据源设置成EUIArrthis.list_hero.dataProvider=EUIArr// 设置list_hero的项呈视器(这里直接写类名,而不是写实例)this.list_hero.itemRenderer=HeroList_item}}

这里可能稍微有点儿绕,需要花一点时间好好理解一下代码执行的流程。

现在点击checked框的时候就能正确的修改数据的isSelected了

继续完成返回和确定选择的按钮

返回按钮其实就是把场景切换到主场景去,在场景控制类中写个方法就好

确定选择的按钮其实也是要切换回到主场景,再获取一下数据里面isSelected为true的项,并把它们显示到屏幕上

设置返回按钮,直接在点击事件中调用场景管理的方法就好了,把按钮的选择状态都清除

HeroScene.ts

// 点击返回按钮,回到主场景this.btn_return.addEventListener(egret.TouchEvent.TOUCH_TAP, (e)=>{SceneManager.toMainScene()SceneManager.instance.mainScene.toggleBtn(0)}, this)

选择功能,点击按钮的时候获取到数据源中的isSelected为true的项都保存到数组中,然后把这个数组作为参数传到场景管理里面。拿到数组就创建对应的消息显示出来就好了

HeroScene.ts

// 点击确定按钮,回到主场景,显示出选择的项this.btn_select.addEventListener(egret.TouchEvent.TOUCH_TAP, this.onClickSelect, this)/*** 点击确定按钮*/onClickSelect(e) {SceneManager.toMainScene()SceneManager.instance.mainScene.toggleBtn(0)// 拿到数据源letdataProvider=this.list_hero.dataProviderletarr:string[] =[]// 遍历数据源中所有项for(leti=0; i<dataProvider.length; i++) {letitem=dataProvider.getItemAt(i)if(item.isSelected) {arr.push(item.name)}}SceneManager.showInfo(arr)}SceneManager.ts/*** 在主场景显示选择的数据*/staticshowInfo(arr:string[]) {lettext:string='你选择了: 'if(arr.length===0) {text='厉害了什么都不选'} else{text+=arr.toString()}// 新建一个消息背景图letimg:egret.Bitmap=newegret.Bitmap()img.texture=RES.getRes('toast-bg_png')SceneManager.instance.mainScene.addChild(img)img.x=SceneManager.instance.mainScene.width/2-img.width/2img.y=500img.height=40// 新建一个label用来显示letlabel:egret.TextField=newegret.TextField(); label.text=textlabel.size=20SceneManager.instance.mainScene.addChild(label)label.x=SceneManager.instance.mainScene.width/2-label.width/2label.y=510label.height=40// 创建一个定时器,1000毫秒后删除labellettimer:egret.Timer=newegret.Timer(1000, 1)timer.start()timer.addEventListener(egret.TimerEvent.TIMER_COMPLETE, (e)=>{SceneManager.instance.mainScene.removeChild(label)SceneManager.instance.mainScene.removeChild(img)}, this)}

到这里,我们的游戏卡牌项目的重点已经基本完成了。

后面还有两个场景,物品场景,关于场景

物品场景其实就是EUI搭建好场景后,加上一个Scroller,然后里面放上数据列表就好,跟前面的操作都一样

关于场景根本就是添加一个图片到场景就ok

最后

如果你按照之前的几篇文章一步一步的动手实现到了这里,那么你已经完成了

  1. EUI项目的创建
  2. exml皮肤界面的拖拽搭建
  3. EUI基本控件的使用方法:image button scorller list ……
  4. loading的实现
  5. 游戏场景切换:实现了场景管理类
  6. 游戏开发的一些思路,代码组织方式 (虽然我的不一定是对的,但是能参考一下)

你已经很强了,所以剩下的两个场景实现起来肯定毫无问题。

我的代码还有很多可以优化的地方, 比如场景管理里面每次都要判断删除其他场景,  完全可以封装一个方法来使用。

做完这个项目最好再好好看一遍自己写的代码,重点是要明确思路,理清代码逻辑。

源码

https://github.com/hedongshu/egret-EUI-DEMO

《菜鸟教程》 EUI卡牌游戏制作相关推荐

  1. EUI卡牌游戏的制作全过程

    转载自:https://bbs.egret.com/forum.php?mod=viewthread&tid=50009&highlight=%E5%8D%A1%E7%89%8C 为了 ...

  2. [Unity3D]卡牌游戏中有关卡牌类的制作

    文章目录 展示卡牌 卡牌展示效果 打出卡牌 敌人释放技能 需求 制作 流程 抽牌: 弃牌: 一些问题 抽牌 查看卡牌 查看抽牌堆 查看弃牌堆 卡牌效果的实现 还没学到设计模式,所以自己和同学捣鼓了一个 ...

  3. 卡牌游戏源代码(原创)(控制台)

    游戏预览: 完成度90%,约3000行,过年这几天全用在这上面了 由于尚未学到QT等,因此只能在黑窗口下面制作了 未完成的部分: ①战斗代码未优化(800行,精简后应该能降到200行左右) ②关卡掉落 ...

  4. php写卡牌游戏,生成汉字卡牌的PHP小应用

    上初中时,班里曾经有人发明了一套用化学元素信息做卡牌的游戏,风靡一时.可惜现在已经完全想不起来当时的玩法了.包子上小学后,包爸就想着也效仿这种模式,让包子和小伙伴们有的玩.于是断断续续花了一个学期的时 ...

  5. 《刀塔传奇》最初不是卡牌游戏——专访龙图COO王彦直

    http://game.donews.com/201407/2814031.shtm "最早是以投资商的身份去合作,后来又转换成发行商的身份去合作." 6月28日,<刀塔传奇 ...

  6. 用js写卡牌游戏(八)

    前言 好久不见,离发布上次分享,已经过去很久很久了,这段时间发生了很多变故,经历了跳槽.离职.创业等等,手头也一直有很多事情在忙,不过鸽这么久其实是有别的理由,有一个非常重要的功能一直卡住,没有思路, ...

  7. 【概率DP】$P2059$ 卡牌游戏

    [概率DP]P2059 卡牌游戏 链接 题目描述 N个人坐成一圈玩游戏.一开始我们把所有玩家按顺时针从1到N编号.首先第一回合是玩家1作为庄家.每个回合庄家都会随机(即按相等的概率)从卡牌堆里选择一张 ...

  8. 天池 在线编程 卡牌游戏(01背包)

    文章目录 1. 题目 2. 解题 1. 题目 你跟你的朋友在玩一个卡牌游戏,总共有 n 张牌. 每张牌的成本为 cost[i] 并且可以对对手造成 damage[i] 的伤害. 你总共有 totalM ...

  9. 动漫品牌“爆笑虫子”宣布与xNFT Protocol战略合作,开发NFT数字卡牌游戏

    2021年4月23日,xNFT Protocol与动漫品牌"爆笑虫子"进行战略合作,推动"爆笑虫子"在卡牌游戏领域进行数字化转型.IP的数字(NFT)化是xNF ...

  10. CCF201612-5 卡牌游戏(募集解题代码)

    试题编号: 201612-5 试题名称: 卡牌游戏 时间限制: 3.0s 内存限制: 256.0MB 问题描述: 问题描述 小Q和小M是游戏数值策划师,他们最近在测试自己新设计的卡牌对战游戏.游戏总共 ...

最新文章

  1. 全员编程时代,人类高质量程序员应具备哪三大特质?
  2. 一个商场营销经理的实习总结
  3. 抢购网站服务器时间表,js获取服务器时间,实现抢购倒计时
  4. IDEA以UML图表方式查看maven项目pom文件中全局及部分jar之间依赖关系
  5. NameNode 启动失败 - There appears to be a gap in the edit log. We expected txid xxx, but got tx
  6. Zookeeper 教程:Zookeeper作为Hadoop和Hbase的重要组件,为分布式应用程序协调服务
  7. 【令人头秃的线段树】线段树入门题目详解(代码逐句分析)
  8. inter Fortran安装匹配VS2012
  9. 把书本上的字快速弄到电脑上
  10. java 短信批量发送_Redis实现订阅发布与批量发送短信
  11. C++编写红警3 1.12版本修改器
  12. 编程中的数学——编程遇见数学,让数学更有趣!
  13. 润和大数据负责人崔凯参加PostgreSQL中国技术大会
  14. R语言学习记录:sample()函数
  15. 天平游码读数例题_托盘天平游码读数方法及使用口诀 | | 化工资讯网
  16. 【电路补习笔记】8、稳压电路 —— 线性电源及LDO
  17. 英菲克无线鼠标pm6的配对方法
  18. 苏、陕、宁、浙四省主动安全防控/智能视频监控预警设备平台一览
  19. ffmpeg对ts流的解析
  20. bert系列第一篇: bert进行embedding

热门文章

  1. 面试题汇总-大牛的Java170
  2. 如何改变计算机内存配置文件,电脑内存使用率过高怎么解决?教你如何调整内存大小...
  3. ITMS-SERVICES://方式安装IPA在IOS 7.1中的变化
  4. 7zip打不开wim文件
  5. CVPR 2018值得一看的25篇论文,都在这里了 | 源码 解读
  6. 历尽磨难,探索未来生活的2014年
  7. 苹果执行请求时出错_苹果执行请求时出错
  8. 电视盒机顶盒搭建FTP功能,外接硬盘U盘,电脑或手机端访问
  9. CTFshow——web入门——php特性(上篇)
  10. 广工Libero SoC安装教程