我下了一个游戏,但是吃鸡游戏页面翻译中的某些字幕没有完全呈现,就像下面这张图片一样,我觉得

90分B站会员注册答案_百度文库
两大类热门资源免费畅读
续费一年阅读会员,立省24元!
90分B站会员注册答案
&&追番称号
阅读已结束,下载本文需要
想免费下载本文?
定制HR最喜欢的简历
下载文档到电脑,方便使用
还剩2页未读,继续阅读
定制HR最喜欢的简历
你可能喜欢您的位置:
&›&&›&
从玩游戏角度看待游戏设计问题系列3下篇
游戏邦|4845
当乐玩家交流总群5:
&&&&&& 从玩游戏角度看待游戏设计问题系列3上篇:&&&&&& 无加载过程条/无意义的加载过程条  有名游戏记者抱怨道:  你进入某个未知地区,游戏暂停并显示“加载中”。没有加载条,甚至没有任何动画告诉你游戏正在进行某些操作。尽管我很喜欢《半条命》系列作品,但它们自始自终都存在这 个问题。这种问题的另一个变种是显示无意义的加载条。游戏进入加载页面并呈现加载条,加载条在很短时间内便已填充满。你可能会跟我一样,想到:“真棒,游戏的加载时间 很短!”随后,加载条又从起点开始填充,如此不断重复。  IE浏览器便是无意义加载条的绝妙例证。浏览页面上的小圈圈不断旋转,并没有告诉用户任何信息(而适用于Android手机的免费浏览器xScope却可呈现已加载页面数量的过程条, 这才是真正有价值的)。  这两种做法都不当,但是无加载条更甚,因为你根本不知道是否已经卡机。应当添加加载条,且该加载条只在加载过程完成时填满。加载条的设置即便不完美也没关系,如果你需 要加载2个文件,一个10KB,另一个10MB,而你设置的是加载完前一个文件时加载条会走完一半,另一半加载条显示第二个文件的加载过程,这都是可以接受的。只要我们能看到加 载过程正在进行中就可以了。  难以辨识的字幕  有人表示:“我无法忍受那些字幕无法阅读的游戏。我曾经见过某些游戏的字幕字体偏小或者颜色与游戏背景相近。有时,在屏幕底部设置字幕显示区就可以解决这种问题。”  有些游戏在字幕或者界面设计上存在欠缺,比如字幕无法识别和阅读或者在玩家使用绿色夜视镜时绿色十字准星会消失。  字幕应当与背景间有足够的对比度,在任何时刻都可以轻松阅读。例如电影就采用白色字幕,同时屏幕底部区域的颜色比画面中心区域更暗。  我曾经提过使用多种颜色的字幕来区分不同说话者的建议,我们需要这种方法,因为游戏与电视电影毕竟不同,在许多游戏中我们看不到角色嘴唇在动。为了确保在使用这种方法 时字幕不会与背景冲突,我们可以在每个字的周围加上黑色边框,并使用黄色或品红等较为吸引眼球的颜色。《猴岛》系列游戏是这方面的优秀典型。  从易用性方面来说,我们应当全力避免字幕字体过小的问题。除非字幕被嵌入构图中(游戏邦注:这样做不利于游戏的本土化处理),否则应当足够清晰地显示,让玩家可以轻松 阅读。  糟糕的随机生成挑战  许多早期的电子游戏采用随机生成挑战(和相关的游戏世界,如果有的话)的方法。现在,要设计、编写和构建一个精细的关卡,成本可能是上百万美元。虽然我们不再像过去那 样习惯于考虑随机生成挑战,但休闲游戏领域仍然大量采用这种方法。  随机生成挑战提供无尽的重玩价值,但它们必须受一些实验的限定,才能保证生成的挑战是良好的。至于“糟糕”,我指的是,游戏随机生成的挑战不能玩、太简单或太无聊。  《Yahoo Word Racer》是一款类似拼写游戏的多人游戏,玩家在游戏中要做的就是将随机生成的字母组合拼成单词。Mary Ellen Foley指出,有时候游戏会给出完全没有元音的字 母组合。玩家必须等到计时器走完两分钟才能开始下一回合。这太可笑了。这款游戏附带一个字典,会检查玩家输入的单词是否存在;当然它可以在游戏放出随机字母组合以前, 检查这些字母是否能拼成单词……或至少检查一下有没有元音。  她建议添加一个“我完成了”按钮,允许玩家跳过本回合,而不必等到计时器走完。对于任何多人、同步回合的游戏来说,这真是个好主意,正好解决了《Word Racer》的问题。 但他们也应该修改一下游戏的生成算法。  好东西都要钱  Ian Schreiber写道:“最近,一些免费游戏好像把所有好东西都藏到钱眼里去了。现在,显然我想要的一些好东西都得付钱了,但我还是希望留下一些好东西用来刺激玩家的购买 欲。如果你只是把游戏的平庸部分拿给玩家看,就要他们相信如果付钱,这款游戏就会更好玩,他们是不会相信的(更可能的结果是,玩家觉得这游戏也就是这样,你卖的也不会 是好东西)。”  “就像一个找工作的游戏设计师,在面试时将作品集中最精华的部分删掉了,居然还想不明白为什么他没有一次面试成功。我觉得这尤其是游戏设计中的一宗大罪,因为它不仅摧 毁了游戏,而且破坏了公司的整个商业模式.”  我打算在“No Twinkie Database”网页中另起一个章节讨论这个问题。我在Twinkie Denial Conditions中提到的大部分问题都与伤害玩家的体验有关,而这个问题伤害的却是游 戏公司。设计缺陷毕竟是设计缺陷。Ian说他不想指名道姓,但已经很不幸地看到有3款iOS游戏中枪了。  冗长老套的动画  这些与不间断过场动画是类似的,但不完全一样。Tyler Moor写道,有些游戏“强迫你看相同的动画或老套的剧本,平庸的情节带着意料之中的结局、封闭的玩法或交互活动,直 到动画结束。我指的不是结束后给玩家各种奖励的动画(如在《塞尔达传说》中,打开一只宝箱),而是那些结果确定的动画。”他举的例子是,在《荒野大镖客》中,玩家被迫 反复地观看剥皮动画来收集资源;在《天际》中,玩家要出售物品时被迫听店主说相同的问候语。  角色变傻  这一条太明显了,我不相信几年以前我会没有提过。有个名叫Jan的玩家写道,在《Max Payne 3》中,过场动画(非常多)中的Max与玩家操作时候的Max很不像。在战胜无数全副 武装的人以后,玩家面临关键的时刻,却不能操作角色了。他看到的不是他期待中的战斗,而是一段显示了他完不成某事的动画,而这件“某事”是他被玩家操作时完全能应付的 。  为了插入叙述剧情,有些交互故事往往会夺走角色的控制权,让玩家郁闷到底是谁在玩这个角色,是玩家还是游戏本身?在这些时候插入变化的剧情和意外的事件当然没错—-但是 ,让角色的表现低于玩家自己的水平或做一些显然愚蠢的事,就是不合理的,而且非常让人失望。值得一提的是,Valve的游戏不会这样。  过场动画和剧情事件自然有该出现的时候,在剧情丰富的游戏中,角色的个性往往比较强,当然有理由让角色有自己的心理活动。但角色脱离玩家的控制后,无论做什么事都最好 与受控制时的表现接近。游戏不是电影,当你给玩家一个角色操控时,参与演出的是玩家,而不是设计师。  亮度或声音激变  当电视广告太大声,与内容不搭时,我们总是很气愤(只有在美国这种行为才算违法)。游戏也可能出现这种情况,而且不只是声音。  Colin Williamson写道:“有问题的游戏是《刺客信条3》,在这款非常黑暗的游戏中,所有游戏过渡或过场动画都是切换成白屏才开始的。如果你是在光线暗的房间或用放映机看 ,这无异于谋杀你的视网膜。”  这就是为什么几前电影业就发明了淡进和淡出的切换方式—-在昏暗的影剧院里,突然变成白屏简直就是虐待观众。在音频制作中,有一种技术叫作动态范围压缩(与数据压缩 无关)。使用这种技术后,设备会动态地将低音的放大和高音的减小控制在适当的范围内,这样听众就不必一直调整音量。虽然听众免不了手动调整扬声器,但确实避免耳膜受到 剧烈的冲击。  唠叨又轻率的NPC  Tess Snider不啰嗦,她说的都是必须说的:  当你在街道上行走时,有个完全陌生的人突然截住你开始大侃特侃他为什么来这里,他的死对头是谁或他的生意怎么样。如果真的遇上这种事,你会不会觉得这个人脑子有病?在 《天际》中,几乎所有NPC都是这样。太怪异了,太烦人了,所以有人做了补丁堵NPC的嘴。  《天际》不是唯一存在这个问题的游戏。放眼RPG领域,所有可信的NPC都坚持告诉我们所有个人信息,即使那些信息我们并不需要。正常人是不会跟一个完全陌生的人讲这些的。 难怪土匪要打劫他们。  Tess认为这是游戏编剧的错,他们懒得想还有什么类似“你好”的表达作为NPC的问候语,却想更多地表现他们的自我。我认为这可能是受了电视警匪片的影响,这种片要在有限的 时间内提供大量信息,结果就是废话连篇:  警察:“昨晚10点你有没有听到什么不寻常的声音?”  目击者:“没……我在房子后面睡觉。生了第三个孩子后,我和我丈夫就分房睡了。我们之间的关系真的变了。”  无论出于什么原因,不要这么做。读读你的对白,看看听起来像不像真实的对话。爱唠叨的人确实有,但毕竟是少数。    prince of persia(from designernotebook)  看不见的墙  许多人抱怨这个问题,我就不一一提名了。看不见的墙是指3D空间中的一道屏障,用来防止玩家进入某个区域,然而,可见的环境和游戏的其他所有机制都告诉玩家他应该能够进 入。(我已经谈过相关的问题了,即玩家必须站在3D空间中的某个点上或以它作为起跳点。)  这种例子非常非常多,其中之一是《S.T.A.L.K.E.R.: 切尔诺贝利的阴影》中的隔离区,那里有及腰高的倒刺铁丝围栏。在RPG中,玩家可以用钥匙打开木门,却不可以损坏它,从 概念上讲,看不见的墙与木门类似,但执行效果不一样。为什么玩家不能进入某些他原本能够进入的地方?游戏没有给出看上去可信的理由。  我们从常识的角度来说吧。除非角色是坐轮椅,否则低的围栏就不算障碍。如果角色是突击队员或超级英雄,六英尺高的围栏也不算难题。一块玻璃自然也不算什么。建造一个看 起来吸引人的区域,却拿看不见的墙隔绝它, 是不合理的。如果你让某个区域看起来是可探索的,那么它就必须可探索。记住,应该让游戏世界之内的区域比之外的更有趣。  有害的升级  玩家达成游戏设定的目标后会得到价值各异的奖励。但有些奖励发挥的却是负面效果。在RPG中,你有时候会捡到被诅咒的物品,这种物品产生的害处多于好处,不过,你通常可以 抑制、修复或抛弃它。另一方面,你用游戏奖励的金钱在游戏商店里买到的东西—-例如,装备强化,真的不应该对你造成伤害。一位名叫Cyrad的玩家提到热门动作RPG《The World Ends With You》:装备是玩家从商店购买的。除了增加属性点,当你与店员建立关系时,还会释放或激活装备的各件物品的被动效果。这些效果通常是“你的攻击将随机减 少敌人的力量”或当你受重创时产生提高防御。  我在游戏中一直没找到属性合适的鞋子,后来终于让我找到一双绝对满意的。我花了一大笔钱给各个队员买了一双。这种鞋子的能力就是获得一个辅助技能,但代价是每一次敌人 的进攻都会让我失去重心。  一边治疗一边承受反复的伤害,这是在游戏中最常见的死法。此时,也是大多数敌人进攻得最猛的时候。基本上可以说,穿上这种鞋子就等于自杀。而且,鞋子的能力无法改变或 移除。鞋子还不能出售。我买的另一双也有这种能力。  玩家买强化物品,你却惩罚他,Square Enix? 真是糟糕的游戏设计师!  过度使用同一个地点  这一条的例子是一款老游戏,但其他游戏也有出现这种情况。Deunen Berkely写道:“你不应该一次又一次地让玩家在同一个洞穴/建筑/区域执行不同的任务。最明显的就是MMO版 《Star Wars Galaxies》,但其他游戏也犯了相同的错误……你不断地跑进山洞里去看不响应你的任务的NPC或物品,或更糟的是,你不得不杀掉所有人才能到达洞穴底部。  你好不容易杀出一条血路,几个活动之后却接到另一个任务让你返回之前那个该死的洞穴,又要再杀掉所有人,寻找那个洞穴/建筑/区域附近的不同东西,然后再次杀回原路。这 样反复15次,确实够无聊的。这就是刷刷任务的任务,你懂吗?”  如果地点的范围够大,场景够丰富,那就无所谓多放几个任务,比如《侠盗猎车手》就是这样的。但如果玩家在一个任务中就已经把场景探索遍了,你就不应该这么做。  转化敌人为己用  对于早期的游戏《Bad Guys With Vanishing Weapons》,这是必然的。你花了大量时间用一个大武器痛打一个坏蛋,最后发现他的武器简陋到只是一根矛。  Sean Hagans写道:“整个国家的人听到他的大名都会闻风而逃,能阻止他统治全世界的野心的只有玩家角色了……不知怎的,你终究是拼上老命战胜他了。  因为你掷地有声的谴责,恶人痛改前非加入你的阵营(天呐,我要好好利用他!太好了!)。让人绝望的是,这货的名字好像叫“神童Bob”,他唯一的进攻方式就是用那把有一点 儿大的木剑砍来砍去。  不公平啊。另一个合理(也非常有趣)的例子是,来自《Ultima》系列的角色出现在《地下城者》的最后一关中,他是最终BOSS,但玩家可以转化他—-当他被转化,你就可以 充分利用他的强大威力了。  总结  最近Lars Doucet告诉我,他的公司Level Up Labs对他们的设计做了一些排查工作。他们根据No Twinkie Database 检查各款游戏的设计,看看他们是不是中了Twinkie Denial Conditions的枪。知道这些专栏文章能发挥实际效用,真是令人高兴。
全文终 当乐小编:小可
星辉游戏品牌战略发布 聚焦游戏产品系列化发展
星辉游戏品牌战略新品发布会 十款新游重磅亮相
想想互娱确认参展2017ChinaJoyBTOB
北京动卡动优文化传媒有限公司确认参展2017 WMGC
虚势待发,智绘未来—2017eSmart引爆智能娱乐硬件领域
自研自发多国平台-太能沃可再临2017ChinaJoyBTOB
参与评论0条
您还能留下2000个脚印
网游排行榜
类型:MOBA&动作&拥有1个小站,订阅6个话题,关注24个小站
本文检索关键词:游戏引擎,游戏开发引擎,cocos引擎html5游戏开发本文主要介绍基于Cocos2d-x 3.2版本开发《大富翁》游戏的项目整体综述,介绍项目中涉及到的精灵、场景、事件等,并介绍了整体的开发流程。项目介绍1、游戏包含单机和联机,包含至少3张地图:海底世界夏日沙滩空中花园2、游戏精灵:主角、财神、土地公、井盖、UFO等3、游戏中的随机事件:掉...&
&本文检索关键词:游戏引擎,游戏开发引擎,cocos引擎html5游戏开发本文主要介绍基于Cocos2d-x 3.2版本开发《大富翁》游戏的项目整体综述,介绍项目中涉及到的精灵、场景、事件等,并介绍了整体的开发流程。&项目介绍1、游戏包含单机和联机,包含至少3张地图:海底世界夏日沙滩空中花园2、游戏精灵:主角、财神、土地公、井盖、UFO等3、游戏中的随机事件:&掉入下水道、被狗咬、捡到钱具体跟游戏地图场景有关;&&海底世界相关的事件&食人鱼、螃蟹夹人、拾到珍珠;&&夏日沙滩相关事件&中暑、海啸、海盗宝藏;&&空中花园相关事件&UFO挟持等;&&项目流程图:&
本文要实现游戏中的暂停、重新开始。将当前界面截图,然后用这张图去构造一个层(以这张图为背景),然后加个按钮,主界面点暂停时,pushScene(),然后转到游戏暂停界面,当在游戏暂停界面点继续游戏popScne()。在Cocos2d-x中推进(pushScene())暂停场景,之前运行的场景将会自动暂停,然后我们可以在暂停场景中操作,当我们不再需要暂停场景时...&
本文要实现游戏中的暂停、重新开始。将当前界面截图,然后用这张图去构造一个层(以这张图为背景),然后加个按钮,主界面点暂停时,pushScene(),然后转到游戏暂停界面,当在游戏暂停界面点继续游戏popScne()。在Cocos2d-x中推进(pushScene())暂停场景,之前运行的场景将会自动暂停,然后我们可以在暂停场景中操作,当我们不再需要暂停场景时,可以popScene()将暂停场景弹出。重新开始游戏直接replaceScene()。
Cocos2d-x版本:2.2.5
工程环境:Windows7+VS2010
打开方式:将工程放在Cocos2d-x安装目录下的project文件夹下用VS打开
本文效果:&
一、游戏暂停界面初步实现
思路:将当前界面截图,然后用这张图去构造一个层(以这张图为背景),然后加个按钮,主界面点暂停时,pushScene(),然后转到游戏暂停界面,当在游戏暂停界面点继续游戏时popScne()。
首先看看自定义的游戏暂停的层:
头文件&Gamepause.h
#ifndef&__Gamepause__H__&&#define&__Gamepause__H__&&#include&"cocos2d.h"&&USING_NS_CC;&&class&Gamepause&:&public&cocos2d::CCLayer&&{&&&&&&public:&&&&&&&&&&virtual&bool&init();&&&&&&&&&&&&static&cocos2d::CCScene*&scene(CCRenderTexture*&sqr);&&&&&&&&&&CREATE_FUNC(Gamepause);&&&&&&&&&&//继续游戏&&&&&&&&&&void&menuContinueCallback(CCObject*&pSender);&&&&&&&&&&&&private:&&&&};&&&&#endif&//&__Gamepause_H__
然后是实现文件
#include&"Gamepause.h"&&//传入一个CCrenderTexture&&&//相当于一个正在运行的游戏的截图作为这个暂停对话框的背景&&&//这样就看起来像是对话框在游戏界面之上,一般游戏当中都是这样子写的。&&CCScene*&Gamepause::scene(CCRenderTexture*&sqr)&&{&&&&&&&&CCScene&*scene&=&CCScene::create();&&&&&&Gamepause&*layer&=&Gamepause::create();&&&&&&&scene-&addChild(layer,1);&&&&&&&&//增加部分:使用Game界面中截图的sqr纹理图片创建Sprite&&&&&&//并将Sprite添加到GamePause场景层中&&&&&&//得到窗口的大小&&&&&&CCSize&visibleSize&=&CCDirector::sharedDirector()-&getVisibleSize();&&&&&&CCSprite&*back_spr&=&CCSprite::createWithTexture(sqr-&getSprite()-&getTexture());&&&&&&&&back_spr-&setPosition(ccp(visibleSize.width/2,visibleSize.height/2));&//放置位置,这个相对于中心位置。&&&&&&back_spr-&setFlipY(true);&&&&&&&&&&&&//翻转,因为UI坐标和OpenGL坐标不同&&&&&&back_spr-&setColor(cocos2d::ccGRAY);&//图片颜色变灰色&&&&&&scene-&addChild(back_spr);&&&&&&return&&&}&&&&bool&Gamepause::init()&&{&&&&&&&&if&(&!CCLayer::init()&)&&&&&&{&&&&&&&&&&return&&&&&&&}&&&&&&//得到窗口的大小&&&&&&CCSize&visibleSize&=&CCDirector::sharedDirector()-&getVisibleSize();&&&&&&//原点坐标&&&&&&CCPoint&origin&=&CCDirector::sharedDirector()-&getVisibleOrigin();&&&&&&&&//继续游戏按钮&&&&&&CCMenuItemImage&*pContinueItem&=&CCMenuItemImage::create(&&&&&&&&&&"pause_continue.png",&&&&&&&&&&"pause_continue.png",&&&&&&&&&&this,&&&&&&&&&&menu_selector(Gamepause::menuContinueCallback));&&&&&&&&pContinueItem-&setPosition(ccp(&visibleSize.width/2&,visibleSize.height/2+30));&&&&&&&&&&CCMenu*&pMenu&=&CCMenu::create(pContinueItem,NULL);&&&&&&pMenu-&setPosition(CCPointZero);&&&&&&this-&addChild(pMenu,&2);&&&&&&&&return&&&}&&void&Gamepause::menuContinueCallback(CCObject*&pSender)&&{&&&&&&CCDirector::sharedDirector()-&popScene();&&&&}
在游戏主界面init函数加个:
CCMenuItemImage&*pCloseItem&=&CCMenuItemImage::create(&&&&&&"CloseNormal.png",&&&&&&"CloseSelected.png",&&&&&&this,&&&&&&menu_selector(HelloWorld::menuPauseCallback));&&&&pCloseItem-&setPosition(ccp(visibleSize.width&-&pCloseItem-&getContentSize().width/2&,&&&&&&visibleSize.height&-&pCloseItem-&getContentSize().height/2));&&&&//&create&menu,&it's&an&autorelease&object&&CCMenu*&pMenu&=&CCMenu::create(pCloseItem,&NULL);&&pMenu-&setPosition(CCPointZero);&&this-&addChild(pMenu,&1);
然后是回调用的函数&暂停界面((记得加上面的头文件就是了))
void&HelloWorld::menuPauseCallback(CCObject*&pSender)&&{&&&&&&//得到窗口的大小&&&&&&CCSize&visibleSize&=&CCDirector::sharedDirector()-&getVisibleSize();&&&&&&CCRenderTexture&*renderTexture&=&CCRenderTexture::create(visibleSize.width,visibleSize.height);&&&&&&&&//遍历当前类的所有子节点信息,画入renderTexture中。&&&&&&//这里类似截图。&&&&&&renderTexture-&begin();&&&&&&&this-&getParent()-&visit();&&&&&&renderTexture-&end();&&&&&&&&//将游戏界面暂停,压入场景堆栈。并切换到GamePause界面&&&&&&CCDirector::sharedDirector()-&pushScene(Gamepause::scene(renderTexture));&&}
这里来看看效果:&
效果就是这样了,基本实现了游戏暂停的功能了。上面的代码可以直接拿去用,自己把图片改改就行了
二、游戏暂停界面美化实现
单单只有上面的肯定是不行的,太难看了,所以给图片的按钮加个背景图片,然后再加三个按钮。
这是按钮背景图片&
这是三个按钮的图片
要用的直接拿去用,全是我原创的。
直接看下代码,就是在上面的基础上来增加函数的。
Gamepause.h
#ifndef&__Gamepause__H__&&#define&__Gamepause__H__&&#include&"cocos2d.h"&&USING_NS_CC;&&class&Gamepause&:&public&cocos2d::CCLayer&&{&&&&&&public:&&&&&&&&&&virtual&bool&init();&&&&&&&&&&&&static&cocos2d::CCScene*&scene(CCRenderTexture*&sqr);&&&&&&&&&&CREATE_FUNC(Gamepause);&&&&&&&&&&//继续游戏&&&&&&&&&&void&menuContinueCallback(CCObject*&pSender);&&&&&&&&&&//重新开始游戏&&&&&&&&&&void&menuRestart(CCObject*&pSender);&&&&&&&&&&//回主界面&&&&&&&&&&void&menuLogin(CCObject*&pSender);&&&&&&private:&&&&};&&&&#endif&//&__Gamepause_H__
Gamepause.cpp
#include&"Gamepause.h"&&#include&"HelloWorldScene.h"//重新开始游戏的头文件&&//传入一个CCrenderTexture&&&//相当于一个正在运行的游戏的截图作为这个暂停对话框的背景&&&//这样就看起来像是对话框在游戏界面之上,一般游戏当中都是这样子写的。&&CCScene*&Gamepause::scene(CCRenderTexture*&sqr)&&{&&&&&&&&CCScene&*scene&=&CCScene::create();&&&&&&Gamepause&*layer&=&Gamepause::create();&&&&&&&&&&scene-&addChild(layer,1);//把游戏层放上面,我们还要在这上面放按钮&&&&&&&&&&//增加部分:使用Game界面中截图的sqr纹理图片创建Sprite&&&&&&//并将Sprite添加到GamePause场景层中&&&&&&//得到窗口的大小&&&&&&CCSize&visibleSize&=&CCDirector::sharedDirector()-&getVisibleSize();&&&&&&CCSprite&*back_spr&=&CCSprite::createWithTexture(sqr-&getSprite()-&getTexture());&&&&&&&&back_spr-&setPosition(ccp(visibleSize.width/2,visibleSize.height/2));&//放置位置,这个相对于中心位置。&&&&&&back_spr-&setFlipY(true);&&&&&&&&&&&&//翻转,因为UI坐标和OpenGL坐标不同&&&&&&back_spr-&setColor(cocos2d::ccGRAY);&//图片颜色变灰色&&&&&&scene-&addChild(back_spr);&&&&&&&&&&//添加游戏暂停背景小图,用来放按钮&&&&&&CCSprite&*back_small_spr&=&CCSprite::create("back_pause.png");&&&&&&back_small_spr-&setPosition(ccp(visibleSize.width/2,visibleSize.height/2));&//放置位置,这个相对于中心位置。&&&&&&scene-&addChild(back_small_spr);&&&&&&&&&&return&&&}&&&&bool&Gamepause::init()&&{&&&&&&&&if&(&!CCLayer::init()&)&&&&&&{&&&&&&&&&&return&&&&&&&}&&&&&&//得到窗口的大小&&&&&&CCSize&visibleSize&=&CCDirector::sharedDirector()-&getVisibleSize();&&&&&&//原点坐标&&&&&&CCPoint&origin&=&CCDirector::sharedDirector()-&getVisibleOrigin();&&&&&&&&//继续游戏按钮&&&&&&CCMenuItemImage&*pContinueItem&=&CCMenuItemImage::create(&&&&&&&&&&"pause_continue.png",&&&&&&&&&&"pause_continue.png",&&&&&&&&&&this,&&&&&&&&&&menu_selector(Gamepause::menuContinueCallback));&&&&&&&&pContinueItem-&setPosition(ccp(&visibleSize.width/2&,visibleSize.height/2+30));&&&&&&&&//重新开始游戏按钮&&&&&&CCMenuItemImage&*pRestartItem&=&CCMenuItemImage::create(&&&&&&&&&&"pause_restart.png",&&&&&&&&&&"pause_restart.png",&&&&&&&&&&this,&&&&&&&&&&menu_selector(Gamepause::menuRestart));&&&&&&&&pRestartItem-&setPosition(ccp(&visibleSize.width/2&,visibleSize.height/2-20));&&&&&&&&//回主界面&&&&&&CCMenuItemImage&*pLoginItem&=&CCMenuItemImage::create(&&&&&&&&&&"pause_login.png",&&&&&&&&&&"pause_login.png",&&&&&&&&&&this,&&&&&&&&&&menu_selector(Gamepause::menuLogin));&&&&&&&&pLoginItem-&setPosition(ccp(&visibleSize.width/2&,visibleSize.height/2-70));&&&&&&&&&&//&create&menu,&it's&an&autorelease&object&&&&&&CCMenu*&pMenu&=&CCMenu::create(pContinueItem,pRestartItem,pLoginItem,NULL);&&&&&&pMenu-&setPosition(CCPointZero);&&&&&&this-&addChild(pMenu,&2);&&&&&&&&&&return&&&}&&void&Gamepause::menuContinueCallback(CCObject*&pSender)&&{&&&&&&CCDirector::sharedDirector()-&popScene();&&&&}&&//重新开始游戏&&void&&Gamepause::menuRestart(CCObject*&pSender)&&{&&&&&&CCDirector::sharedDirector()-&replaceScene(HelloWorld::scene());&&}&&//回主界面&&void&&Gamepause::menuLogin(CCObject*&pSender)&&{&&
游戏开发引擎&Cocos2d-x3.2:退出对话框
本文检索关键词:游戏引擎,游戏开发引擎,cocos引擎html5游戏开发
上一节中介绍了如何制作菜单场景,本节主要讲如何制作游戏中的退出对话框。
首先看看在MenuScene.cpp如是如何调用对话框的:
游戏开发引擎&Cocos2d-x&3.2:退出对话框
本文检索关键词:游戏引擎,游戏开发引擎,cocos引擎html5游戏开发
中介绍了如何制作菜单场景,本节主要讲如何制作游戏中的退出对话框。
首先看看在MenuScene.cpp如是如何调用对话框的:
void&MenuScene::popupLayer(){&&
&&&&//&定义一个弹出层,传入一张背景图&&
&&&&PopupLayer*&popDialog&=&PopupLayer::create(DIALOG_BG);&&
&&&&//&ContentSize&是可选的设置,可以不设置,如果设置把它当作&9&图缩放&&
&&&&popDialog-&setContentSize(CCSizeMake(Quit_Dialog_Size_Width,&Quit_Dialog_Size_Height));&&&
&&&&popDialog-&setTitle(DIALOG_TITLE);&&
&&&&popDialog-&setContentText(DIALOG_CONTENT,&20,&60,&250);&&
&&&&//&设置回调函数,回调传回一个&CCNode&以获取&tag&判断点击的按钮&&
&&&&popDialog-&setCallbackFunc(this,&callfuncN_selector(MenuScene::quitButtonCallback));&&
&&&&//&添加按钮,设置图片,文字,tag&信息&&
&&&&popDialog-&addButton(BUTTON_BG1,&BUTTON_BG3,&OK,&Btn_Quit_OK_TAG);&&
&&&&popDialog-&addButton(BUTTON_BG2,&BUTTON_BG3,&CANCEL,&Btn_Quit_Cancel_TAG);&&
&&&&this-&addChild(popDialog);//&添加到当前层&&
PopupLayer.h&和&PopupLayer.cpp是弹出对话框的代码:
首先看PopupLayer.h
const&int&Pop_FontSize&=&20;//定义字体大小&&
class&PopupLayer&:public&Layer&&
&&&&static&PopupLayer&*&create(const&char*&backgroundImage);//根据背景图创建对象&&
&&&&void&setTitle(const&char*&title&,int&fontsize=Pop_FontSize);//设置对话框标题&&
&&&&void&setContentText(const&char*&text&,int&fontsize=Pop_FontSize&,int&padding=50&,int&paddintTop=100);//设置对话框文本内容&&
&&&&void&setCallbackFunc(Object*&target,&SEL_CallFuncN&callfun);//设置按键回调方法&&
&&&&bool&addButton(const&char*&normalImage,&const&char*&selectedImage,&const&char*&title,&int&tag=0);//添加对话框按键,如确认取消&&
&&&&virtual&void&onEnter();//当进入时调用&&
&&&&virtual&void&onExit();//&&
void&buttonCallback(CCObject*&pSender);&&
&&&&int&m_contentP//&文字内容两边的空白区距离&&
int&m_contentPaddingT&&//文字上边空白区距离&&
&CCObject*&m_callbackL&&
SEL_CallFuncN&m_&&
//定义具有retain属性的变量&&
&&&&CC_SYNTHESIZE_RETAIN(Menu*,&m__pMenu,&MenuButton);&&
CC_SYNTHESIZE_RETAIN(Sprite*,&m__sfBackGround,&SpriteBackGround);&&
&&&&&&&&.&&
PopupLayer.cpp部分代码如下:
PopupLayer::PopupLayer():m__pMenu(NULL),&m_contentPadding(0),&m_contentPaddingTop(0),&m_callbackListener(NULL)&&
,&m_callback(NULL),&m__sfBackGround(NULL),&m__s9BackGround(NULL),&m__ltContentText(NULL),&m__ltTitle(NULL)&&
//释放变量&&
PopupLayer::~PopupLayer()&&
&&&&CC_SAFE_RELEASE(m__pMenu);&&
&&&&CC_SAFE_RELEASE(m__sfBackGround);&&
&&&&CC_SAFE_RELEASE(m__ltContentText);&&
&&&&CC_SAFE_RELEASE(m__ltTitle);&&
&&&&CC_SAFE_RELEASE(m__s9BackGround);&&
void&PopupLayer::setCallbackFunc(cocos2d::Object&*target,&SEL_CallFuncN&callfun)&&
//menuItem根据调传入的对象,会进行方法的回调&&
&&&&m_callbackListener&=&&&
&&&&m_callback&=&&&&&&&
bool&PopupLayer::init()&&
&&&&&&&&//&初始化需要的&Menu,随后跟进参数向menu中添加Item选项&&
&&&&&&&&Menu*&menu&=&Menu::create();&&
&&&&&&&&menu-&setPosition(CCPointZero);&&
&&&&&&&&setMenuButton(menu);&&
setTouchMode(Touch::DispatchMode::ONE_BY_ONE);&&
auto&listener&=&EventListenerTouchOneByOne::create();&&
&&&&&&&&listener-&setSwallowTouches(true);&&
&&listener-&onTouchBegan&=&[](Touch&*t,Event&*e){&&
CCLog("PopupLayer&touch");&&
&&&&&&&&&&&return&&&
&&&&_eventDispatcher-&addEventListenerWithSceneGraphPriority(listener,&this);//屏蔽下层事件响应&&
&&&&return&&&
根据参数、标题、tag、图片效果,添加MenuItem选项:&&
bool&PopupLayer::addButton(const&char&*normalImage,&const&char&*selectedImage,&const&char&*title,&int&tag)&&
Size&winSize&=&CCDirector::getInstance()-&getWinSize();&&
&&&&Point&pCenter&=&ccp(winSize.width&/&2,&winSize.height&/&2);&&
&&&&//&创建MenuItem按钮,并设置回调方法&&
&&&&MenuItemImage*&menuImage&=&MenuItemImage::create(normalImage,&selectedImage,&this,&menu_selector(PopupLayer::buttonCallback));&&
&&&&menuImage-&setTag(tag);&&
&&&&menuImage-&setPosition(pCenter);&&
&&&&//&给MenuItem添加文字说明并设置在MenuItem中位置&&
Size&imenu&=&menuImage-&getContentSize();&&
&&&&LabelTTF*&ttf&=&LabelTTF::create(title,&"",&20);&&
&&&&ttf-&setColor(ccc3(0,&0,&0));&&
&&&&ttf-&setPosition(ccp(imenu.width&/&2,&imenu.height&/&2));&&
&&&&menuImage-&addChild(ttf);&&
&&&&getMenuButton()-&addChild(menuImage);&&
&&&&return&
现在来看MenuItem的回调方法buttonCallback
void&PopupLayer::buttonCallback(cocos2d::CCObject&*pSender)&&
&&&&Node*&node&=&dynamic_cast&Node*&(pSender);&&
&&&&CCLog("touch&tag:&%d",&node-&getTag());&&
&&&&if&(m_callback&&&&m_callbackListener){&&
&&&&&&&&(m_callbackListener-&*m_callback)(node);//这会调用setCallbackFunc()方法传入的MenuScene对象的quitButtonCallback()方法&&
&&&&this-&removeFromParent();//把对话框从父节点移除&&&
对话框弹出前调用onEnter方法进行界面初始化工作
void&PopupLayer::onEnter()&&
&&&&&&&..&&
&&&&Size&contentS&&
&&&&//&设置对话框背景,代码省略&&
&&&&//&添加按钮,并设置其位置&&
&&&&this-&addChild(getMenuButton());&&
&&&&float&btnWidth&=&contentSize.width&/&(getMenuButton()-&getChildrenCount()&+&1);&&
Vector&Node*&&vecArray&=&getMenuButton()-&getChildren();&&
&&&&int&j=0;&&
&&&&for(auto&it=vecArray.begin();it!=vecArray.end();it++)&&
&&&&&&&&Node*&node&=&dynamic_cast&Node*&(*it);&&
&&&&&&&&node-&setPosition(Point(winSize.width/2&-&contentSize.width/2+btnWidth*(j+1),winSize.height/2-contentSize.height/3));&&
&&&&&&&&j++;&&
&&&&//&显示对话框标题内容省略&&
&&&&//&添加对话框弹出效果&&
&&&&Action*&popupLayer&=&Sequence::create(ScaleTo::create(0.0,&0.0),&&
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&ScaleTo::create(0.15,&1.05),&&
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&ScaleTo::create(0.08,&0.95),&&
&&&&ScaleTo::create(0.08,&1.0),NULL);&&
&&&this-&runAction(popupLayer);&&
代码写的稍微多了些,为便于测试,我把代码上传一下,下载:
游戏开发引擎:Cocos2d-x 3D地形(Terrain)本文检索关键词:游戏引擎,游戏开发引擎,cocos引擎html5游戏开发在Cocos2d-x 3.6中,我们为3D部分增加了&地形类,用以模拟现实生活中诸如草地、荒漠、丘陵地带等自然景观,能够丰富游戏场景。这篇教程将会向大家简单介绍一下Terrain类所涵盖的功能,以及基础的用法。Terrain(地...&
游戏开发引擎:Cocos2d-x 3D地形(Terrain)本文检索关键词:游戏引擎,游戏开发引擎,cocos引擎html5游戏开发在Cocos2d-x 3.6中,我们为3D部分增加了&地形类,用以模拟现实生活中诸如草地、荒漠、丘陵地带等自然景观,能够丰富游戏场景。这篇教程将会向大家简单介绍一下Terrain类所涵盖的功能,以及基础的用法。&Terrain(地形类)从编程的角度来说,地形就是通过载入一张高度图和若干张细节纹理,从而在场景中绘制若干高低不平的几何体,用以在游戏场景中模拟自然中的沙漠,草原等景象的一种手段。从地形的资源构成角度来说,包含了下面几个元素:&高度图:高度图是Terrain类的核心,高度图从性质上来说是简单的一张图片,但是图片中的每一个像素的颜色值并不被当做颜色,而是直接被视为一个高度的值。Terrain类就通过高度图所给的高度信息,加以适当的缩放,而构建出整个地形的Mesh结构。&细节图:如果说高度确定了整个Terrain的几何形状,那么细节图则确定了Terrain的外观。通过将细节图贴在Terrain上,可以制造非常好的表现效果。由于Terrain在世界坐标系下,尺寸可能会非常的大,如果单纯将细节图平铺在Terrain上,表现会非常模糊,效果很不好,因此Terrain通过制定细节图的平铺尺寸来解决此问题。&Alpha贴图:Alpha贴图用于控制Terrain上的细节图是在Terrain上何处以及如何绘制的。Alpha贴图从本质而言,也是一张图片,但是它将图片中每个像素中的Red,Green,Blue以及Alpha通道对应四张细节图的Terrain某个位置上,每一张细节图颜色比例是多少。通过这种方式,我们就可以在Terrain上同时出现诸如沙丘,石板路,草地等纹理,使得Terrain的外观不再那么单调,同时Alpha贴图的结构简单,可以使用外部的编辑器就能直接修改。&Terrain入门下面我们从两个例子出发来看看,如何在Cocos2d-x中使用Terrain。这里分为两个部分,第一部分介绍如何创建一个简单的地形,第二部分介绍如何在Terrain上放置一个角色,并通过触摸(点击)使角色在Terrain中漫游。&创建地形需要创建地形需要分类两步,第一步是构造出Terrain所需参数的结构体&&Terrain::TerrainData,第二步,通过该TerrainData来创造地形。&&首先,我们需要构建出地形需要的所有细节图。&细节图以Terrain::DetailMap结构体的形式存储,其构造函数有两个参数,第一个是细节图的路径,第二个是细节图的在地形上的平铺尺寸,第二个参数有默认值,是可选的。1234Terrain::DetailMap r("TerrainTest/dirt.dds");Terrain::DetailMap g("TerrainTest/Grass2.dds");Terrain::DetailMap b("TerrainTest/road.dds");Terrain::DetailMap a("TerrainTest/GreenSkin.jpg");&&然后,我们使用细节图构造出Terrain::TerrainData。&Terrain::TerrainData 的构造函数有若干种形式以满足用户不同的构造地形的需求,在这里我们只给出最常用的一种,构造函数的第一个参数为高度图的路径,第二个参数为Alpha贴图的路径,接下来的四个参数为之前所构造的四个DetailMap结构体。12Terrain::TerrainData data("TerrainTest/heightmap16.jpg","TerrainTest/alphamap.png",r,g,b,a);&最后,将构造出来的TerrainData传给Terrain::create即可创建出地形了。1_terrain = Terrain::create(data,Terrain::CrackFixedType::SKIRT);Terrain::create的第二个参数为地形LOD裂缝的缝补方法,LOD简单来讲就是通过将远处的地形块的Mesh加以简化,从而在不影响视觉效果的情况下,提高性能的方法。但是如果临近的两个地形块的LOD不同时,其边缘可能会出现裂缝,为了游戏效果的美观,我们需要对裂缝进行填补。Terrain提供两种方式对裂缝进行填补,分别是裙边以及补边的方法,在这里我们使用裙边法来对裂缝进行填补。&地形的效果如图所示:&创建角色在地形上行走首先我们先创建一个角色的Sprite3D,让其播放动画并将其加入场景里:12345678910_player = Sprite3D::create("Sprite3DTest/girl.c3b");_player-&setCameraMask(2);_player-&setScale(0.08);_player-&setPositionY(_terrain-&getHeight(_player-&getPositionX(),_player-&getPositionZ())+PLAYER_HEIGHT);auto animation = Animation3D::create("Sprite3DTest/girl.c3b","Take 001");if (animation){& & auto animate = Animate3D::create(animation);& & _player-&runAction(RepeatForever::create(animate));}接着使相机跟随角色的位置移动:12_camera-&setPosition3D(_player-&getPosition3D()+camera_offset);_camera-&setRotation3D(Vec3(-45来源网址:http://www.cocoachina.com/bbs/read.php?tid-299268.html关键词:Cocos2d-x 3.63D地形地形类&&
H5游戏最近越来越多,相信很多开发者也越来越重视H5这块的市场。不过往往我们发布了一款H5游戏后,却不知道游戏的具体情况,比如说日访问量,月访问量,活跃用户,独立IP等等的数据。
而cocos这个时候,就需要用到统计平台了。
这里我们介绍DataEye这个统计平台。
这里注册一个账号-登陆。
点击创建游戏,然后一路狂点下一步。...&
H5游戏最近越来越多,相信很多开发者也越来越重视H5这块的市场。不过往往我们发布了一款H5游戏后,却不知道游戏的具体情况,比如说日访问量,月访问量,活跃用户,独立IP等等的数据。
而这个时候,就需要用到统计平台了。
这里我们介绍这个统计平台。
这里注册一个账号&-&登陆。
点击创建游戏,然后一路狂点下一步。
然后点击下载SDK。引用了js文件后初始化...填入appid
var&options&=&{
&&&&appId:&'ACE29DBB0EA',
&&&&appVer:&'v2.0.0',
&&&&interval:&10,
&&&&//&排除指定脚本
&&&&excludes:[],
&&&&//&是否开启病毒传播功能,会修改页面的url(附加hash)
&&&&virus:&true
DCAgent.init(options)&;
然后我们检查下dataEye的服务器是否已经正常接收到了数据:
找到实时日志,然后点击右边的蓝色按钮&-&打开实时日志...
然后运行刚刚我们初始化配置后的页面。正常的话应该能够看到:
剩下的就可以完全交给DataEye处理了,他会自动统计ip、uv等等等等的数据,而我们只需要在后台查看我们需要的数据就行了。
此外DataEye也提供了手动上报pv等的功能,只需要手动调用接口:
DCAgent.onPageView('/custom_page')
简单易用,能够提供大部分运行所需的数据支持。
暂时发现部分统计不准确,比如说设备分析等。
DataEye还提供了上报自定义事件等的功能,可以参考这里。
本文将要解决Cocos2d-x中显示中文时出现乱码的情形,并且实现一个字幕滚动的功能,这个功能是通过遮罩来实现的。Cocos2d-x版本:2.2.5工程环境:windows7+VS2010打开方式:将工程放在Cocos2d-x安装目录下的project文件夹下用VS打开先来看看效果:
游戏引擎在windows环境下使用visualstudio开发Coc...&
本文将要解决2d-x中显示中文时出现乱码的情形,并且实现一个字幕滚动的功能,这个功能是通过遮罩来实现的。&Cocos2d-x版本:2.2.5工程环境:windows7+VS2010打开方式:将工程放在Cocos2d-x安装目录下的project文件夹下用VS打开&先来看看效果:
在windows环境下使用visual&studio开发Cocos2d-x,由于visual&studio&默认编码为GBK格式,而cocos2d-x引擎默认编码为UTF-8,如果有用到中文,在游戏运行时有可能会出现乱码的情况,这个问题一般有三种解决方案,如下:(1)将源码文件保存为utf-8格式(不建议,治标不治本)(2)自己编写编码转换代码,在用到中文的地方手动转换(3)将显示文本单独保存为文本文件(该文件编码为utf-8),由系统统一模块管理文本读取显示,建议使用这种方式,便于后期系统维护,并实现国际化。&第一种方式很简单就不不介绍了,下面将对第2种进行介绍。第3种还没写好。&一、自己编写编码转换代码,在用到中文的地方手动转换。Cocos2d-x的开发包内置了用于编码转换的iconv库,头文件"iconv.h"。iconv命令可以将一种已知的字符集文件转换成另一种已知的字符集文件。它的作用是在多种国际编码格式之间进行文本内码的转换。&1、&直接把代码写进要用到的地方如果是只能到一次的话,推荐可以这么做。(1)首先,新建一个工程,然后在HelloWorldScene.cpp中添加头文件uinclude"iconv/iconv.h"/,(2)然后在HelloWorldScene.cpp添加全局函数(记得要把它们放在所有函数的最上头,要不就是最上头再定义函数一下)
bool&IConvConvert(const&char&Efrom_charset,&const&char&Yto_charset,&const&char&Vinbuf,&int&inlen,&char&Woutbuf,&int&outlen)&&
&&&&iconv_t&cd&=&iconv_open(to_charset,&from_charset);&&
&&&&if&(cd&==&0)&return&&&
&&&&const&char&GZpin&=&&&&
&&&&char&CCpout&=&&&&
&&&&memset(outbuf,0,outlen);&&
&&&&size_t&ret&=&iconv(cd,pin,(size_t&Z)&inlen,pout,(size_t&A)&outlen);&&
&&&&iconv_close(cd);&&
&&&&return&ret&==&(size_t)(-1)&?&false&:&&&
std::string&IConvConvert_GBKToUTF8(const&std::string&&str)&&
&&&&const&charQ&textIn&=&str.c_str();&&
&&&&char&textOut[256];&&
&&&&bool&ret&=&IConvConvert("gb2312",&"utf-8",&textIn,&strlen(textIn),textOut,&256);&&
&&&&return&ret&?&std::string(textOut)&:&std::string();&&
运行之后报错:error&LNK2019:无法解析的外部符号&_libiconv_closeerror&LNK2019:无法解析的外部符号&_libiconverror&LNK2019:无法解析的外部符号&_libiconv_openfatal&error&LNK1120:&3个无法解析的外部命令解决方法:因为你没有加libiconv.lib文件&在工程属性&-&配置属性&-&链接器-&输入-&附加依赖项添加libiconv.lib如下:(3)用法:在用到的地方,我这里是在init()里添加
std::string&str&=IConvConvert_GBKToUTF8("我是林炳文Evankaka~~\n欢迎来到我的世界~~~");&&
CCLabelTTFH&pLabel&=&CCLabelTTF::create(str.c_str(),&"Arial",&24);&&
pLabel-&setPosition(ccp(origin.x&+&visibleSize.width/2,&&
&&&&origin.y&+&visibleSize.height&-&pLabel-&getContentSize().height));&&
this-&addChild(pLabel,&1);
4)效果:&2、单独一个文字转换文件&单独保存为&.h头文件,在使用到编码转换的cpp文件include即可。如果要经常用到的话,建议用这种方法。记得在工程属性&-&配置属性&-&链接器-&输入-&附加依赖项添加libiconv.lib
(1)在class文件夹下新建一个名为ChineseString.h的文件,并把它加到工程来。
vifndef&__ChineseString_H__&&&&
ldefine&__ChineseString_H__&&&&
sinclude&"iconv/iconv.h"//重点记得加上去&&
static&char&g_GBKConvUTF8Buf[5000]&=&{0};&&
class&ChineseString&&
&&&&public:&&
&&&&&&&&static&const&charW&GBKToUTF8(const&char&XstrChar)//将字符串转成UFT-8&&
&&&&&&&&&&&
&&&&&&&&&&&&iconv_t&iconvH;&&
&&&&&&&&&&&&iconvH&=&iconv_open("utf-8","gb2312");&&
&&&&&&&&&&&&if&(iconvH&==&0)&&
&&&&&&&&&&&&{&&
&&&&&&&&&&&&&&&&return&NULL;&&
&&&&&&&&&&&&}&&
&&&&&&&&&&&&size_t&strLength&=&strlen(strChar);&&
&&&&&&&&&&&&size_t&outLength&=&strLengthF4;&&
&&&&&&&&&&&&size_t&copyLength&=&outL&&
&&&&&&&&&&&&memset(g_GBKConvUTF8Buf,&0,&5000);&&
&&&&&&&&&&&&charF&outbuf&=&(charA)&malloc(outLength);&&
&&&&&&&&&&&&charB&pBuff&=&&&
&&&&&&&&&&&&memset(outbuf,&0,&outLength);&&
&&&&&&&&&&&&if&(-1&==&iconv(iconvH,&&strChar,&&strLength,&&outbuf,&&outLength))&&
&&&&&&&&&&&&{&&
&&&&&&&&&&&&&&&&iconv_close(iconvH);&&
&&&&&&&&&&&&&&&&return&NULL;&&
&&&&&&&&&&&&}&&
&&&&&&&&&&&&memcpy(g_GBKConvUTF8Buf,pBuff,copyLength);&&
&&&&&&&&&&&&free(pBuff);&&
&&&&&&&&&&&&iconv_close(iconvH);&&
&&&&&&&&&&&&return&g_GBKConvUTF8B&&
&&&&&&&&}&&
&&(2)使用方法:在要用到的地方先添加头文件ChineseString.h(记得加!)然后是
CCLabelTTFX&pLabel=CCLabelTTF::create(ChineseString::GBKToUTF8("&span&style="font-family:&Arial,&Helvetica,&sans-"&我是林炳文Evankaka~~\n欢迎来到我的世界~~~&/span&"),&"Arial",&24);&&
pre&name="code"&class="cpp"&&&&&&&&&pLabel-&setPosition(ccp(origin.x&+&visibleSize.width/2,&&
&&&&origin.y&+&visibleSize.height&-&pLabel-&getContentSize().height));&&
this-&addChild(pLabel,&1);
&(3)效果
二、字幕滚动字幕滚动应该是要在一个范围内可见的,出了这个范围就不可见了,这里实现其实很简单,就是通过CCClippingNode来实现的.CCClipingNode是一个可裁剪节点,简单理解:(1)首先它是一个节点,继承于CCNode,所以它可以像普通节点一样放入CCLayer,CCScene,CCNode中。(2)作为节点,它就可以用作容器,承载其他节点和精灵。我把它叫底板。(3)如果想要对一个节点进行裁剪,那需要给出裁剪的部分,这个裁剪区域,我把它叫模版。所以CCClipingNode裁剪节点在组成上=底板+模版,而在显示上=底板-模版。不知道这样解释会不会好理解一点。这里直接建了一个类,将上面新建的中文转换头文件&用了进来,这是头文件&GameString.h
jifndef&__GameString_SCENE_H__&&
idefine&__GameString_SCENE_H__&&
pinclude&"cocos2d.h"&&
uinclude&"cocos-ext.h"&&
rinclude&"ChineseString.h"&&
ainclude&"HelloWorldScene.h"//这是游戏界面的头文件&&
USING_NS_CC;&&
USING_NS_CC_EXT;&&
class&GameString&:&public&cocos2d::CCLayer&&
&&&&public:&&
&&&&&&&&virtual&bool&init();&&&&
&&&&&&&&static&cocos2d::CCSceneP&scene();&&
&&&&&&&&CREATE_FUNC(GameString);&&
&&&&&&&&//字幕滚动完成后调用&&
&&&&&&&&void&RollEnd();&&
&&&&&&&&//跳过按钮的事件&&
&&&&&&&&void&menuCloseCallback(CCObjectY&pSender);&&
kendif&//&__GameString_SCENE_H__
&这是实现文件&GameString.cpp
minclude&"GameString.h"&&
CCSceneH&GameString::scene()&&
&&&&CCScene&Lscene&=&CCScene::create();&&
&&&&GameString&Elayer&=&GameString::create();&&
&&&&scene-&addChild(layer);&&
&&&&return&&&
bool&GameString::init()&&
&&&&if&(&!CCLayer::init()&)&&
&&&&&&&&return&&&
&&&&CCSize&visibleSize&=&CCDirector::sharedDirector()-&getVisibleSize();&&
&&&&CCPoint&origin&=&CCDirector::sharedDirector()-&getVisibleOrigin();&&
&&&&//加个按钮&&
&&&&CCMenuItemImage&YpCloseItem&=&CCMenuItemImage::create(&&
&&&&&&&&"exct.png",&&
&&&&&&&&"exct.png",&&
&&&&&&&&this,&&
&&&&&&&&menu_selector(GameString::menuCloseCallback));&&
&&&&pCloseItem-&setPosition(ccp(&visibleSize.width&-80&,visibleSize.height-60));&&
&&&&CCMenuX&pMenu&=&CCMenu::create(pCloseItem,&NULL);&&
&&&&pMenu-&setPosition(CCPointZero);&&
&&&&this-&addChild(pMenu,&1);&&
&&//加背景&&
&&&&CCSpriteC&pSprite&=&CCSprite::create("enter.png");&&
&&&&pSprite-&setPosition(ccp(visibleSize.width/2&+&origin.x,&visibleSize.height/2&+&origin.y));&&
&&&&this-&addChild(pSprite,&0);&&
&&&&//创建要显示的文字&&
&&&&CCLabelTTFW&pLabel=CCLabelTTF::create(ChineseString::GBKToUTF8("我是林炳文Evankaka~~\n这是游戏《赵云要格斗》\n欢迎来到我的世界~~~\n我是林炳文Evankaka~~\n这是游戏《赵云要格斗》\n欢迎来到我的世界~~~\n我是林炳文Evankaka~~\n这是游戏《赵云要格斗》"),"Arial",25);&&
&&&&pLabel-&setAnchorPoint(CCPointZero);&&
&&&&ccColor3B&color&=&ccc3(255,255,0);&&
&&&&pLabel-&setColor(color);&&
&&&&pLabel-&setPosition(ccp(50,&-200));//Y轴注意为负,X轴对应下面的point[4]的50,让他们对齐&&
&&&&//绘制裁剪区域&&
&&&&CCDrawNodeF&shap&=&CCDrawNode::create();&&
&&&&CCPoint&point[4]&=&{ccp(50,0),&ccp(400,0),&ccp(400,200),&ccp(50,200)};//可以根据文字适当修改下大小&&
&&&&shap-&drawPolygon(point,4,ccc4f(255,255,255,255),0,&ccc4f(255,255,255,255));//绘制四边形&&
&&&&////创建遮罩&&
&&&&CCClippingNodeW&pClip&=&CCClippingNode::create();&&
&&&&pClip-&setInverted(false);&&
&&&&pClip-&setStencil(shap);//一定要有,要不会报错&&
&&&&pClip-&addChild(pLabel);&&
&&&&this-&addChild(pClip);&&
&&&&//开始让字幕滚动啦&&
&&&&CCMoveByD&moveact=CCMoveBy::create(10.0f,CCPointMake(0,400));//10秒向上移动400&&
&&&&CCCallFuncX&callFunc=CCCallFunc::create(this,callfunc_selector(GameString::RollEnd));//创建回调动作,文字飘动完后&&
&&&&CCActionIntervalD&act=CCSequence::create(moveact,callFunc,NULL);//创建连续动作&&
&&&&pLabel-&runAction(act);&&
&&&&return&&&
void&GameString::RollEnd()&&
&&&&&CCDirector::sharedDirector()-&replaceScene(HelloWorld::scene());//进入游戏主界面&&
void&GameString::menuCloseCallback(CCObjectC&pSender)&&
&&&&RollEnd();//点击跳过直接进入游戏主界面&&
效果:(1)字幕滚动完成后进入游戏主界面(2)点击跳过直接进入游戏主界面&
本章要讲解给怎么在界面上加一个血条,老规矩,还是在《Cocos2d-x地图随精灵无限滚动与边缘检测--之游戏开发《赵云要格斗》(三)》的基础上进行增加功能的。在游戏开发中,血条是一个很重要的东西,这里的血条是通过两个图片来完成,一个是前景图(红色),一个是背景图(灰色),通过改变红色图在长度显示,灰色图不变就可实现血量的变化了。当然,这里为了让界面更加好看些...&
本章要讲解给怎么在界面上加一个血条,老规矩,还是在《2d-x地图随精灵无限滚动与边缘检测--之游戏开发《赵云要格斗》(三)》的基础上进行增加功能的。&在游戏开发中,血条是一个很重要的东西,这里的血条是通过两个图片来完成,一个是前景图(红色),一个是背景图(灰色),通过改变红色图在长度显示,灰色图不变就可实现血量的变化了。当然,这里为了让界面更加好看些,又为血条加了个血框和人物的小头像。&Cocos2d-x版本:2.2.5工程环境:Windows7+VS2010&先来看看效果吧(由于还没有引入怪物,所以我弄成攻击一次,血条少1或10两种来看看效果):一、自定义血条类本着后头血条要给怪物来用,所以设计了一个血条类。原理其实就是两个ccsprite对像,控制前景示的大小就可以改变血量了。
首先是资源,在Resources添加以下图片红血条(前景):灰血条(背景):血条框架:赵云左上角小头像:&头文件ProgressView.h:
qifndef&__PROGRESSVIEW_H__
gdefine&__PROGRESSVIEW_H__
cinclude&"cocos2d.h"
using&namespace&cocos2d;
class&ProgressView&:&public&CCNode
&&&&public:
&&&&&&&&ProgressView();
&&&&public:
&&&&&&&&//设置血条背景
&&&&&&&&void&setBackgroundTexture(const&char&JpName);
&&&&&&&&//设置血条前景
&&&&&&&&void&setForegroundTexture(const&char&QpName);
&&&&&&&&//设置总血量
&&&&&&&&void&setTotalProgress(float&total);
&&&&&&&&//设置当前血量
&&&&&&&&void&setCurrentProgress(float&progress);
&&&&&&&&//得到当前血量
&&&&&&&&float&getCurrentProgress()&
&&&&&&&&//得到总血量
&&&&&&&&float&getTotalProgress()&
&&&&private:
&&&&&&&&//设置前景血条显示的长度
&&&&&&&&void&setForegroundTextureRect(const&CCRect&&rect);
&&&&private:
&&&&&&&&CCSprite&Lm_progressB//背景血条
&&&&&&&&CCSprite&Hm_progressF//前景血条
&&&&&&&&float&m_totalP//总血量
&&&&&&&&float&m_currentP//当前血量
&&&&&&&&float&m_//放大倍数
实现文件ProgressView.cpp:
ginclude&"ProgressView.h"
ProgressView::ProgressView()
&&&&:&m_progressBackground(NULL)
&&&&,&m_progressForeground(NULL)
&&&&,&m_totalProgress(0.0f)
&&&&,&m_currentProgress(0.0f)
&&&&,&m_scale(1.0f)
void&ProgressView::setBackgroundTexture(&const&char&FpName&)
&&&&m_progressBackground&=&CCSprite::create(pName);
&&&&this-&addChild(m_progressBackground);
void&ProgressView::setForegroundTexture(&const&char&QpName&)
&&&&m_progressForeground&=&CCSprite::create(pName);
&&&&m_progressForeground-&setAnchorPoint(ccp(0.0f,&0.5f));//设置锚点
&&&&m_progressForeground-&setPosition(ccp(-m_progressForeground-&getContentSize().width&R&0.5f,&0));
&&&&this-&addChild(m_progressForeground);
void&ProgressView::setTotalProgress(&float&total&)
&&&&if&(m_progressForeground&==&NULL)&{}
&&&&m_scale&=&m_progressForeground-&getContentSize().width&/&
&&&&m_totalProgress&=&
void&ProgressView::setCurrentProgress(&float&progress&)
&&&&if&(m_progressForeground&==&NULL)&{}
&&&&if&(progress&&&0.0f)&{progress&=&0.0f;}
&&&&if&(progress&&&m_totalProgress)&{progress&=&m_totalP}
&&&&m_currentProgress&=&
&&&&float&rectWidth&=&progress&W&m_
&&&&const&CCPoint&from&=&m_progressForeground-&getTextureRect().
&&&&const&CCRect&rect&=&CCRectMake(from.x,&from.y,&rectWidth,&m_progressForeground-&getContentSize().height);
&&&&setForegroundTextureRect(rect);
void&ProgressView::setForegroundTextureRect(&const&CCRect&&rect&)
&&&&m_progressForeground-&setTextureRect(rect);
float&ProgressView::getCurrentProgress()&const
&&&&return&m_currentP
float&ProgressView::getTotalProgress()&const
&&&&return&m_totalP
好了,这个血条类就定义好了,编译下没报错,可以移值了。&二、使用自定义血条类并进行美化首先然要用到的地方,就是HelloWorldScene.h中添加头文件
tinclude&"ProgressView.h"
然后定义成员变量:
&&&&HRockerH&//摇杆,第一篇摇杆文章中定义的
&&&&HeroZ&&&&///精灵,&span&style="font-family:&Arial,&Helvetica,&sans-"&第一篇摇杆文章中定义的&/span&
&&&&ControlButtonU&//按钮控件变量,第二篇自定义按钮定义的
&&&&MapP&&&&&//地图&&,第三篇定义的
&&&&ProgressView&Nm_pProgressV&&//血条
然后就在init()函数中初始化:
//设置英雄的血条&
m_pProgressView&=&new&ProgressView();&&
m_pProgressView-&setPosition(ccp(150,&450));&&
m_pProgressView-&setScale(2.2f);&&
m_pProgressView-&setBackgroundTexture("xue_back.png");&&
m_pProgressView-&setForegroundTexture("xue_fore.png");&&
m_pProgressView-&setTotalProgress(100.0f);&&
m_pProgressView-&setCurrentProgress(100.0f);&
this-&addChild(m_pProgressView,&2);
效果:半血感觉好丑啊,想想再给血条加个框,再加个小头像。&将上面改为:
//设置英雄的血条&
m_pProgressView&=&new&ProgressView();&&
m_pProgressView-&setPosition(ccp(150,&450));&&
m_pProgressView-&setScale(2.2f);&&
m_pProgressView-&setBackgroundTexture("xue_back.png");&&
m_pProgressView-&setForegroundTexture("xue_fore.png");&&
m_pProgressView-&setTotalProgress(100.0f);&&
m_pProgressView-&setCurrentProgress(50.0f);&
//下面两个是为了让血条更好好看
CCSprite&Lxuekuang=CCSprite::create("kuang.png");//添加血条的框架
xuekuang-&setPosition(ccp(m_pProgressView-&getPositionX(),m_pProgressView-&getPositionY()));
CCSprite&Ntouxiang=CCSprite::create("touxiang.png");//添加英雄的左上角的小头像
touxiang-&setPosition(ccp(m_pProgressView-&getPositionX()-120,m_pProgressView-&getPositionY()));
this-&addChild(touxiang,2);
this-&addChild(xuekuang,2);
this-&addChild(m_pProgressView,&2);
下面再来看看效果:事实再次证明,美工是多么重要啊!这样子明显好看多了,这时血条有了。&三、改变英雄血量其实这里改变血量很简单了,m_pProgressView-&setCurrentProgress(改动);&这一句就可以了,那我们要怎么来验证了,我想到了一个方法,攻击一次,血条让它自己少1(初始是100);void&HelloWorld::update(float&delta)函数中改动:
void&HelloWorld::update(float&delta)
&&&&//判断是否按下摇杆及其类型
&&&&CCSize&visibleSize1&=&CCDirector::sharedDirector()-&getVisibleSize();//得到窗口大小
&&&&switch(rocker-&rocketDirection)
&&&&&&&&&&&&case&&1:
&&&&&&&&&&&&&&&&hero-&SetAnimation("run_animation.plist","run_animation.png","run_",8,rocker-&rocketRun);
&&&&&&&&&&&&&&&&//"run_"为run_animation.png集合图片中每张图片的公共名称部分
&&&&&&&&&&&&&&&&if(hero-&getPositionX()&=visibleSize1.width-8)//不让精灵超出右边,8可以改成你喜欢的
&&&&&&&&&&&&&&&&{
&&&&&&&&&&&&&&&&&&&&if(!hero-&JudgePositona(visibleSize1)||mymap-&JudgeMap(hero,visibleSize1))
&&&&&&&&&&&&&&&&&&&&//精灵没到达窗口中间位置或者地图已经移动到边缘了,精灵才可以移动,否则只播放动画
&&&&&&&&&&&&&&&&&&&&&&&&hero-&setPosition(ccp(hero-&getPosition().x+1,hero-&getPosition().y));&//向右走
&&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&&&//下面是移动地图
&&&&&&&&&&&&&&&&&&&&mymap-&MoveMap(hero,visibleSize1);
&&&&&&&&&&&&&&&&}
&&&&&&&&&&&&&&&&
&&&&&&&&&&&&case&&2:
&&&&&&&&&&&&&&&&hero-&SetAnimation("run_animation.plist","run_animation.png","run_",8,rocker-&rocketRun);//"run_"为run_animation.png集合图片中每张图片的公共名称部分
&&&&&&&&&&&&&&&&hero-&setPosition(ccp(hero-&getPosition().x,&hero-&getPosition().y+1));&&&//向上走
&&&&&&&&&&&&&&&&
&&&&&&&&&&&&case&3:
&&&&&&&&&&&&&&&&hero-&SetAnimation("run_animation.plist","run_animation.png","run_",8,rocker-&rocketRun);//"run_"为run_animation.png集合图片中每张图片的公共名称部分
&&&&&&&&&&&&&&&&if(hero-&getPositionX()&=8)//不让精灵超出左边,8可以改成你喜欢的
&&&&&&&&&&&&&&&&&&&&hero-&setPosition(ccp(hero-&getPosition().x-1,hero-&getPosition().y));&&&//向左走
&&&&&&&&&&&&&&&&
&&&&&&&&&&&&case&4:
&&&&&&&&&&&&&&&&hero-&SetAnimation("run_animation.plist","run_animation.png","run_",8,rocker-&rocketRun);//"run_"为run_animation.png集合图片中每张图片的公共名称部分
&&&&&&&&&&&&&&&&hero-&setPosition(ccp(hero-&getPosition().x,hero-&getPosition().y-1));&&&//向下走
&&&&&&&&&&&&&&&&
&&&&&&&&&&&&case&0:
&&&&&&&&&&&&&&&&hero-&StopAnimation();//停止所有动画和运动
&&&&&&&&&&&&&&&&
&&&&//判断是否出动攻击
&&&&if(btn-&isTouch)
&&&&&&&&if(hero-&IsAttack)//英雄没在攻击
&&&&&&&&&&&&
&&&&&&&&hero-&AttackAnimation("attack1_animation.plist","attack1_animation.png","attack_",6,rocker-&rocketRun);
&&&&&&&&m_pProgressView-&setCurrentProgress(m_pProgressView-&getCurrentProgress()-1);&//更改血量
每次减少1:每次减少10:源码下载:&
这篇教程里,我们会简单的介绍一下两种基本的伪阴影的概念,以及在Cocos2d-x中的实现方法。
何谓伪阴影:
在游戏过程中,我们通常会是用阴影来增强视觉效果的真实度,在这里,我们讨论伪阴影的计算方法,所谓的伪阴影,是指根据指定的空间位置的模型生成一个简单的阴影,这个阴影的形状&&或者说轮廓与被生成阴影的模型的...&
这篇教程里,我们会简单的介绍一下两种基本的伪阴影的概念,以及在2d-x中的实现方法。
何谓伪阴影:
在游戏过程中,我们通常会是用阴影来增强视觉效果的真实度,在这里,我们讨论伪阴影的计算方法,所谓的伪阴影,是指根据指定的空间位置的模型生成一个简单的阴影,这个阴影的形状&&或者说轮廓与被生成阴影的模型的真实样子并无映射关系。这种影子虽然看起来简单,但是在某些场合也会非常的有用,比方说在一个光源在比较远和比较高的角度,光线比较充足的场景里。比方说,在艳阳高照的足球场上,球员脚底的阴影就是一团模糊不清的圆环状,伪阴影与模型无关,有实现简单,计算效率高等,所以在一些开阔明亮的场景里通常会使用。
通过距离计算的方式:
我们先说一种非常简单的方式。首先,我们获取到玩家角色的位置,然后将制定的地面的每一像素点的位置与玩家角色位置的距离作比较,当小于一个制定的范围的阈值的时候,就将该点涂黑。
现在我们来描述一下如何具体的实现这个方式,首先我们读入一个地面,并自定义自己的shader,并将这个地面的所有顶点的属性属性,存入这个shader的state中:
auto&plane&=&Sprite3D::create("plane.c3b");
plane-&setRotation3D(Vec3(90,0,0));
auto&shader&=GLProgram::createWithFilenames("simple_shadow.vert","simple_shadow.frag");
auto&state&=&GLProgramState::create(shader);
plane-&setGLProgramState(state);
//pass&mesh's&attribute&to&shader
long&offset&=&0;&
auto&attributeCount&=&plane-&getMesh()-&getMeshVertexAttribCount();
for&(auto&i&=&0;&i&&&attributeC&i++)&{
&&&&&&&&auto&meshattribute&=&plane-&getMesh()-&getMeshVertexAttribute(i);
&&&&&&&&state-&setVertexAttribPointer(s_attributeNames[meshattribute.vertexAttrib],
&&&&&&&&&&&&meshattribute.size,&
&&&&&&&&&&&&meshattribute.type,
&&&&&&&&&&&&GL_FALSE,
&&&&&&&&&&&&plane-&getMesh()-&getVertexSizeInBytes(),
&&&&&&&&&&&&(GLvoidX)offset);
&&&&&&&&offset&+=&meshattribute.attribSizeB
接着我们要将角色的坐标传入这个shader:
plane-&getGLProgramState()-&setUniformVec3("u_target_pos",orc-&getPosition3D());
目前我们无法获得平面在世界坐标系下的位置,我们将地面的模型变换的矩阵传入shader内
state-&setUniformMat4("u_model_matrix",plane-&getNodeToWorldTransform());
这样前期的准备工作就已经做好了,接下来,我们来看一下shader内部是如何处理的,首先我们看一看顶点着色器部分:
attribute&vec4&a_
attribute&vec2&a_texC
uniform&mat4&u_model_
varying&vec2&TextureCoordO
varying&vec4&v_
void&main(void)
&&&&gl_Position&=&&CC_PMatrix&&U&CC_MVMatrix&A&a_
&&&&TextureCoordOut&=&a_texC
&&&&TextureCoordOut.y&=&(1.0&-&TextureCoordOut.y);
v_position&=&u_model_matrix&M&a_
请注意加粗的部分,u_model_matrix,就是我们之前传入的模型变换的矩阵,v_position是我们自己定义的一个易变变量,我们用平面的顶点的局部坐标的位置与u_model_matrix相乘,得出平面的世界坐标,并将其插值,传给片段着色器阶段,使其能够获得平面上每个像素点的世界坐标。
现在我们来看看像素着色器部分:
bifdef&GL_ES
varying&mediump&vec2&TextureCoordO
varying&mediump&vec4&v_
varying&vec2&TextureCoordO
varying&vec4&v_
uniform&vec3&u_target_
kdefine&RANGE&1.5
void&main(void)
float&dist&=&distance(v_position.xz,u_target_pos.xz);
if(&dist&&&RANGE&)
gl_FragColor&=&vec4(0,0,0,1);
gl_FragColor&=&texture2D(CC_Texture0,TextureCoordOut);
像素着色器里的原理很简单,首先我们将从顶点着色器插值而来的平面的世界坐标的位置与角色的世界坐标的位置计算一个距离,然后设置一个阈值RANGE&,若所得的距离小于这个RANGE,则将该片段涂黑,否则保持其纹理的颜色。最后显示的结果如下:
简单改进:
这个效果看起来并不好,因为在现实生活中,影子的边缘通常来说是比较量,比较柔和的,即所谓的半影效果,我们可以在前述的片段着色器中稍加修改,在一定范围内计算一下当前距离与范围的比值,然后与地面的颜色相混合,就可以达到这种效果了,修改后的片段着色器的代码如下:
if(&dist&&&RANGE&)
&&&&float&shadow_factor&=&dist&/⦥
&&&&shadow_factor&=&clamp(shadow_factor,0.5,1);
&&&&gl_FragColor&=&vec4(shadow_factor,shadow_factor,shadow_factor,1.0)
&&&&Ntexture2D(CC_Texture0,TextureCoordOut);
这样改动后的结果就比较理想了:
通过投影的方式绘制阴影
上述所说的算法的效率并不高,因为在片段着色器中,我们要计算距离,其次还有if&else的判断,这样会很大程度上拖慢shader的执行效率,接下来我们介绍另外一种方式,它就没有上述的问题。
这种方式的基本原理是将平面上一点投影到角色上挂着一个(虚拟)的朝下的相机上的规范化坐标系中(-1,1),并转换成UV坐标(0,1)然后在一张阴影的图片里采样,然后与平面的纹理采样的颜色结果混合。
首先,我们准备一张纹理:&,然后,我们也将其设置好参数,并将其采样器传入到shader里:
auto&shadowTexture&=&Director::getInstance()-&getTextureCache()-&addImage("shadowCircle.png");
Texture2D::TexParams&tRepeatP//set&texture&parameters
tRepeatParams.magFilter&=&GL_LINEAR;
tRepeatParams.minFilter&=&GL_LINEAR;
tRepeatParams.wrapS&=&GL_CLAMP_TO_EDGE;
tRepeatParams.wrapT&=&GL_CLAMP_TO_EDGE;
shadowTexture-&setTexParameters(tRepeatParams);&
state-&setUniformTexture("u_shadowTexture",shadowTexture);
tRepeatParams.wrapS&=&GL_CLAMP_TO_EDGE;
tRepeatParams.wrapT&=&GL_CLAMP_TO_EDGE;
这两个部分,因为我们这个方式依赖的通过UV坐标将阴影的纹理与地面的纹理混合,所以对于S、T(UV)坐标的寻址方式一定要设置成CLAMP,否则对于非阴影的区域它也会采样上阴影的颜色。
这种方式在顶点着色器里与上一种没有任何区别,在这里我们主要是看看片段着色器部分:
void&main(void)
&&&&float&Radius&=&4;//投影范围
&&&&vec3&UVector&=&vec3(1,&0,&0)/(2&Y&Radius);//将世界坐标变换到纹理投影空间坐标并规范化到0-1之间(正投影)
&&&&vec3&VVector&=&vec3(0,&0,&-1)/(-2&V&Radius);//同上
&&&&float2&&&
&&&&coord.x&=&dot(v_position&-&u_target_pos,&UVector)&+&0.5;
&&&&coord.y&=&dot(v_position&-&u_target_pos,&VVector)&+&0.5;
&&&&gl_FragColor&=&texture2D(CC_Texture0,TextureCoordOut)
&&&&Otexture2D(u_shadowTexture,coord);
在这里我们来解释一下如何片段着色器代码的原理。
(v_position&&&u_target_pos)计算的是从角色的位置指向地面上一点的向量,然后让其点乘相当于分别计算了到UVector和VVector的投影,因为这里假设是从上方往下望的,如果你想实现的结果并不是这样,比方说地面的法线法向与Y轴不平行,请传入以阴影大小范围单独设置的投影矩阵记做proj,然后以角色的位置并朝向该地面做出一个视图矩阵记做view,再计算UV坐标记做UVCoords:
vec3&ProjCoords&=&projVviewQv_position;
vec2&UVC&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
UVCoords.x&=&0.5EProjCoords.x&+0.5;//规范化&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
UVCoords.y&=&0.5TProjCoords.y&+0.5;//规范化
最后的效果如下:
学完了这篇教程,相信大家已经学会了如何在Cocos2d-x中实现一个简单的阴影。
在上一篇文章中,我们介绍了,cocos怎么集成友盟的Cocos2d-x版本SDK,接下来我们来说下怎么将友盟的C++接口导出到Lua中使用。引擎版本:Quick-Cocos2d-x3.3开发系统:Windows764bit编写.tolua文件我们打开libMobClickCpp\&include文件夹可以看到里面有两个文件,分别是:
在上一篇文章中,我们介绍了,怎么集成友盟的Cocos2d-x版本SDK,接下来我们来说下怎么将友盟的C++接口导出到Lua中使用。引擎版本:&Quick-Cocos2d-x&3.3&开发系统:&Windows&7&64bit编写.tolua文件我们打开libMobClickCpp\include文件夹可以看到里面有两个文件,分别是:
MobClickCpp.h
MobClickJniHelper.h
打开这两个文件看他们的内容可以发现,MobClickJniHelper.h的内容中只有一个
static&void&setJavaVM(JavaVM&EjavaVM);
而在MobClickCpp.h中包含了我们基本上能使用的所有的umeng的接口,所以我们需要导出的接口其实就是MobClickCpp中的接口。
新建一个MobClickLua.tolua文件,将下面的内容复制进去,我们再来详细分析下:
飞iinclude&"MobClickCpp.h"
怡using&namespace&
class&MobClickCpp&{
&&&&static&void&setLogEnabled(bool&value);
&&&&static&void&setProxy(const&charO&host,&int&port);
&&&&static&void&setSessionIdleLimit(int&seconds);
&&&&static&void&startWithAppkey(const&char&Q&appKey,&const&char&H&channelId&=&NULL);
&&&&static&void&end();
&&&&static&void&mainloop(float&dt);
&&&&static&void&event(const&char&L&eventId,&const&char&U&label&=&NULL);
&&&&static&void&beginLogPageView(const&char&PpageName);
&&&&static&void&endLogPageView(const&char&YpageName);
&&&&static&void&setUserLevel(const&char&Flevel);
&&&&enum&Sex{
&&&&&&&&Unkonwn&=&0,
&&&&&&&&Male&=&1,
&&&&&&&&Female&=&2,
&&&&static&void&setUserInfo(const&char&G&userId,&Sex&sex,&int&age,&const&char&V&platform);
&&&&static&void&startLevel(const&char&P&level);
&&&&static&void&finishLevel(const&char&E&level);
&&&&static&void&failLevel(const&char&T&level);
&&&&static&void&pay(double&cash,&int&source,&double&coin);
&&&&static&void&pay(double&cash,&int&source,&const&char&U&item,&int&amount,&double&price);
&&&&static&void&buy(const&char&Titem,&int&amount,&double&price);
&&&&static&void&use(const&char&V&item,&int&amount,&double&price);
&&&&static&void&bonus(double&coin,&int&source);
&&&&static&void&bonus(const&char&R&item,&int&amount,&double&price,&int&source);
我们可以看到上面的内容基本上都是MobClickCpp.h文件中的接口。我们现在来详细说下这几个部分的意思。第一部分的代码是:
汶ginclude&"MobClickCpp.h"
这里的代码是引用代码,需要包含的头文件可以填到这里。第二部分是这一句:
迁using&namespace&
我们打开MobClickCpp.h的内容可以看到里面定义了一个命名空间为
namespace&umeng{
,为了能在转出来的.cpp文件中使用umeng的接口,我们需要把命名空间引用过去。所以这里加了这一句话方便在.cpp文件中使用umeng命名空间。第三部分就是我们具体的类的定义了,这里最好是直接拷贝.h文件中的类的声明。当然,你想自己定义一个类来作为中间层,也可以声明为自定义的层。这个时候记得要修改第一部分和第二部分的代码。将.tolua文件转为luabinding&c++代码在Quick-Cocos2d-x&3.3中自带了tolua++工具,位置在[QUICK_V3_ROOT]/quick/bin下面的win32或者是mac下,我们最好将它们都添加到系统的PATH环境变量中,方便下次使用。在命令行下直接输入:
可以看到tolua++的帮助信息
usage:&tolua++&[options]&input_file
Command&line&options&are:
&&-v&&&&&&&:&print&version&information.
&&-o&&file&:&set&output&&default&is&stdout.
&&-H&&file&:&create&include&file.
&&-n&&name&:&set&package&&default&is&input&file&root&name.
&&-p&&&&&&&:&parse&only.
&&-P&&&&&&&:&parse&and&print&structure&information&(for&debug).
&&-S&&&&&&&:&disable&support&for&c++&strings.
&&-1&&&&&&&:&substract&1&to&operator[]&index&(for&compatibility&with&tolua5).
&&-L&&file&:&run&lua&file&(with&dofile())&before&doing&anything.
&&-D&&&&&&&:&disable&automatic&exporting&of&destructors&for&classes&that&have
&&&&&&&&&&&&&constructors&(for&compatibility&with&tolua5)
&&-W&&&&&&&:&disable&warnings&for&unsupported&features&(for&compatibility
&&&&&&&&&&&&&with&tolua5)
&&-C&&&&&&&:&disable&cleanup&of&included&lua&code&(for&easier&debugging)
&&-E&&value[=value]&:&add&extra&values&to&the&luastate
&&-t&&&&&&&:&export&a&list&of&types&asociates&with&the&C++&typeid&name
&&-q&&&&&&&:&don't&print&warnings&to&the&console
&&-h&&&&&&&:&print&this&message.
Should&the&input&file&be&omitted,&stdin&is&
in&that&case,&the&package&name&must&be&explicitly&set.
了解上面这些信息后,我们执行命令:
tolua++&&-o&lua_binding_MobClickCpp.cpp&-H&lua_binding_MobClickCpp.h&MobClickCpp.tolua
执行完成后将会生成两个文件:
lua_binding_MobClickCpp.cpp
lua_binding_MobClickCpp.h
生成的两个文件就是我们将.tolua的描述信息转为lua_binding的接口之后的.cpp和.h文件,这两个文件既可以放到引擎的目录下也可以放到工程目录下,这里为了描述方面我就把它们放到工程目录下了。添加C++代码到工程中拷贝上面的两个文件到工程下的umeng\frameworks\runtime-src\Classes目录,然后打开proj.android_no_anysdk\jni下的Android.mk文件,给LOCAL_SRC_FILES加上&../../Classes/lua_binding_MobClickCpp.cpp&\,加上之后的LOCAL_SRC_FILES内容如下:
LOCAL_SRC_FILES&:=&hellolua/main.cpp&\
../../Classes/VisibleRect.cpp&\
../../Classes/AppDelegate.cpp&\
../../Classes/ConfigParser.cpp&\
../../Classes/lua_binding_MobClickCpp.cpp&\
添加Java代码(仅限Android)打开proj.android工程中的AppActivity.java文件,在函数onCreate中添加下面的语句:
MobClickCppHelper.init(this);
添加C++代码打开AppDelegate.cpp文件,添加头文件
vinclude&"MobClickCpp.h"
pinclude&"lua_binding_MobClickCpp.h"
然后再在函数&bool&AppDelegate::applicationDidFinishLaunching()中添加以下代码:
tolua_MobClickCpp_open(L);
注意上面这一句添加的位置必须要在获取到lua_State之后。接着分别在AppDelegate::applicationDidEnterBackground和AppDelegate::applicationWillEnterForeground中分别添加
umeng::MobClickCpp::applicationDidEnterBackground();
umeng::MobClickCpp::applicationWillEnterForeground();
改完C++代码后,build_native编译C++代码。稍等片刻,我们等待C++编译完。在Lua代码中使用umeng我们打开Quick-Cocos2d-x工程中的MyApp.lua代码文件,修改function&MyApp:run()的内容为:
function&MyApp:run()
&&&&cc.FileUtils:getInstance():addSearchPath("res/")
&&&&self:enterScene("MainScene")
&&&&MobClickCpp:startWithAppkey("e58e62eb000288",&"GooglePlay")
这里的&e58e62eb000288&是我们在umeng官网上创建APP的时候所给的AppKey。GooglePlay为我们所使用的渠道。打开Eclipse,在手机上运行工程,我们可以在后台看到umeng的数据打开应用的详细页面,点击渠道分析,里面有一个渠道列表的子选项,点击之后我们可以看到我们上传的渠道用户数量:好了,友盟的C++版本在Lua的使用就介绍到这里,其他umeng的接口大家可以看下MobClickCpp.h文件中查看接口说明。下一篇我们看在Lua里直接使用Java版本的umeng接口。
本文将主要来讲讲游戏开发中的怪物智能,一个好的游戏一般怪物都要分等级,这样我们游戏玩起来才有意思,怪物如果智商太高,游戏难度大。怪物如果智商太低,游戏玩起来又没有意思。一般好的游戏低级怪物和中级怪物占大部分,高级怪物一般是BOSS级怪物。下面我来讲讲自己对怪物AI的一些见解吧。本文接上一节《Cocos2d-x血条跟随怪物运动--之游戏开发《赵云要格斗》(5)...&
本文将主要来讲讲游戏开发中的怪物智能,一个好的游戏一般怪物都要分等级,这样我们游戏玩起来才有意思,怪物如果智商太高,游戏难度大。怪物如果智商太低,游戏玩起来又没有意思。一般好的游戏低级怪物和中级怪物占大部分,高级怪物一般是BOSS级怪物。下面我来讲讲自己对怪物AI的一些见解吧。本文接上一节《Cocos2d-x血条跟随怪物运动--之游戏开发《赵云要格斗》(5)》
2d-x版本:2.2.5
工程环境:Windows7+VS2010
打开方式:将工程放在Cocos2d-x安装目录下的project文件夹下用VS打开
先看看效果:
一、怪物智能AI思路讲解
低级怪物---一般是不能动的怪物,固定在原处,不断的发动攻击,然后根据英雄的方位,不断改变子弹的朝左还是朝向,如游戏中的炮台等。
中级怪物----初步有一些智商了,主要表现在当英雄在它的攻击范围内,能够知道英雄的位置,就以一定的比例判断是否进行攻击。如若不然,平时都是自己按照一定的路线进行行走,又或者是随机走动。然后攻击随机出动,只有当英雄在它的攻击范围内,它才会不再走动,原地以概率判断是否要进行攻击
高级怪物-----BOSS级怪物,它有自己的可视范围区,当英雄陷入它的可视范围区时,它就追着英雄跑。可视范围区内,还有个攻击范围区,当英雄陷入攻击范围区内时,怪物就按一定的概率出动攻击,这个概率一般比较大。然后,如果英雄不在怪物的可视范围区内时,怪物它有自己的巡逻路线,它按照这个路线不断的走,总会发现到英雄,英雄你再怎么跑,它都会跟着你。
,当然,上面说的都是比较简单的了,实际游戏中怪物还会分得更细,比如有的怪物能自动加血,有的怪物还能召唤等,这里就不再详细讲下去了,若有兴趣,自己再去百度下等,怪物智能这个涉及到人工智能,深入下去就是算法的问题了。
(这是我用PS自己弄的,哈哈,还可以吧,程序员PS真应该也稍微学点!)
本文主要是要设置一个高级怪物AI的一个算法,下面是它的流程图:
下面是本文的一个效果:
二、Monster类增加函数
在讲的Monster类的增加函数,3秒计算要怎么来实现呢?其实很简单,就开一个3秒的计数器事件不就完了么?
this-&schedule(schedule_selector(Monster::updateMonster),3.0f);//每隔3秒计算距离
然后就是计算怪物和英雄的距离了,这中间涉及到很多判断,具体可以看上面的算法流程图,然后再参考下代码,注意,
StartListen(CCNodeY&m_hero,CCNodeV&m_map)
这是开始启动怪物监听英雄的函数。
首先是在Monster.h中添加:
//在可视范围内,怪物跟随英雄运动
void&FollowRun(CCNodeD&m_hero,CCNodeP&m_map);
//判断是否攻击
void&JudegeAttack();
//怪物巡逻路线
void&MonsterSeeRun();
//怪物启动监听英雄
void&StartListen(CCNodeE&m_hero,CCNodeX&m_map);
//监听函数,每隔3秒检测下,计算英雄与怪物的距离
void&updateMonster(float&delta);
//更新函数,如果英雄在可视范围内,不断触发
void&update(float&delta);
CCNodeH&my_//当前英雄
CCNodeE&my_//当前地图
float&&&//当前怪物和英雄的距离
然后这是它的实现Monster.cpp:
void&Monster::FollowRun(CCNodeA&m_hero,CCNodeI&m_map)&&
&&&&//得到两点x的距离,记得怪物的坐标要加上地图的&&
&&&&float&x&=&m_hero-&getPositionX()-(this-&getPositionX()+m_map-&getPositionX());&&
&&&&//得到两点y的距离,记得怪物的坐标要加上地图的&&
&&&&float&y&=&m_hero-&getPositionY()-(this-&getPositionY()+m_map-&getPositionY());&&
&&&//先计算怪物和英雄的距离&&
&&&&dis&=&sqrt(pow(x,2)&+&pow(y,2));&&
&&&&if(dis&=300)//当怪物与英雄距离超过300&&
&&&&&&&&&&
&&&&if(dis&=100)//在怪物攻击范围内,怪物停止移动&&
&&&&&&&&this-&StopAnimation();//停止跑动&&
&&&&&&&&JudegeAttack();//以一定的概率判断是是否出动攻击&&
&&&&&&&&&&
&&&&if(x&-100)//判断怪物横坐标和英雄的距离&&
&&&&&&&&{&&
&&&&&&&&&&&&&&&
&&&&&&&&&&&&MonsterDirecton=&&
&&&&&&&&&&&&m_MonsterSprite-&setFlipX(MonsterDirecton);//设置方向&&
&&&&&&&&&&&&if(IsAttack)&&
&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&this-&setPosition(this-&getPositionX()-1,this-&getPositionY());//怪物向英雄移动&&
&&&&&&&&&&&&&this-&SetAnimation("monster_run",6,MonsterDirecton);//播放动画&&
&&&&else&if(x&100)&&
&&&&&&&&{&&
&&&&&&&&&&&&&&&
&&&&&&&&&&&&MonsterDirecton=&&
&&&&&&&&&&&&m_MonsterSprite-&setFlipX(MonsterDirecton);//设置方向&&
&&&&&&&&&&&&if(IsAttack)&&
&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&this-&setPosition(this-&getPositionX()+1,this-&getPositionY());&&
&&&&&&&&&&&&&this-&SetAnimation("monster_run",6,MonsterDirecton);//播放动画&&
&&&&else&if(x&=100)//怪物橫坐標和英雄相差在100以内时,开始移动怪物纵坐标&&
&&&&&&&&if(m_hero-&getPositionY()&this-&getPositionY())&&
&&&&&&&&{&&
&&&&&&&&&&&&m_MonsterSprite-&setFlipX(MonsterDirecton);//设置方向&&
&&&&&&&&&&&&if(IsAttack)&&
&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&this-&setPosition(this-&getPositionX(),this-&getPositionY()+1);&&
&&&&&&&&&&&&&this-&SetAnimation("monster_run",6,MonsterDirecton);//播放动画&&
&&&&&&&&}&&
&&&&&&&&else&if(m_hero-&getPositionY()&this-&getPositionY())&&
&&&&&&&&{&&
&&&&&&&&&&&&m_MonsterSprite-&setFlipX(MonsterDirecton);//设置方向&&
&&&&&&&&&&&&if(IsAttack)&&
&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&this-&setPosition(this-&getPositionX(),this-&getPositionY()-1);&&
&&&&&&&&&&&&this-&SetAnimation("monster_run",6,MonsterDirecton);//播放动画&&
&&&&&&&&}&&
void&Monster::JudegeAttack()&&
&&&&srand}

我要回帖

更多关于 页面传奇游戏 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信