CocosCreator学习1:做一个简单的游戏

来源:互联网 发布:创可贴的网络意思 编辑:程序博客网 时间:2024/05/29 02:32

把计步器写好了,到了写游戏场景、控件什么的时候,傻眼了。想做一个简单的地图,可以在地图上点击选择城市,发现用Cocos2D-X代码码出来好麻烦,尤其是城市位置问题,需要调试去找对像素区域做一个按钮控制,整个人都不好了。本来还想尝试用Tiled map来做,想法很逗比,应该不能用。今晚被长辈连番教育中,说到了撞墙走弯路才想起来,当初光顾着学引擎看代码了,竟然忘了还有CocosCreator,这么简单实用的工具我竟然没有去用,太傻了。而且现在距离比较提交程序结果时间也比较紧了,直接用CocosCreator做游戏时最明智的。下面将转向CocosCreator的学习。

CocosCreator有很详细的入门教程,下面我就跟随这个教程来进行学习。
http://www.cocos.com/docs/creator/getting-started/quick-start.html#–2

打开项目

教程中提供了一个简单游戏的初始版本,我就从这个游戏入手进行学习。从CocosCreator选择打开其他项目,打开start_project文件夹,选中即可打开。注意下载的start_project不能放在CocosCreator路径下。

打开后如图:
这里写图片描述

在资源管理器面板中,可以看到项目中的文件。项目资源的根目录叫asserts,对应于解压初始版本得到的文件夹名。其中标注bf图标的文件是位图字体,是一种字体资源,由fnt文件和同名的png图片文件共同组成。

创建场景

下面来创建游戏场景。游戏场景一般包括:场景图像(Sprite)、文字(Label)、角色、以组件形式附加在场景节点上的游戏逻辑脚本。在资源管理器中点击asserts目录前面的加号,选择Scene,会创建一个New Scene的场景文件。
这里写图片描述
双击New Scene,就会在场景编辑器和层级管理器中打开这个场景。在层级管理器中可以看到当前场景的所有节点和他们的层级关系。

Canvas画布节点/渲染根节点

现在New Scene中只有一个Canvas节点,称为画布节点或渲染根节点,点击选中Canvas可以在属性检查器中看到他的属性。
这里写图片描述
这里写图片描述
其中的Design Resolution属性用来指定游戏分辨率,Fit Hight和Fit Width是分辨率自适应匹配方法。只需要把图像放到Canvas下,就可以完成对不同分辨率的自适应,非常简单。

设置场景图像

增加背景图像

在资源管理器中将textures中background图像拖到
层级管理器的Canvas下即可增加背景图像,会看到Canvas下增加了一个background子节点。
这里写图片描述
点击文件->保存场景或使用快捷键ctrl+s保存场景后,在场景编辑器中便会显示增加的背景图像。
这里写图片描述
点击窗口左上角工具栏的第四格矩形变换工具,然后选中场景编辑器中的背景图像,可以实现对图像尺寸、位置、锚点的修改。
这里写图片描述
当然也可以直接使用属性检查器来直接设置这些参数。
在实际的应用开发中背景图像一般都是要大于显示范围的,这样可以让背景图覆盖整个屏幕,不出现穿帮的情况。

增加地面
使用和增加背景图像相同的方法,将地面图像拖到层级管理器的Canvas上,将ground节点移到background节点下方。
这里写图片描述
在层级管理器中,下方的节点的渲染顺序在上方节点之后,也就是说下方节点会遮挡上方节点。
这里写图片描述
使用相同的方法可以对地面图像的尺寸、位置、锚点进行修改。

增加主角
同样的方法,将主角图像player拖到ground下方。在之后的动画中,需要主角接触地面并跳跃,因此将锚点改为最下方,即y值为0,然后将它拖到地面上。
这里写图片描述

编写脚本

创建并添加脚本
脚本也就是游戏的逻辑规则,需要代码实现。
首先在资源管理器中右键点击assets文件夹,新建->文件夹,创建一个名为New Folder的文件夹,然后对其右击选择新建->JavaScript,创建一个JavaScript脚本NewScript,重命名为Player,双击即可打开编写界面。Cocos Creator 中脚本名称就是组件的名称。
在Player中的properties部分增加以下代码:

// Player.js    //...    properties: {        // 主角跳跃高度        jumpHeight: 0,        // 主角跳跃持续时间        jumpDuration: 0,        // 最大移动速度        maxMoveSpeed: 0,        // 加速度        accel: 0,    },    //...

这些属性用于规定主角的移动方式,可以在属性检查器中直接设置属性的数值。

然后在层级编辑器中选择player,在属性检查器中选择添加组件,选择增加用户脚本组件->Player,即可为主角添加组件。

现在可以在属性检查器看到Player组件并修改属性数值了。
这里写图片描述

跳跃和移动代码
在properties代码块下面定义setJumpAction方法:

// Player.js    properties: {        //...    },    setJumpAction: function () {        // 跳跃上升        var jumpUp = cc.moveBy(this.jumpDuration, cc.p(0, this.jumpHeight)).easing(cc.easeCubicActionOut());        // 下落        var jumpDown = cc.moveBy(this.jumpDuration, cc.p(0, -this.jumpHeight)).easing(cc.easeCubicActionIn());        // 不断重复        return cc.repeatForever(cc.sequence(jumpUp, jumpDown));    },

修改onLoad: function:

// Player.js    onLoad: function () {        // 初始化跳跃动作        this.jumpAction = this.setJumpAction();        this.node.runAction(this.jumpAction);    },

onLoad方法会在场景加载完成后立即执行,所以在这里进行初始化操作。
保存脚本运行一下试试,可以看到player不断的在进行跳跃动作。

在setJumpAction下面定义setInputControl方法来实现用A和D控制主角的移动操作:

// Player.js    setJumpAction: function () {        //...    },    setInputControl: function () {        var self = this;        // 添加键盘事件监听        cc.eventManager.addListener({            event: cc.EventListener.KEYBOARD,            // 有按键按下时,判断是否是我们指定的方向控制键,并设置向对应方向加速            onKeyPressed: function(keyCode, event) {                switch(keyCode) {                    case cc.KEY.a:                        self.accLeft = true;                        self.accRight = false;                        break;                    case cc.KEY.d:                        self.accLeft = false;                        self.accRight = true;                        break;                }            },            // 松开按键时,停止向该方向的加速            onKeyReleased: function(keyCode, event) {                switch(keyCode) {                    case cc.KEY.a:                        self.accLeft = false;                        break;                    case cc.KEY.d:                        self.accRight = false;                        break;                }            }        }, self.node);    },

修改onLoad方法,在其中加入向左和向右加速的开关,以及主角当前在水平方向的速度,最后再调用我们刚添加的setInputControl方法,在场景加载后就开始监听键盘输入:

// Player.js    onLoad: function () {        // 初始化跳跃动作        this.jumpAction = this.setJumpAction();        this.node.runAction(this.jumpAction);        // 加速度方向开关        this.accLeft = false;        this.accRight = false;        // 主角当前水平方向速度        this.xSpeed = 0;        // 初始化键盘输入监听        this.setInputControl();    },

最后修改update方法,添加加速度、速度和主角当前位置的设置:

// Player.js    update: function (dt) {        // 根据当前加速度方向每帧更新速度        if (this.accLeft) {            this.xSpeed -= this.accel * dt;        } else if (this.accRight) {            this.xSpeed += this.accel * dt;        }        // 限制主角的速度不能超过最大值        if ( Math.abs(this.xSpeed) > this.maxMoveSpeed ) {            // if speed reach limit, use max speed with current direction            this.xSpeed = this.maxMoveSpeed * this.xSpeed / Math.abs(this.xSpeed);        }        // 根据当前速度更新主角的位置        this.node.x += this.xSpeed * dt;    },

这样就可以实现对主角移动的控制了。

制作Prefab脚本-星星
这里增加游戏规则,从随机位置生成星星,用主角接住星星即可得分。
对于重复生成的节点,可以保存成Prefab(预置)资源,作为动态生成节点时的模板。
这里直接将assets/textures/star资源到场景中,位置随意,给星星增加一个脚本,当主角碰到星星时,让星星消失。

// Star.js    properties: {        // 星星和主角之间的距离小于这个数值时,就会完成收集        pickRadius: 0    },

给star节点增加脚本,将pickRadius值设置为60。将层级管理器中的star节点拖到资源管理器的assets文件夹下,将场景中的star节点删除。star现在即为Prefab资源。

添加游戏控制脚本
在assets/scripts文件夹下添加游戏的主逻辑脚本Game,添加生成星星需要的属性:

// Game.js    properties: {        // 这个属性引用了星星预制资源        starPrefab: {            default: null,            type: cc.Prefab        },        // 星星产生后消失时间的随机范围        maxStarDuration: 0,        minStarDuration: 0,        // 地面节点,用于确定星星生成的高度        ground: {            default: null,            type: cc.Node        },        // player 节点,用于获取主角弹跳的高度,和控制主角行动开关        player: {            default: null,            type: cc.Node        }    },

然后将Game添加到Canvas节点上,然后将star这个Prefab资源拖到Canvas属性检查器Game组件中的Star Prefab属性上。把层级管理器中的ground和Player节点也拖到组件中相应属性处即可。设置Min Star Duration和Max Star Duration值为3和5,之后生成星星时,会在这两个值之间随机取值作为星星消失前经过的时间。

在随机位置生成星星
修改Game脚本,在onLoad方法后面添加星星的逻辑:

// Game.js    onLoad: function () {        // 获取地平面的 y 轴坐标        this.groundY = this.ground.y + this.ground.height/2;        // 生成一个新的星星        this.spawnNewStar();    },    spawnNewStar: function() {        // 使用给定的模板在场景中生成一个新节点        var newStar = cc.instantiate(this.starPrefab);        // 将新增的节点添加到 Canvas 节点下面        this.node.addChild(newStar);        // 为星星设置一个随机位置        newStar.setPosition(this.getNewStarPosition());    },    getNewStarPosition: function () {        var randX = 0;        // 根据地平面位置和主角跳跃高度,随机得到一个星星的 y 坐标        var randY = this.groundY + cc.random0To1() * this.player.getComponent('Player').jumpHeight + 50;        // 根据屏幕宽度,随机得到一个星星 x 坐标        var maxX = this.node.width/2;        randX = cc.randomMinus1To1() * maxX;        // 返回星星坐标        return cc.p(randX, randY);    }

添加主角碰触收集星星的行为
重点在于星星要随时获取主角节点的位置,才能判断与主角的距离是否小于可收集距离。因此将Game组件的实例传给星星并保存,然后可以随时通过game.player来访问主角节点。
在Game脚本的spawnNewStar方法最后添加如下代码:

// Game.js    spawnNewStar: function() {        // ...        // 将 Game 组件的实例传入星星组件        newStar.getComponent('Star').game = this;    },

然后在star脚本里onLoad方法后面添加getPlayerDistance和onPicked方法:

// Star.js    getPlayerDistance: function () {        // 根据 player 节点位置判断距离        var playerPos = this.game.player.getPosition();        // 根据两点位置计算两点之间距离        var dist = cc.pDistance(this.node.position, playerPos);        return dist;    },    onPicked: function() {        // 当星星被收集时,调用 Game 脚本中的接口,生成一个新的星星        this.game.spawnNewStar();        // 然后销毁当前星星节点        this.node.destroy();    },

在update方法中添加每帧判断距离,如果距离小于pickRadius属性规定值,就执行收集行为:

// Star.js    update: function (dt) {        // 每帧判断和主角之间的距离是否小于收集距离        if (this.getPlayerDistance() < this.pickRadius) {            // 调用收集行为            this.onPicked();            return;        }    },

现在可以看效果了。
这里写图片描述

添加计分牌
在层级管理器的Canvas中右键创建新节点->创建渲染节点->Label(文字),命名为score。将position设为(0,180),string设为score:0,Font Size设为50。从资源管理器中将assets/mikado_outline_shadow位图字体资源拖到Font属性中。
这里写图片描述

添加得分逻辑
在Game的properties里添加score需要的属性:

// Game.js    properties: {        // ...        // score label 的引用        scoreDisplay: {            default: null,            type: cc.Label        }    },

在onLoad方法里添加计分用的变量初始化:

// Game.js    onLoad: function () {        // ...        // 初始化计分        this.score = 0;    },

在update方法后面添加gainScore的新方法:

// Game.js    gainScore: function () {        this.score += 1;        // 更新 scoreDisplay Label 的文字        this.scoreDisplay.string = 'Score: ' + this.score.toString();    },

将score节点拖到Canvas属性的Game组件中的Score Display属性中。
在Star脚本的onPicked方法中添加gainScore的调用:

// Star.js    onPicked: function() {        // 当星星被收集时,调用 Game 脚本中的接口,生成一个新的星星        this.game.spawnNewStar();        // 调用 Game 脚本的得分方法        this.game.gainScore();        // 然后销毁当前星星节点        this.node.destroy();    },

这样收集到星星,分数就会变化了。
这里写图片描述

失败判断和重新开始
加入给星星加入计时消失的逻辑,在Game脚本的onLoad方法的spawNewStar调用之前加入需要的变量声明:
// Game.js
onLoad: function () {
// …
// 初始化计时器
this.timer = 0;
this.starDuration = 0;
// 生成一个新的星星
this.spawnNewStar();
// 初始化计分
this.score = 0;
},
然后在spawnNewStar方法最后加入重置计时器的逻辑,其中this.minStarDuration和this.maxStarDuration是我们一开始声明的Game组件属性,用来规定星星消失时间的随机范围:

// Game.js    spawnNewStar: function() {        // ...        // 重置计时器,根据消失时间范围随机取一个值        this.starDuration = this.minStarDuration + cc.random0To1() * (this.maxStarDuration - this.minStarDuration);        this.timer = 0;    },

在update方法中加入计时器更新和判断超过时限的逻辑:

// Game.js    update: function (dt) {        // 每帧更新计时器,超过限度还没有生成新的星星        // 就会调用游戏失败逻辑        if (this.timer > this.starDuration) {            this.gameOver();            return;        }        this.timer += dt;    },

最后加入gameOver方法,游戏失败重新加载场景。

// Game.js    gameOver: function () {        this.player.stopAllActions(); //停止 player 节点的跳跃动作        cc.director.loadScene('game');    }

然后修改Star脚本,加入即将消失星星的提示效果,在update方法中加入以下代码:

// Star.js    update: function() {        // ...        // 根据 Game 脚本中的计时器更新星星的透明度        var opacityRatio = 1 - this.game.timer/this.game.starDuration;        var minOpacity = 50;        this.node.opacity = minOpacity + Math.floor(opacityRatio * (255 - minOpacity));    }

这样游戏画面和逻辑就全部完成了,可以说游戏已经基本完成了。

加入音效
首先加入跳跃音效,在Player脚本中引用声音文件资源jumpAudio属性:

// Player.js    properties: {        // ...        // 跳跃音效资源        jumpAudio: {            default: null,            url: cc.AudioClip        },    },

修改setJumpAction方法,插入播放音效的回调,并通过添加playJumpSound方法来播放声音:

// Player.js    setJumpAction: function () {        // 跳跃上升        var jumpUp = cc.moveBy(this.jumpDuration, cc.p(0, this.jumpHeight)).easing(cc.easeCubicActionOut());        // 下落        var jumpDown = cc.moveBy(this.jumpDuration, cc.p(0, -this.jumpHeight)).easing(cc.easeCubicActionIn());        // 添加一个回调函数,用于在动作结束时调用我们定义的其他方法        var callback = cc.callFunc(this.playJumpSound, this);        // 不断重复,而且每次完成落地动作后调用回调来播放声音        return cc.repeatForever(cc.sequence(jumpUp, jumpDown, callback));    },    playJumpSound: function () {        // 调用声音引擎播放声音        cc.audioEngine.playEffect(this.jumpAudio, false);    },

然后加入得分音效,在Game脚本的properties添加引用声音文件:

// Game.js    properties: {        // ...        // 得分音效资源        scoreAudio: {            default: null,            url: cc.AudioClip        }    },

在gainScore方法添加播放声音的代码:

// Game.js    gainScore: function () {        this.score += 1;        // 更新 scoreDisplay Label 的文字        this.scoreDisplay.string = 'Score: ' + this.score.toString();        // 播放得分音效        cc.audioEngine.playEffect(this.scoreAudio, false);    },

在层级管理器中,将assets/audio/jump声音资源拖到Player节点的组件Jump Audio属性上。将assets/audio/score资源拖拽到Canvas节点Game组件的Score Audio属性上。
大功告成,一个完整的游戏就做好了。

0 0
原创粉丝点击