到目前为止我们已经实现了整个游戏的界面以及“空格”和键盘按钮的动画,接下来完成游戏的基础玩法流程。

完整代码

一、初始化游戏

由于在游戏中“空格”的背景和Label会有相应的变化。所以在游戏开始前需要进行一些初始化设置。

1、随机生成一个5个字母的单词。

2、重置“空格”的背景和字体颜色:重置为在Cocos Creator编辑器中的初始设计值。

3、设置“空格”只读:初始状态下,只有第一排可以输入。

4、重置键盘按钮的背景颜色:重置为在Cocos Creator编辑器中的初始设计值。

5、设置当前选中的“空格”。

在gamemanager中实现以上功能,代码如下:

    import { words } from './words';//加载词库//根据词库随机生成一个单词setCurrentAnswer () {let sAnswer = words.getRandomword();gamemanager._currentAnswer = sAnswer;}getCurrentAnswer () {return gamemanager._currentAnswer;}//重置中间方块区域resetMiddleBtn () {let homeNode = gamemanager.instance.homeNode;for (let i = 0; i < 6; i ++){let layoutNode = homeNode.getChildByPath('top/Layout_middle' + (i + 1).toString());for(let j = 0; j < layoutNode.children.length;j++){layoutNode.children[j].getChildByName('Sprite').getComponent(Sprite).spriteFrame = layoutNode.children[j].getChildByName('Sprite').getComponent(Sprite).spriteAtlas.getSpriteFrame('btn_border');layoutNode.children[j].getChildByName('Label').getComponent(Label).string = '';layoutNode.children[j].getChildByName('Label').getComponent(Label).color = new Color(0,0,0);}  }  }//设置中间方块区域只读setMiddleBtnReadOnly () {let homeNode = gamemanager.instance.homeNode;for (let i = 0; i < 6; i ++){let layoutNode = homeNode.getChildByPath('top/Layout_middle' + (i + 1).toString());if (i === 0) {gamemanager.instance.setBtnEnable(layoutNode,true);}else {gamemanager.instance.setBtnEnable(layoutNode,false); }   }  }setBtnEnable(layoutNode,isEnable){if(layoutNode) {for(let i = 0;i < layoutNode.children.length;i++){layoutNode.children[i].getComponent(Button).enabled = isEnable;}}} //重置键盘按钮resetKeybordeBG () {let homeNode = gamemanager.instance.homeNode;for(let i = 0; i < 3; i++){let layoutNode = homeNode.getChildByPath('top/Layout_bottom' + (i + 1).toString());for(let j = 0; j < layoutNode.children.length; j++){layoutNode.children[j].getComponent(Sprite).spriteFrame = layoutNode.children[j].getComponent(Sprite).spriteAtlas.getSpriteFrame('keybord_bg');}}}//运行“空格”输入动画showBtnInputTween (currentBtnNode) {currentBtnNode.getComponent('btn_middle').tweenObjLabelInput.start();}//运行“空格”清除动画showBtnClearTween (currentBtnNode) {currentBtnNode.getComponent('btn_middle').tweenObjClear.start();}

词库是在github上找的原版游戏的词库。词库分为两部分,正确的单词大概有2700多个,允许输入的单词大概有1万个。原版游戏的作者只将常用的英文单词作为正确答案,考虑不通国家的玩家的语言不同又增加了近万个单词允许输入。后续教程写完以后会将原代码以及所用到的素材提供下载,这里就不再贴出来了,太长不好显示。

在home.ts脚本中增加initgame函数来统一管理游戏初始化过程:

    start () {this.initgame();}//初始化游戏initgame() {let homeNode = gamemanager.instance.getHomeNode();   const layoutnode = homeNode.getChildByPath('top/Layout_middle1');//设置答案gamemanager.instance.setCurrentAnswer();//重置中间框格背景,字体颜色gamemanager.instance.resetMiddleBtn();//设置中间方格只读gamemanager.instance.setMiddleBtnReadOnly();//重置键盘按钮颜色gamemanager.instance.resetKeybordeBG(); //选中第一个方框gamemanager.instance.setCurrentLayoutNode(layoutnode); gamemanager.instance.setCurrentBtnNode(layoutnode.children[0]); layoutnode.children[0].getComponent(Button).clickEvents[0].emit(['click']);                     }

二、提交答案

1、获取当前所在第几排,然后将这一排5个字母组合成一个字符串。

2、进行合法性校验:填写的字母够不够5个,是否为有效单词。

3、若未通过校验则显示提示框,提示框为prefab组件。

在home.ts中增加submitAnswer函数,代码如下:

    submitAnswer () {//提交答案let currentLayoutNode = gamemanager.instance.getCurrentLayoutNode();let err = '';let sAnswer = '';for (let i = 0;i < currentLayoutNode.children.length; i++) {sAnswer += currentLayoutNode.children[i].getChildByName('Label').getComponent(Label).string;}sAnswer = sAnswer.toLowerCase();if (sAnswer.length < 1) {err = '请填一个单词';}else if (sAnswer.length < 5) {err = '单词还没有填完';}else if (words.allwords.indexOf(sAnswer) < 0){//校验单词err = '不是有效单词';}if (err) {//弹出提示框Util.showDiolag('prefab/messageBox',homeNode.parent,(newNode) =>{if(newNode) {newNode.getChildByName('Label').getComponent(Label).string = err;}                });}else {         //处理答案提交动画           this.processAnswer();}}

需要先创建Util.ts脚本并在home.ts中引用它,Utile.ts脚本中我将常用的功能进行了一些封装。如下:


import { _decorator, Component, resources,Prefab,instantiate,Label } from 'cc';
const { ccclass, property } = _decorator;@ccclass('Util')
export class Util extends Component {//判断字符串是否为空static isEmpty (str): boolean {if (str === null ||str === '' ||str === undefined ||str.length === 0) {return true} else {return false}}//动态加载prefab组件static showDiolag(sPath,parentNode,callback){resources.load(sPath,Prefab,(err, prefeb) => {if(err) {console.log(err);}else {let newNode = instantiate(prefeb);if(callback) {callback(newNode);}parentNode.addChild(newNode); }});   }//执行线性等待static async sleep(ms: number) {return new Promise((resolve) => {setTimeout(() => {resolve('');}, ms)});}    //获取字符串最后一个字符static getLastChar(str) : string{if(Util.isEmpty(str)){return '';}else {return str.slice(str.length - 1,str.length);}}//http请求有道翻译static translate(str,handler){let xhr = new XMLHttpRequest();xhr.timeout = 5000;//超时参数xhr.onreadystatechange = function (data) {if (xhr.readyState === 4 && (xhr.status >= 200 && xhr.status < 300)) {let response = xhr.responseText;let data = JSON.parse(response);if (handler) {//获取翻译结果let sResult = data['translateResult'][0][0]['tgt'];let sUrl = 'https://dict.youdao.com/dictvoice?type=0&audio=' + str; handler(sResult,sUrl);}//data['translateResult'][0][0]['tgt']翻译结果//data.type 翻译类型:EN2ZH_CN英译汉 ZH_CN2EN汉译英//有道英文语音接口//'https://dict.youdao.com/dictvoice?type=0&audio=' + sResult;//百度中文语音接口//https://fanyi.baidu.com/gettts?lan=zh&text=' + sResult + '&spd=5&source=web';}  }//翻译接口采用有道翻译let url = 'https://fanyi.youdao.com/translate?&doctype=json&type=EN2ZH_CN&i=' + strxhr.withCredentials = true;xhr.open("GET", url , true);//跨域设置xhr.setRequestHeader('Access-Control-Allow-Origin', '*');xhr.setRequestHeader('Access-Control-Allow-Methods', 'GET, POST');xhr.setRequestHeader('Access-Control-Allow-Headers', 'x-requested-with,content-type,authorization');xhr.send();}
}

由于typescripte脚本是异步执行方式,在实践中要顺序显示“方格”的翻转动画,就需要实现一个类似Java中的sleep函数功能,让前一个“空格”开始翻转后等待100ms再开始旋转下一个“空格”。之所以要设计一个获取字符串最后一个字符的功能是因为在Cocos creator编辑器中,Layout和btn_middle等组件我都是将名称最后一位作为索引,然后在代码中根据这个索引来判断是位置。现在回过头来重新看这段代码就会觉得没有必要,可以根据父节点的.children属性来遍历子节点。

玩家提交的答案通过合法性校验后根据游戏规则判断猜测结果并调用“方格”的旋转动画,在home.ts中增加processAnswer函数:

将随机生成的答案转换为sAnswer数组,在for循环中依次比对玩家输入的每一个字母,并根据游戏规则改变“方格”的背景。为了方便玩家识别还有哪些字母可使用,增加了alterKeybordebg函数将比对结果同步更新到键盘按钮上。当前这一排提交后就需要将这一排设置为只读,让玩家不能再输入,然后将下一排设置为可以输入。当玩家猜中单词时则胜利,游戏结束。当第6排提交以后还未猜中单词,再获取下一排时就会获取到null,则输了,游戏结束。实现代码如下:

    async processAnswer (){let homeNode = gamemanager.instance.getHomeNode();let isPass = true;let layoutNode_middle = gamemanager.instance.getCurrentLayoutNode();let sAnswer = gamemanager.instance.getCurrentAnswer().split('');//先锁定这一排gamemanager.instance.setBtnEnable(layoutNode_middle,false); for (let i = 0; i < layoutNode_middle.children.length; i++) {let char = layoutNode_middle.children[i].getChildByName('Label').getComponent(Label).string;char = char.toLowerCase();if (sAnswer.indexOf(char) < 0){//答案中没有这个字母layoutNode_middle.children[i].getComponent('btn_middle').runRotation('btn_wrong');this.alterKeybordebg(char,'wrong');isPass = false;}else{if (sAnswer[i] != char) {//答案中有这个字母但是顺序不对layoutNode_middle.children[i].getComponent('btn_middle').runRotation('btn_partright');this.alterKeybordebg(char,'partright');sAnswer[sAnswer.indexOf(char)] = null; isPass = false;}else{//答案中有这个字母,顺序也对layoutNode_middle.children[i].getComponent('btn_middle').runRotation('btn_right');this.alterKeybordebg(char,'right');sAnswer[i] = null;}}await Util.sleep(100); //不执行线性等待,则所有方块一起翻转   }if(isPass) {//通过则显示胜利弹窗和战绩,let sCorrectAnswer = gamemanager.instance.getCurrentAnswer();Util.showDiolag('prefab/resultBox',homeNode.parent,(newNode)=>{if(newNode){newNode.getChildByName('content').getChildByName('title').getComponent(Label).string = '恭喜你答对了!';newNode.getChildByName('content').getChildByName('message').getComponent(Label).string = '答案是:' + sCorrectAnswer;                    }});            this.readyToNext();}else {//获取下一排的layoutNodelet char = Util.getLastChar(layoutNode_middle.name);let nextIndex = parseInt(char) + 1;const nextLayoutNode = homeNode.getChildByPath('top/Layout_middle' + nextIndex.toString());if(nextLayoutNode){//获取到了则设置当前layout节点和btn节点const nextBtnNode = nextLayoutNode.getChildByName(nextLayoutNode.name + '_1');gamemanager.instance.setBtnEnable(nextLayoutNode,true);gamemanager.instance.setCurrentLayoutNode(nextLayoutNode);gamemanager.instance.setCurrentBtnNode(nextBtnNode);//模拟点击事件nextBtnNode.getComponent(Button).clickEvents[0].emit(['click']);}else{//没获取到,则表示已经输了,显示正确答案let sCorrectAnswer = gamemanager.instance.getCurrentAnswer() ;Util.showDiolag('prefab/resultBox',homeNode.parent,(newNode)=>{if(newNode){newNode.getChildByName('content').getChildByName('title').getComponent(Label).string = '很遗憾你答错了!';newNode.getChildByName('content').getChildByName('message').getComponent(Label).string = '答案是:' + sCorrectAnswer;                    }});this.readyToNext();                }}}alterKeybordebg(sKey,type){let homeNode = gamemanager.instance.getHomeNode(); let key = sKey.toUpperCase();for(let i = 0;i < 3; i++) {let layoutNode = homeNode.getChildByPath('top/Layout_bottom' + (i + 1).toString());for(let j = 0; j < layoutNode.children.length; j++) {if (layoutNode.children[j].getChildByName('Label').getComponent(Label).string === key) {if(type === 'wrong') {//错误要判断之前是否已经更新过了,没有更新过才更新if ((layoutNode.children[j].getComponent(Sprite).spriteFrame.name === 'keybord_bg')) {layoutNode.children[j].getComponent(Sprite).spriteFrame = layoutNode.children[j].getComponent(Sprite).spriteAtlas.getSpriteFrame('keybord_wrong');                            }}else if (type === 'right') {//正确直接更新layoutNode.children[j].getComponent(Sprite).spriteFrame = layoutNode.children[j].getComponent(Sprite).spriteAtlas.getSpriteFrame('keybord_right');}else {//若存在,但是位置不正确的字母,需要判断是否之前更新过,如果之前更新过则不需要再更新了if (layoutNode.children[j].getComponent(Sprite).spriteFrame.name === 'keybord_bg') {layoutNode.children[j].getComponent(Sprite).spriteFrame = layoutNode.children[j].getComponent(Sprite).spriteAtlas.getSpriteFrame('keybord_partright');}}}}}}    

上述代码中调用的this.readyToNext()是将“ENTER”键的显示内容变化成“NEXT”,此时玩家点击后将开起第二局游戏。为了方便玩家识别,做了背景色的变化。代码如下:

    readyToNext() {//游戏结束时,将当前选中节点置空gamemanager.instance.setCurrentBtnNode(null);gamemanager.instance.setCurrentLayoutNode(null);this.setENTERBtnInfo('NEXT',new Color(17,235,130));     }

最后在home.ts中创建onClick函数,此函数将绑定到ENTER键的点击事件上。判断“ENTER”键的显示内容若为“ENTER”则调用submitAnswer进行答案提交,若为“NEXT”,则还原“ENTER”键的初始社会并调用initgame开始下一局游戏。代码如下:

   setENTERBtnInfo(smessage : string,color : Color){//还原ENTER键的背景和显示内容let homeNode = gamemanager.instance.getHomeNode();let ENTERNode = homeNode.getChildByPath('top/Layout_bottom4/ENTER');ENTERNode.getChildByName('Label').getComponent(Label).string = smessage;ENTERNode.getComponent(Sprite).color = color;ENTERNode.angle = 0;}startNextGame() { //开始下一局游戏this.setENTERBtnInfo('ENTER',new Color(255,255,255));        this.initgame(); }onClick (){//ENTER键点击事件let homeNode = gamemanager.instance.getHomeNode();let ENTERNode = homeNode.getChildByPath('top/Layout_bottom4/ENTER');if (ENTERNode.getChildByName('Label').getComponent(Label).string === 'NEXT') {this.startNextGame();}else {this.submitAnswer();}}

事件绑定的操作前面已经介绍过,这里不再累述。最终“ENTER”键的设置如下:

三、制作消息提示框和游戏结果信息提示框

在游戏中提示框是很常见的组件,需要制作为prefab在代码中动态加载,实现组件的重复利用。动态加载的功能已经在Util.ts脚本中封装好。prefab的制作方法在前面已经介绍过,这里不再累述,只是介绍一下提示框的UI和功能设计。

消息提示框设计如下

1、messageBox为一个空节点。

2、Mask为Sprite(单色):大小设置为宽720,高1280,。并且绑定一个button组件,UIOpacity组件。将UIOpacity设置为0(完全透明),button按钮事件数量设置为0。

这样设计的目的是为了让Mask成为一个透明遮罩,当提示框显示出来时,用户点击Sprite以外的区局也就无法触发“空格”上的点击事件。

3、Sprite为Sprite。作为背景图,添加一个UIOpacity组件,透明度设置为100。

4、Label。主要设置一下字体,颜色。Sprite和Label的大小根据自己喜好自行设定即可。

界面设计完成后,再创建一个messageBox.ts脚本文件绑定到messageBox这个空节点上。messageBox.ts实现的功能也很简单,如下:

import { _decorator, Component, Node, tween, Sprite, UIOpacity } from 'cc';
const { ccclass, property } = _decorator;@ccclass('messageBox')
export class messageBox extends Component {private tweenObj = null;onLoad () {let self = this;this.tweenObj = tween(this.node.getChildByName('Sprite').getComponent(UIOpacity)).to(0.3,{opacity : 255}).delay(1).call(function () {self.node.destroy();});}start () {this.tweenObj.start();}
}

在加载的时候创建一个动画,在0.3秒内将Sprite的透明度变化到255,延迟一秒,调用self.node.destroy()将节点销毁,此时提示框也就消失了。

Util.showDiolag('prefab/messageBox',homeNode.parent,(newNode) =>{
                if(newNode) {
                    newNode.getChildByName('Label').getComponent(Label).string = err;
                }                
            });

第一个参数是prefab的路径和prefab的名称,prefab是在resources目录下的文件夹,messageBox是prefab的名称。homeNode是prefab将要加载到哪个节点下,这里的homeNode也就是home节点。通过回调函数给messageBox中的Label复制,显示提示消息。最终实现的效果就是弹出一个提示框,提示框有一个透明的变化,由半透明变化到不透明,并且显示1秒后就自动销毁,不用玩家再手工关闭。

游戏结果提示框设计如下:

1、resultBox是空节点。宽720,高1280

2、mask和消息提示框prefab中的mask一样。

3、content是Sprtie,背景为一张黄色的图片。

4、title是Label,用于显示游戏结果。

5、message是Label,用于显示答案。

6、btn是按钮,点击后关闭该提示框。

新建resultBox.ts脚本将脚本挂载到resultBox空节点上。代码如下:


import { _decorator, Component, Node } from 'cc';
const { ccclass, property } = _decorator;@ccclass('resultBox')
export class resultBox extends Component {onClick() {this.node.destroy();}
}

然后将onClick函数绑定到btn按钮的点击事件上即可。调用方式:

Util.showDiolag('prefab/resultBox',homeNode.parent,(newNode)=>{
                if(newNode){
                    newNode.getChildByName('content').getChildByName('title').getComponent(Label).string = '恭喜你答对了!';
                    newNode.getChildByName('content').getChildByName('message').getComponent(Label).string = 
                    '答案是:' + sCorrectAnswer;                    
                }
            });

和messageBox一样,就不再详细描述了。

四、音效播放功能实现:

作为一个游戏来说,音效是不可或缺的元素,没有声音的游戏显得太苍白了。在Cocos Creator3.x版本中提供了AudioSource组件来实现音效的播放这与2.x版本中不一样,好在官方在demo示例中提供了完整使用案例。直接拿过来用即可。

新建audioManager.ts脚本,代码如下:


import { _decorator, Component,AudioClip,AudioSource,assetManager,assert,warn, resources } from 'cc';
const { ccclass, property } = _decorator;@ccclass('audioManager')
export class audioManager extends Component {private static _instance: audioManager;private static _audioSource?: AudioSource;//单例模式 static get instance () {if (this._instance) {return this._instance;}this._instance = new audioManager();return this._instance;}soundVolume : number = 1;//初始化函数,在gameRoot调用init (audioSource: AudioSource) {audioManager._audioSource = audioSource;}/*** 播放音效* @param {String} name */playSound(name: string){const audioSource = audioManager._audioSource!;assert(audioSource,'AudioSource not inited!');let path = 'sound/';resources.load(path + name,AudioClip,(err: any,audioClip: AudioClip) =>{if (err) {warn('load audioClip failed: ',err);}audioSource.playOneShot(audioClip,this.soundVolume);});}/*** 播放远程音效* @param {String} url */playRemote(url: string){const audioSource = audioManager._audioSource!;assert(audioSource,'AudioSource not inited!'); console.log(url);assetManager.loadRemote(url,{ext : '.mp3'},(err, audioClip : AudioClip) => {if (err) {warn('load audioClip failed: ',err);}audioSource.playOneShot(audioClip,this.soundVolume);        })}setSoundVolume(volume: number){this.soundVolume = volume;}openSound () {this.setSoundVolume(1);}closeSound () {this.setSoundVolume(0);}start () {// [3]}// update (deltaTime: number) {//     // [4]// }
}

audioManager.ts我是在官方提供的示例中直接复制的,只保留了我需要的playSound()函数。在此基础上新增了另外一个播放远程音效的功能playRemote。音频文件一般使用mp3格式,需要存放在resources文件夹下才能动态加载,为了便于管理,音频文件都统一存放在resources下的sound文件夹中。

新建gameRoot.ts脚本,挂载到gameRoot节点下。gameRoot在之前已经介绍过,作为场景下的第一个节点,在代码中注册为常驻节点并挂载AudioSource组件。代码如下:


import { _decorator, Component, AudioSource,assert,game } from 'cc';
import { audioManager } from './audioManager';const { ccclass, property } = _decorator;@ccclass('gameRoot')
export class gameRoot extends Component {@property(AudioSource)private _audioSource: AudioSource = null;onLoad(): void{const audioSource = this.getComponent(AudioSource);assert(audioSource);this._audioSource = audioSource;//将gameRoot节点注册为常驻节点game.addPersistRootNode(this.node);audioManager.instance.init(this._audioSource);}
}

gameRoot节点下挂载audioSource组件:

调用方式:

audioManager.instance.playSound('btn_click');

'btn_click'就是键盘按钮点击的音频文件,通过指定音频文件的名称就可以进行播放,很方便。

这里要注意一下,在网上搜索音频文件的时候要确认好是否有版权。不想付费的话就只能选没有版权的音频文件(知识付费的年代不好白嫖啊)。另外推荐一个免费的压缩工具,这个工具是网页版并且免费的,压缩比例也比较高。这个是为了后续发布出来的程序包尽量小一点,微信小游戏的发布有限制,首包只能小于4M。每一KB都要斤斤计较。

到此游戏的基本玩法功能都实现完了,调试的时候发现少了一个功能(“DEL”清除键的功能还没有实现)。清除功能也简单,就是将当前选中的“空格”中的内容清空,并切换一下背景。新建btn_backspace.ts脚本文件,代码如下:


import { _decorator, Component,Sprite, Node, Label, Button } from 'cc';
import { audioManager } from './audioManager';
import { gamemanager } from './gamemanager';
const { ccclass, property } = _decorator;@ccclass('btn_backspace')
export class btn_backspace extends Component {onClick () {audioManager.instance.playSound('btn_click');let layoutNode = gamemanager.instance.getCurrentLayoutNode();let btnNode = gamemanager.instance.getCurrentBtnNode();   //游戏结束时CurrentLayoutNode被置空,再次点击DEL按钮就不要操作了if (!layoutNode) {return;}    //如果当前选中的空格为空,则选最右边的空格if (!btnNode) {btnNode = layoutNode.children[layoutNode.children.length - 1];gamemanager.instance.setCurrentBtnNode(btnNode);}this.clearBtnNode(btnNode);}clearBtnNode (btnNode) {btnNode.getChildByName('Sprite').getComponent(Sprite).spriteFrame = btnNode.getChildByName('Sprite').getComponent(Sprite).spriteAtlas.getSpriteFrame('btn_border');btnNode.getChildByName('Label').getComponent(Label).string = '';        gamemanager.instance.showBtnClearTween(btnNode);        }}

将 btn_backspace.ts挂载到“DEL”按键上,并绑定onClick时间:

至此 游戏的基本玩法功能就已经全部实现了,赶紧试玩一下吧。

五、注意事项:

在VS CODE中修改了代码以后,一定要切换到Cocos Creator编辑器中。此时,Cocos Creator编辑器的左下方会冒出一个小弹窗显示出哪些脚本文件被修改了,这就代表Cocos Creator重新加载了这些被修改的脚本文件。然后你在VS CODE中按F5进行调试的时候才是最新的代码,不切换一下的话你在VS CODE中修改了代码直接F5运行的话,还是运行的之前的老代码。这个坑我也是踩了好几次。

微信小游戏实战--cocos creator实现wordle游戏(五)相关推荐

  1. 微信小游戏实战--cocos creator实现wordle游戏(六)

    就wordle游戏本身而言它已经完成了,但我并不打算就到此为止."麻雀虽小五脏俱全",从"完整"的角度来看,它还缺少一些"必不可少"的功能: ...

  2. 微信小游戏实战--cocos creator实现wordle游戏(一)

    前言 前段时间赋闲在家,整理电脑上的资料时才发现从业这么多年都是在给公司打工,没为自己写过点什么,所以决定为自己写一个完整的"产品".同时,为了检验一下自己的学习能力,选择了从未接 ...

  3. 【10086个赞】Cocos Creator助力H5游戏大爆发

    梦想起航,共筑辉煌.4月21日,"资本助推H5行业发展--2017·H5-GAME资深大咖荟"在厦门创+会议中心正式拉开帷幕. 作为一个新兴行业,H5游戏至去年年末便被众多从业者炒 ...

  4. 视频教程-老司机讲前端之微信小程序开发成语消消乐游戏视频课程-微信开发

    老司机讲前端之微信小程序开发成语消消乐游戏视频课程 中国实战派HTML5培训第一人,微软技术讲师,曾任百合网技术总监,博看文思HTML5总监.陶国荣长期致力于HTML5.JavaScript.CSS3 ...

  5. 老司机讲前端之微信小程序开发成语消消乐游戏视频课程-陶国荣-专题视频课程...

    老司机讲前端之微信小程序开发成语消消乐游戏视频课程-102人已学习 课程介绍         本课通过一个完整.真实的游戏项目,带着学员手动开发代码,本课分项目介绍.界面效果.技术分析.代码实现.打包 ...

  6. axure 小程序 网盘_万门大学微信小程序实战开发特训班【完结】网盘高清全套最新系列精品课程...

    万门大学微信小程序实战开发特训班[完结]网盘高清全套最新系列精品课程 课 程 简介 我买了这个课程,课程很有价值,我们通过链接或百度网盘群的形式在共享资料库中与您共享,需要万门大学微信小程序实战开发特 ...

  7. 微信小程序实战篇:商品属性联动选择(案例)

    本期的微信小程序实战篇来做一个电商网站经常用到的-商品属性联动选择的效果,素材参考了一点点奶茶. 效果演示: 商品属性联动.gif 代码示例 1.commodity.xml <!-- <v ...

  8. 微信小程序实战开发视频

    微信小程序实战开发视频: 链接:http://pan.baidu.com/s/1jIAwBLs     密码:ej3b

  9. 小程序swiper怎么让内容撑开高度_[视频]微信小程序实战优购商城,涵盖你所学的技能点...

    很多友友都在找视频教程学习,IT技术教程分享网[http://www.mano100.cn]已经为你收集了各种各样的视频教程,不用再到处找视频教程学习了.无论是免费的,还是收费的,都在这里了.只要你注 ...

最新文章

  1. javascript ES6有趣的Set,数组去重、并集、交集、差集
  2. 《深入剖析Tomcat》一2.2 应用程序 1
  3. Lambda-常用函数式接口
  4. Mysql合并两个sql结果
  5. AcWing 827. 双链表
  6. 青少年计算机知识,学习计算机程序设计和算法知识对青少年教育有什么帮助?...
  7. PHP面试100题汇总
  8. c语言for语句用法和例子
  9. Linux系统安装DB2数据库详解
  10. eds能谱图分析实例_SPC控制图公式_均值极差SPC控制图公式应用实例分析
  11. 分布式常见面试题总结(2021)
  12. js获取本机ip地址
  13. C语言三款游戏(贪吃蛇、推箱子、小鸟飞飞)(含gui)(含完整代码、粘贴即用)
  14. 移动通信之蜂窝数据网络
  15. 软件调试高级研习班庐山秀峰站(2017-06)
  16. 游戏开发团队及工作流程
  17. vscode使用注意事项
  18. css单位-vh/vw
  19. p设计一个Person类,属性有姓名、年龄、性别,创建方法personInfo,打印输出这个人的信息;创建Student类,继承Person类,属性有学院college,班级Group,重写父类Per
  20. 公募基金主要业务逻辑

热门文章

  1. 【推荐】智慧电力智能化巡检在线监控信息化平台系统建设推荐解决方案合集(共60份,363M)
  2. 相机稳定性测试软件,用于天文观测的科学级相机成像和测试软件的研究
  3. java各类英文的意思,附源代码
  4. sip篇——sip协议是什么?
  5. 旧电脑千万不要扔掉!它的剩余价值多得超乎想象!
  6. 用集群脚本功能安装大象医生优化你的大数据作业
  7. Python实现列表匹配
  8. 【小程序源码】看成语猜古诗句好玩解闷小游戏
  9. 本经阴符七术(鬼谷子术数),译文奉献给各位朋友
  10. matlab plot点线的一些参数设置