版权申明:

  • 本文原创首发于以下网站:
  1. 博客园『优梦创客』的空间:https://www.cnblogs.com/raymondking123
  2. 优梦创客的官方博客:https://91make.top
  3. 优梦创客的游戏讲堂:https://91make.ke.qq.com
  4. 『优梦创客』的微信公众号:umaketop
  • 您可以自由转载,但必须加入完整的版权声明!

游戏原图


游戏介绍

  • 《信使(The Messenger)》是一款横版过关冒险游戏,此游戏在IGN上获得了8.0分的不错成绩,IGN编辑MITCHELL SALTZMAN认为《信使》拥有很多想带给玩家的内容。它是一款2D动作平台游戏,拥有华丽的美学,从8位风格无缝过渡到16位,游戏拥有一些搞笑的幽默场景,巧妙的对白,以及一个最佳的复古"芯片风”音乐。
  • 《信使(The Messenger)》无论从哪一方面来看都是受到了FC时代《忍者龙剑传》的影响,这款游戏的发行商Devolver Digital还邀请到了FC《忍者龙剑传》初代的制作人吉沢秀雄进行体验。

    游戏规则介绍

  • 游戏的操作与FC上的忍龙基本一致,左右移动、跳、落(从平台上落下)、攻击

    游戏开发过程

    搭建游戏UI界面

  • 在assets上创建一个文件夹名为Scence,这个文件夹用来存放场景,新建一个场景Scence改名为Game
  • 在Canvas上建一个Background节点,在这个节点上插入Sprite(图片精灵)组件,把背景图片拖进去,调整大小,这个就是游戏的背景
  • 在Canvas上新建节点Ground、Platform、Wall、Pitfall、Save、Lame,分别用来放置地面、平台、墙、陷阱、保存点、灯

    创建主角

  • 将一张忍者的图片拉至Canvas节点下,并重命名为Player

    制作动画特效

  • 在资源管理器的assets文件夹下创建一个子文件夹Animation,用来存放各种动画
  • 选择Player,在动画编辑器中点击按钮《添加Animation组件》为Player节点添加动画组件
  • 在点击按钮《新建Clip文件》为Player创建动画
  • 单击动画编辑器左上角的书写图标按钮开始编辑动画
  • 将主角的往右跑的4张图片组合成主角右跑动画(序列帧动画)
  • 再创建主角左跑动画、攻击动画、爬墙动画······

    写脚本

    Player脚本

    创建Player脚本
  • 在资源管理器的assets文件夹下创建一个子文件夹Script,用来存放各种脚本
  • 在资源管理器的Script文件夹下创建一个JavaScript脚本,重命名为Player
  • 将脚本Player挂在Player对象上

    编辑Player脚本
    定义玩家属性
properties: {camera: { //摄像机type: cc.Node, //属性类型default: null, //默认值},jumpHeight: 200, //跳跃高度playerState: 2, //玩家状态 0站立 1跳 2落 3爬墙isRun: false,  //是否跑动playerDirection: 1, //玩家方向 0左 1右     mayJump: true, //能否跳跃speed: 0, //速度hp: 5, //生命值time: 0, //时间shinState: 0, //攀爬状态 0为不动 1为上爬 2为下滑     isAttack: false, //是攻击状态whetherSpringback: true, //是否回弹
},
给玩家创建各种能力(函数)
  • 攻击
attack() {this.isAttack = true; //是攻击状态 if (this.playerDirection == 0) { //如果玩家方向为左this.getComponent(cc.Animation).play("主角左攻动画");} else { //否则this.getComponent(cc.Animation).play("主角右攻动画");}this.node.getComponent(cc.BoxCollider).size = cc.size(140, 87); //获取主角的碰撞器,并设置包围盒大小(扩大包围盒,因为攻击时人物的包围盒要把刀包围进去)
},
  • 左移
leftMove() {this.node.x -= 10
},
  • 右移
rightMove() {this.node.x += 10;
},
  • 攀爬,触碰墙壁进入爬墙状态后可使用爬墙方法
shin() {if (this.shinState == 1) { //如果人物攀爬状态为上爬this.node.y += 3;} else if (this.shinState == 2) { //否则,就是人物状态为下滑this.node.y -= 9;}
},
  • 跳跃,在平台、地面、空中时可执行
jumpAction: null,
jump() {this.jumpAction = cc.moveBy(0.5, cc.v2(0, this.jumpHeight)).easing(cc.easeCubicActionOut());this.node.runAction(this.jumpAction);
},
  • 爬墙跳,此方法只有攀爬在墙壁上时可使用
jumpDistance: null,
wallJump: null,
WallJump() {if (this.playerDirection == 0) {this.jumpDistance = 200;} else {this.jumpDistance = -200;}this.wallJump = cc.moveBy(0.5, cc.v2(this.jumpDistance, this.jumpHeight)).easing(cc.easeCubicActionOut());this.node.runAction(this.wallJump);
},
  • 翻跳上地面,当与墙壁结束碰撞时执行,用于结束攀爬进入站立状态
WallGroundJump() {if (this.playerDirection == 0) {this.jumpDistance = -100;this.getComponent(cc.Animation).play("主角左跳动画");} else {this.jumpDistance = 100;this.getComponent(cc.Animation).play("主角右跳动画");}var WallJump = cc.moveBy(0.25, cc.v2(this.jumpDistance, this.jumpHeight / 2));this.node.runAction(WallJump);
},
  • 落下,这是一个被动方法,只要玩家在空中且没有上升力,此方法就一直执行
drop(speed) {this.node.y += speed;
},
主角的碰撞处理
  • 碰撞开始
onCollisionEnter: function (other, self) { //处理碰撞的方法if (other.node.group == "Ground" || other.node.group == "Platform") { //如果玩家碰到的是节点分组中的地面,或平台this.otherObject = other; //获取另一个对象(玩家碰撞的对象)if (this.speed < -30) { //如果速度过快this.hp = 0; //摔死}if (self.node.getComponent("Player").playerState == 2 && other.node.y < self.node.y) { //如果玩家状态为下落self.node.getComponent("Player").playerState = 0; //玩家状态变为站立self.node.y = other.node.y + other.node.height / 2 + 42; //回弹,防止人物脚陷入地面if (this.isRun) { //如果是跑动状态if (this.playerDirection == 0) { //如果玩家方向为左this.getComponent(cc.Animation).play("主角左跑动画");} else { //否则,就是玩家方向为右this.getComponent(cc.Animation).play("主角右跑动画");}} else { //否则就是玩家不是跑动状态if (this.playerDirection == 0) { //如果玩家方向为左this.getComponent(cc.Animation).play("主角左立动画");} else { //否则,就是玩家方向为右this.getComponent(cc.Animation).play("主角右立动画");}}} else if (self.node.getComponent("Player").shinState == 2) {self.node.getComponent("Player").playerState = 0; //玩家状态变为站立if (self.node.getComponent("Player").playerDirection == 0) {self.node.x += 20;this.getComponent(cc.Animation).play("主角左立动画");} else {self.node.x -= 20;this.getComponent(cc.Animation).play("主角右立动画");}}} else if (other.node.group == "Wall") { //如果玩家碰到的是节点分组中的墙壁if (this.isAttack) { //如果是攻击状态this.isRun = false; //停止跑动if (this.playerDirection == 0) { //如果人物方向为左this.node.x += 50; //攻击到墙壁往右回弹} else { //否则(人物方向为右)this.node.x -= 50; //攻击到墙壁往左回弹}} else {if (self.node.getComponent("Player").playerState == 0) {self.node.y += 20;}this.node.stopAction(this.wallJump);self.node.getComponent("Player").playerState = 3; //玩家状态变为爬墙this.isRun = false;this.shinState = 0; //攀爬状态为不动if (this.playerDirection == 0) { //如果人物方向为左self.node.x = other.node.x + other.node.width / 2 + 25; //回弹,防止人物陷入墙壁this.getComponent(cc.Animation).play("主角左贴动画");} else { //否则,就是人物方向为右self.node.x = other.node.x - other.node.width / 2 - 25; //回弹,防止人物陷入墙壁this.getComponent(cc.Animation).play("主角右贴动画");}}} else if (other.node.group == "Pitfall") { //如果玩家碰到的是节点分组中的陷阱this.hp = 0;this.time = 0;} else if (other.node.group == "Save") { //如果玩家碰到的是节点分组中的保存点this.playerX = this.node.x;this.playerY = this.node.y;}
},
  • 碰撞过程中
onCollisionStay: function (other, self) {if (other.node.group == "Lamp") {if (this.isAttack) {this.mayJump = true;this.node.getComponent(cc.BoxCollider).size = cc.size(55, 87); //获取主角的碰撞器,并设置包围盒大小(缩小包围盒,因为攻击到灯后结束攻击人物收刀后碰撞范围变小)this.isAttack = false;this.time = 0;}}
},
  • 碰撞结束时
onCollisionExit: function (other, self) {if (this.hp > 0) {if (other.node.group == "Ground" || other.node.group == "Platform") { //如果玩家与地面或平台碰撞结束if (self.node.getComponent("Player").playerState == 0) { //如果玩家状态为站立self.node.getComponent("Player").playerState = 2; //玩家状态变为下落if (this.playerDirection == 0) { //如果玩家方向为左this.getComponent(cc.Animation).play("主角左落动画");} else { //否则,就是玩家方向为右this.getComponent(cc.Animation).play("主角右落动画");}}} else if (other.node.group == "Wall" && self.node.getComponent("Player").playerState == 3) {this.playerState = 1; //玩家状态设为跳this.WallGroundJump(); //玩家执行翻跳上地面this.speed = 100; //刚起跳时速度快this.mayJump = false; //能跳设为false}}
},
在update中刷新玩家
update(dt) {if (this.hp == 0) { //如果玩家生命值为0,就是死了     if (this.time == 0) {this.getComponent(cc.Animation).play("主角爆炸动画");}if (this.time < 0.4) {this.time += dt;} else if (this.time >= 0.4) {this.node.x = this.playerX;this.node.y = this.playerY + 30;this.speed = 0;this.playerState = 2;this.time = 0;this.isRun = false;this.hp = 5;}} else { //否则,就是活着//this.camera.x = this.node.x; //if (this.camera.x > this.node.x + 100) {this.camera.x = this.node.x //+ 100;//} else if (this.camera.x < this.node.x - 100) {this.camera.x = this.node.x //- 100;//}if (this.camera.y > this.node.y + 100) {this.camera.y = this.node.y + 100;} else if (this.camera.y < this.node.y - 100) {this.camera.y = this.node.y - 100;if (this.isAttack) { //是否是攻击状态this.time += dt; //计时if (this.time > 0.3) { //当时间大于0.3秒this.node.getComponent(cc.BoxCollider).size = cc.size(55, 87); //获取主角的碰撞器,并设置包围盒大小(缩小包围盒,因为攻击结束人物收刀后碰撞范围变小)this.isAttack = false; //将攻击状态变为falsethis.time = 0; //时间归零if (this.playerState == 0) { //如果玩家是站立状态if (this.isRun) { //如果玩家是跑动的的if (this.playerDirection == 0) { //如果玩家方向为左this.getComponent(cc.Animation).play("主角左跑动画");} else { //否则(就是玩家方向为右)this.getComponent(cc.Animation).play("主角右跑动画");}} else { //否则(就是站在不动)if (this.playerDirection == 0) { //如果玩家方向为左this.getComponent(cc.Animation).play("主角左立动画");} else { //否则(就是玩家方向为右)this.getComponent(cc.Animation).play("主角右立动画");}}} else { //否则(就是在空中)if (this.playerDirection == 0) { //如果玩家方向为左this.getComponent(cc.Animation).play("主角左落动画");} else { //否则(就是玩家方向为右)this.getComponent(cc.Animation).play("主角右落动画");}}}if (this.isRun) { //如果能跑动if (this.playerDirection == 0) { //如果玩家方向是左this.leftMove(); //向左跑} else { //否则this.rightMove(); //向右跑}if (this.playerState == 0) { //如果玩家状态为站立this.speed = 0; //速度归零this.mayJump = true; //能跳跃} else if (this.playerState == 1) { //如果玩家状态为跳this.speed -= dt * 400; //速度越来越慢if (this.speed <= 0) { //如果速度减少到小于等于0this.speed = 0; //速度归零this.node.stopAction(this.jumpAction); //停止跳this.playerState = 2; //玩家状态变为下落}} else if (this.playerState == 2) { //如果玩家状态为下落this.speed -= dt * 30; //下落状态下速度随时间变得越来越快this.drop(this.speed); //执行下落} else if (this.playerState == 3) { //如果玩家状态为爬墙this.speed = 0; //速度归零this.mayJump = true; //能跳跃this.shin(); //攀爬}}
},

Game脚本

创建Game脚本
  • 在资源管理器的Script文件夹下创建一个JavaScript脚本,重命名为Game
  • 将脚本Game挂在Canvas上

    编辑Game脚本
    在onLoad中开启碰撞监听、监听系统事件
onLoad() {var manager = cc.director.getCollisionManager(); //获取碰撞组件manager.enabled = true; //开启碰撞监听//manager.enabledDebugDraw = true; //开启碰撞组件Debugthis.playerJS = this.Player.getComponent("Player"), //获取玩家脚本//系统事件,当键被按下时调用keyDown回调函数处理cc.systemEvent.on(cc.SystemEvent.EventType.KEY_DOWN, this.keyDown, this);//系统事件,当键弹起时调用keyUp回调函数处理cc.systemEvent.on(cc.SystemEvent.EventType.KEY_UP, this.keyUp, this);
},
创建keyDown于keyUp方法用来控制玩家
  • keyDown方法
playerJS: null, //玩家脚本
keyDown(event) {if (this.playerJS.hp > 0) { //如果玩家hp大于0,就是玩家活着switch (event.keyCode) {case cc.macro.KEY.a:if (this.playerJS.isRun == false) { //如果能跑动是错误的if (this.playerJS.playerState != 3) { //如果玩家不为爬墙this.playerJS.isRun = true; //能跑动设为truethis.playerJS.playerDirection = 0; //玩家方向设为左if (this.playerJS.playerState == 0) { //如果玩家狀態為站立this.Player.getComponent(cc.Animation).play("主角左跑动画");}} else if (this.playerJS.playerDirection == 1) {this.playerJS.playerState = 1; //玩家状态设为跳this.playerJS.WallJump(); //玩家执行爬墙跳this.playerJS.playerDirection = 0; //玩家方向设为左this.playerJS.speed = 200; //刚起跳时速度快this.playerJS.mayJump = false; //能跳设为falsethis.Player.getComponent(cc.Animation).play("主角左跳动画");}}break;case cc.macro.KEY.d:if (this.playerJS.isRun == false) { //如果能跑动是错误的if (this.playerJS.playerState != 3) { //如果玩家不为爬墙this.playerJS.isRun = true; //能跑动设为truethis.playerJS.playerDirection = 1; //玩家方向设为右if (this.playerJS.playerState == 0) { //如果玩家狀態為站立this.Player.getComponent(cc.Animation).play("主角右跑动画");}} else if (this.playerJS.playerDirection == 0) {this.playerJS.playerState = 1; //玩家状态设为跳this.playerJS.WallJump(); //玩家执行爬墙跳this.playerJS.playerDirection = 1; //玩家方向设为右this.playerJS.speed = 200; //刚起跳时速度快this.playerJS.mayJump = false; //能跳设为falsethis.Player.getComponent(cc.Animation).play("主角右跳动画");}}break;case cc.macro.KEY.w:if (this.playerJS.playerState != 3) { //如果玩家状态不为爬墙if (this.playerJS.mayJump) { //如果能跳                   this.playerJS.playerState = 1; //玩家状态设为跳this.playerJS.jump(); //玩家执行跳this.playerJS.speed = 200; //刚起跳时速度快this.playerJS.mayJump = false; //能跳设为falseif (this.playerJS.playerDirection == 0) { //如果玩家方向为左this.Player.getComponent(cc.Animation).play("主角左跳动画");} else { //否则,就是玩家方向为右this.Player.getComponent(cc.Animation).play("主角右跳动画");}}} else { //否则,就是玩家为爬墙状态this.playerJS.shinState = 1; //攀爬状态设为上爬if (this.playerJS.playerDirection == 0) { //如果玩家方向为左this.Player.getComponent(cc.Animation).play("主角左爬动画");} else { //否则,就是玩家方向为右this.Player.getComponent(cc.Animation).play("主角右爬动画");}}break;case cc.macro.KEY.s:if (this.playerJS.playerState == 0) { //如果玩家状态为站立if (this.playerJS.otherObject.node.group == "Ground") { //如果玩家依附在地面上//蹲下} else if (this.playerJS.otherObject.node.group == "Platform") { //如果玩家依附在平台上//this.Player.y -= 30; //玩家y坐标减,为了快速从平台上落下(此语句可有可无)this.playerJS.playerState = 2; //玩家状态变为下落状态if (this.playerJS.playerDirection == 0) { //如果玩家方向为左this.Player.getComponent(cc.Animation).play("主角左落动画");} else { //否则,就是玩家方向为右this.Player.getComponent(cc.Animation).play("主角右落动画");}}} else if (this.playerJS.playerState == 3) { //如果玩家状态为爬墙this.playerJS.shinState = 2 //攀爬状态设为下滑if (this.playerJS.playerDirection == 0) { //如果玩家方向为左this.Player.getComponent(cc.Animation).play("主角左爬动画");} else { //否则,就是玩家方向为右this.Player.getComponent(cc.Animation).play("主角右爬动画");}}break;case cc.macro.KEY.j:if (this.playerJS.isAttack == false) { //如果玩家攻击状态为false(已经是攻击状态不能再攻击,必须等攻击结束才能再次攻击)if (this.playerJS.playerState != 3) //如果玩家不为爬墙状态(不能在爬墙时攻击){this.playerJS.attack(); //玩家执行攻击}}break;}}
},
  • keyUp方法
keyUp(event) {if (this.playerJS.hp > 0) { //如果玩家hp大于0,就是玩家活着switch (event.keyCode) {case cc.macro.KEY.a:if (this.playerJS.isRun && this.playerJS.playerDirection == 0) { //如果在跑动,并且玩家方向朝左this.playerJS.isRun = false; //能跑动设为falseif (this.playerJS.playerState == 0) { //如果玩家狀態為站立this.Player.getComponent(cc.Animation).play("主角左立动画");}}break;case cc.macro.KEY.d:if (this.playerJS.isRun && this.playerJS.playerDirection == 1) { //如果在跑动,并且玩家方向朝右this.playerJS.isRun = false; //能跑动设为falseif (this.playerJS.playerState == 0) { //如果玩家狀態為站立this.Player.getComponent(cc.Animation).play("主角右立动画");}}break;case cc.macro.KEY.w:if (this.playerJS.playerState != 3) { //如果玩家状态不为爬墙if (this.playerJS.playerState == 1) { //如果玩家状态为跳,并且速度大于100if (this.playerJS.speed > 100) {this.playerJS.speed = 50; //玩家速度变慢}}} else { //否则,就是玩家为爬墙状态this.playerJS.shinState = 0; //攀爬状态设为不动if (this.playerJS.playerDirection == 0) { //如果玩家方向为左this.Player.getComponent(cc.Animation).play("主角左贴动画");} else { //否则,就是玩家方向为右this.Player.getComponent(cc.Animation).play("主角右贴动画");}}break;case cc.macro.KEY.s:if (this.playerJS.playerState == 3) {this.playerJS.shinState = 0; //攀爬状态设为不动if (this.playerJS.playerDirection == 0) { //如果玩家方向为左this.Player.getComponent(cc.Animation).play("主角左贴动画");} else { //否则,就是玩家方向为右this.Player.getComponent(cc.Animation).play("主角右贴动画");}}break;}}
},

项目链接

https://github.com/VRVVR/ccz.git

转载于:https://www.cnblogs.com/raymondking123/p/11361862.html

Cocos Creator经典游戏制作之:信使(The Messenger)相关推荐

  1. cocos creator经典游戏英文版《俄罗斯方块》源码H5+安卓+IOS三端源码

    cocos creator2.2.2经典游戏英文版<俄罗斯方块>源码H5+安卓+IOS三端源码,开发脚本为typeScript方便扩展和阅读,支持cocos creator2.X版本,完整 ...

  2. 使用 cocos creator 3.0 制作抽奖小游戏

    使用 cocos creator 3.0 制作抽奖小游戏 描述 一个抽奖小游戏demo, 点击 抽奖按钮 进行抽奖, 抽完奖后该结果置灰.下一次抽奖就会跳过已经抽过的奖项. 注意: 每次点击 抽奖按钮 ...

  3. cocos creator休闲游戏甜品幻想H5+安卓+IOS三端源码开发脚本为javaScript

    cocos creator休闲游戏甜品幻想H5+安卓+IOS三端源码,开发脚本为javaScript方便扩展和阅读,支持cocos creator2.X版本,完整的源码可拿来运营学习研究二次开发. 1 ...

  4. 最齐全的Cocos2D Cocos creator Cocos2Dx游戏源代码素材,速来收藏

    Cocos2D Cocos creator Cocos2Dx游戏源代码类资源应该算是素材类网站中必不可少的资源类型了吧~今天给大家推荐超好用,免费质量高的素材噢,让你坐拥海量资源同时又不撞款! 本人曾 ...

  5. 经典游戏制作教程[小糊涂的灵感]

    经典游戏制作教程 peng 1.游戏制作的主要流程 -------------------------------------------------------------------------- ...

  6. cocos creator小游戏加载跨域头像

    cocos creator小游戏加载跨域头像 // 玩家头像 和 名字 (防止跨域问题) cc.assetManager.downloader.downloadDomImage(avatarUrl , ...

  7. Cocos creator小游戏实现套牛小游戏资源及代码

    Cocos creator实现套牛小游戏资源及代码 一 安装CocosDashBoard 二 新建2D项目RunCow 1.管理项目目录 2.搭建界面 三 上线微信小游戏 1.上线微信小游戏 2.Co ...

  8. Cocos Creator小游戏-2048(PC、安卓、H5)益智类 项目展示+完整项目源码

    游戏录像 Cocos Creator小游戏-2048 游戏玩法 在棋盘上,每次会增加一个小动物,你可以选择四个方向滑动,然后小动物会按方向移动,遇到相同的小动物就会合并,看谁合并的最多. 功能 1.初 ...

  9. cocos creator V1.9 制作像素鸟游戏(1)-场景设计

    上次立的flag来实现了.先进行场景的设计,在制作的时候,就发现自己被打脸了.场景设计其实只要三个就可以了,最后一个结束其实在主场景上设置相关的的信息,等到游戏结束的时候再显示出来便可以了.于是,场景 ...

最新文章

  1. python 定时任务
  2. 公元2019年,你对AI的信任有几分?
  3. 极客编程日历桌面版for mac开发笔记[swift]
  4. Unity学习笔记3 简易2D横版RPG游戏制作(三)
  5. mysql稠化报表_使用Partitioned Outer Join实现稠化报表
  6. 【C#】读取Excel中嵌套的Json对象,Json带斜杠的问题(其三)
  7. Struts2——解耦方式
  8. 阿里云成立技术脱贫联盟,要用技术助力脱贫
  9. CocoStudio练习笔记3 - 动画编辑器
  10. 数据治理--浅谈数据标准、元数据、主数据、数据模型
  11. IC卡读写器的应用有哪些?
  12. Word如何删除尾注的横线(Office 2003)
  13. 网页保存视频最有效的几种方法
  14. Torah RVP Claiming Tutorial
  15. 人工智能ai思维_人工智能系统如何学习创造性思维
  16. Qt 事件过滤器(秒懂)
  17. 对不起 我来晚了 —— Android群英传 出版祭
  18. 人机料法环,最全质量管理方法都在这儿!
  19. 用Python给你准备了一份新年礼物~制作春节专属手机壁纸跟专属头像啦
  20. 【C语言】大写字母A转小写字母a

热门文章

  1. rocketmq docker
  2. 阿里大咖精心烹饪整理85道Java微服务面试题(附答案)
  3. pdo sqlite_ sqlite2 pdo_mysql_PHP数据库连接篇,PDO连接sqlite数据库,Sqlite安装使用说明!(PHP+Sqlite2和PHP+Sqlite3)...
  4. bzoj 4009: [HNOI2015]接水果 整体二分+k-d tree
  5. FDisk支持的文件系统类型
  6. 学习心得:Apollo无人驾驶汽车入门课程——第一课:无人驾驶概览
  7. Win10 软件出现菱形问号乱码
  8. 国际开源社区OW2成立快应用兴趣小组,助推快应用生态发展
  9. 「解析」牛客网-华为机考企业真题 81-108
  10. GoogleEarth二次开发平台指南(3) ---如何获取点坐标、绘制线路和区域、沿指定线路三维漫游