我想让吃这款游戏使用64java让主线程等待该怎么做

戴尔灵越玩游戏怎么样3个回答藤泽h71这款本本的配置还算可以,采用Intel最新的i3处理器,这款处理器是蛮不错的:2.13GHz的主频、双核心四线程、3MB的3级缓存。打游戏绝对够用。2GBDDRIII的内存也是亮点。就是显卡有点低了,ATI HD 4330显卡,只有64bit的位宽……实在不能说是一款中端显卡。512的显存倒是够用了。反正打游戏不要特效全开,用中低特效的话现在一般游戏都能应负的来。要是特别吃显卡的游戏,肯定是带不起来了。这款电脑售价是四千多,如果你不在乎多支付一千块的话就可以买更高端的配备睿频技术的酷睿i5CPU和ATI HD4570显卡的本本。性价比更高,游戏性能也更好。
希望对你有帮助
wap你好,这款机子非常不错。i5是物理四核,通过intel的超线程技术可以虚拟8核。这么说吧,以前你的马车是一只马拉,现在是8匹马拉,动力就足够了。还有,你老电脑的DDR速度和硬盘转速都低,显存也不足,所以慢。我推荐的机子是i5+4gddr 1600MHZ+2g独显,跑大型3D游戏都够了。
soufunwa戴尔灵越系列我个人觉得还是比较不错的,性能、速度都很不错。音质好的没话说。散热也还可以。大多数电脑应用都能无压力运行。外观觉得比较好看。
希望可以帮到你,祝你生活愉快,望采纳
热门问答123456789101112131415161718192021222324252627282930相关问答3个回答袁嘉誉戴尔灵越14r拆法如下;
具体拆机步骤如下:
拆下电池,拧松掉这个盖板的螺丝,打开盖板,拆下内存条和光驱。
拆下光驱电、池和内存后,拧下螺丝及蓝色圈内的隐...3个回答lizhongcai98你好,很高兴解答您的问题。
中等、主流的i5 cpu 显卡不错,能带大型游戏
其他配置属于中等,一般化 也不错
关键看cpu 和显卡
总体属于中上游的笔记本...3个回答cwandyn您好,戴尔灵越3443是一款轻巧纤薄款,性能还可以,玩网络游戏,上网速度可以,看电影,上qq也很流畅,外观我也比较喜欢。很不错的。希望我的回答对你有帮助。
3个回答莫鸿雪戴尔笔记本灵越14r挺不错的,Inspiron灵越14R使用了富有激情的红色,中央则是标志式的“DELL”Logo,金属光泽显得非常有质感,在阳光照耀下反射出耀眼的光芒,同时作为纯...3个回答漂泊在外南溪人我觉得戴尔灵越14mr挺好用的,不过戴尔的笔记本外观都很普通,但是性能很好,配置的系统也很高端,运行速度什么都挺快的,性价比比较高。
3个回答bkll1992戴尔笔记本灵越系列的性能不错,戴尔 灵越 15 5000是戴尔推出的一款超值家庭娱乐本,机身采用全新光感设计,尽显极致简约的设计理念,金属拉丝外壳搭配流线型边框,是的整体机型看起来...3个回答tj_zhangmin戴尔灵越14(Ins14VD-269B)笔记本采用奔腾双核P6000处理器,英特尔HM57主板芯片,戴尔无线b/g半高迷你卡;拥有2GB DDR3-1333内...3个回答zuoyuesibia戴尔Latitude E5520 笔记本电脑报价不是特别高的,
参考报价:¥5890
屏幕尺寸: 15.6英寸
CPU型号: Intel酷睿i32...4个回答小夜L箐335  戴尔灵越系列台式机有7种型号,型号分别如下:
  戴尔Inspiron灵越 660s 系列台式机、戴尔Inspiron灵越 660 系列台式机、戴尔Inspiron灵越 ...3个回答elXZ44S  戴尔灵越17r挺好的。戴尔灵越17R笔记本外壳采用铝合金,轮廓线条勾勒得轻快明了,略显圆润的边角过度自然流畅,给人一种不错的大方、大度、大气的外观享受。笔记本上网采用TP-LI...游戏研究院游戏研究院研究游戏技术关注专栏更多最新文章{&debug&:false,&apiRoot&:&&,&paySDK&:&https:\u002F\u002Fpay.zhihu.com\u002Fapi\u002Fjs&,&wechatConfigAPI&:&\u002Fapi\u002Fwechat\u002Fjssdkconfig&,&name&:&production&,&instance&:&column&,&tokens&:{&X-XSRF-TOKEN&:null,&X-UDID&:null,&Authorization&:&oauth c3cef7c66aa9e6a1e3160e20&}}{&database&:{&Post&:{&&:{&title&:&Unity3D热更新LuaFramework入门实战(8)——声音管理器&,&author&:&pyluo&,&content&:&\u003Cp\u003ELuaFramework内置的管理器包括GameManager(处理热更新)、luaManager(lua脚本管理器)、PanelManager(界面管理器)、NetworkManager(网络管理器)、ResourceManager(资源管理器)、TimerManager(时间管理器)、线程管理器(ThreadManager)和SoundManager(声音管理器)。其中GameManager、luaManager、PanelManager、NetworkManager、ResourceManager在前面的文章中已经有过介绍,这一篇讲讲讲播放声音相关的SoundManager。\u003C\u002Fp\u003E\u003Cp\u003Eby 罗培羽\u003Cbr\u003E\u003C\u002Fp\u003E\u003Ch2\u003E\u003Cb\u003E1、使用方法\u003C\u002Fb\u003E\u003C\u002Fh2\u003E\u003Cp\u003ESoundManager估计是从其他地方拷过来的,并不能很好的与框架结合,这里我们先看看原来的SoundManager的使用方法,再介绍它的不足之处及改进方法。虽然SoundManager定义了好几个方法,但能直接在lua中使用的只有用于播放背景音乐的PlayBacksound。\u003C\u002Fp\u003E\u003Cp\u003E编写播放声音的代码前,需要在GameManager上挂载AudioSource组件,以播放背景音乐。\u003C\u002Fp\u003E\u003Cimg src=\&ae823f297d76c1db82450f.png\& data-rawwidth=\&474\& data-rawheight=\&277\&\u003E\u003Cp\u003E把声音文件放到Resource目录下,由于SoundManager使用Resources.Load加载声音文件,声音文件必须放到这个目录下。如下图所示。\u003C\u002Fp\u003E\u003Cimg src=\&f1acac3ddb9f1259aaf6d77.png\& data-rawwidth=\&172\& data-rawheight=\&90\&\u003E\u003Cp\u003E然后编写lua代码,调用soundMgr:PlayBacksound即可,它的第一个参数指明Resource目录下的文件名,第二个参数为true表示开始播放,false表示停止播放。\u003C\u002Fp\u003E\u003Ccode lang=\&text\&\u003E--主入口函数。从这里开始lua逻辑\nfunction Main()\t\t\t\t\t\n\tLuaHelper = LuaFramework.LuaH\n\tsoundMgr = LuaHelper.GetSoundManager();\n\tsoundMgr:PlayBacksound(\&motor\&, true)\nend\u003C\u002Fcode\u003E\u003Cp\u003E运行游戏,即可听到音效。关于Unity3D播放声音的内容,大家也可以参考《Unity3D网络游戏实战》哦!\u003C\u002Fp\u003E\u003Ch2\u003E2、\u003Cb\u003E代码解析\u003C\u002Fb\u003E\u003C\u002Fh2\u003E\u003Cp\u003ESoundManager的示意代码如下,实际上是使用Resources.Load来加载资源的,所以声音文件必须放在Resources目录下。\u003C\u002Fp\u003E\u003Cimg src=\&aa4d7bd7bec7e9eca27eb.png\& data-rawwidth=\&679\& data-rawheight=\&557\&\u003E\u003Cp\u003E这种用法违背了热更新框架的设计,因为在Resources目录下的文件并不能热更。\u003C\u002Fp\u003E\u003Ch2\u003E\u003Cb\u003E3、改进的声音管理器\u003C\u002Fb\u003E\u003C\u002Fh2\u003E\u003Cp\u003E这一部分我们需要改进声音管理器,实现这么几个功能:\u003C\u002Fp\u003E\u003Cp\u003E1)从本地“数据目录”读取打包后的声音文件,使它支持热更新;\u003C\u002Fp\u003E\u003Cp\u003E2)添加播放\u002F停止背景音乐的PlayBackSound\u002FStopBackSound和播放音效的PlaySound方法;\u003C\u002Fp\u003E\u003Cp\u003E3)使用缓存存储加载后的声音文件,以提高运行效率。\u003C\u002Fp\u003E\u003Cp\u003E为了支持加载AudioClip的加载,在ResourceManager中添加LoadAudioClip方法,该方法将会加载资源包abName的资源assetName,加载完AudioClip资源后调用回调函数func,代码如下。\u003C\u002Fp\u003E\u003Ccode lang=\&text\&\u003E\u002F\u002F载入音效资源\npublic void LoadAudioClip(string abName, \n
string assetName, Action&UObject[]& func) \n{\n\tLoadAsset&AudioClip&(abName, new string[] { assetName }, func);\n}\u003C\u002Fcode\u003E\u003Cp\u003E修改SoundManager,使用Hashtable类型的sounds存储加载后的声音,包含PlayBackSound、StopBackSound和PlaySound三个API。代码如下所示。\u003C\u002Fp\u003E\u003Cp\u003E先是整体kuan\u003C\u002Fp\u003E\u003Ccode lang=\&text\&\u003Eusing UnityE\nusing System.C\nusing System.Collections.G\n \nnamespace LuaFramework \n{\n
public class SoundManager : Manager \n
{\n\tprivate AudioS\n\tprivate Hashtable sounds = new Hashtable();\n\tstring backSoundKey = \&\&;\n \n\tvoid Start() \n\t{\n\t\taudio = GetComponent&AudioSource&();\n\t\tif (audio == null)\n\t\t\tgameObject.AddComponent&AudioSource& ();\n\t}\n \n\t\u002F\u002F回调函数原型\n\tprivate delegate void GetBack(AudioClip clip, string key);\n \n\t\u002F\u002F获取声音资源\n\tprivate void Get(string abName, string assetName, GetBack cb)\n\t{\n\t\tstring key = abName + \&.\& + assetN\n\t\tif(sounds [key] == null) \n\t\t{\n\t\t\tResManager.LoadAudioClip(abName, assetName, (objs)=&\n\t\t\t{\n\t\t\t\tif(objs == null || objs[0] == null)\n\t\t\t\t{\n\t\t\t\t\tDebug.Log(\&PlayBackSound fail);\n\t\t\t\t\tcb(null,key);\n\t\t\t\t\\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tsounds.Add(key, objs[0]);\n\t\t\t\t\tcb(objs[0] as AudioClip ,key);\n\t\t\t\t\\n\t\t\t\t}\n\t\t\t});\n\t\t} \n\t\telse \n\t\t{\n\t\t\tcb(sounds [key] as AudioClip,key);\n\t\t\\n\t\t}\n\t}\n
}\n}\u003C\u002Fcode\u003E\u003Cbr\u003E\u003Cp\u003EPlayBackSound:\u003C\u002Fp\u003E\u003Ccode lang=\&text\&\u003E\t\u002F\u002F播放背景音乐\n\tpublic void PlayBackSound(string abName, string assetName)\n\t{\n\t\tbackSoundKey = abName + \&.\& + assetN\n\t\tGet(abName, assetName,(clip, key)=&\n\t\t{\n\t\t\tif(clip == null)\n\t\t\t\\n\t\t\tif(key != backSoundKey)\n\t\t\t\\n \n\t\t\taudio.loop =\n\t\t\taudio.clip =\n\t\t\taudio.Play();\n\t\t});\n\t}\n\u003C\u002Fcode\u003E\u003Cp\u003EStopBackSound:\u003C\u002Fp\u003E\u003Ccode lang=\&text\&\u003E\t\u002F\u002F停止背景音乐\n\tpublic void StopBackSound()\n\t{\n\t\tbackSoundKey = \&\&;\n\t\taudio.Stop ();\n\t}\n\u003C\u002Fcode\u003E\u003Cbr\u003E\u003Ccode lang=\&text\&\u003E \t\u002F\u002F播放音效\n\tpublic void PlaySound(string abName, string assetName)\n\t{\n\t\tGet(abName, assetName,(clip, key)=&\n\t\t{\n \n\t\t\tif(clip == null)\n\t\t\t\\n\t\t\tif(Camera.main == null)\n\t\t\t\\n\t\tAudioSource.PlayClipAtPoint(clip, \n\t\t\t\t\tCamera.main.transform.position); \n\t\t});\n\t}\n\u003C\u002Fcode\u003E\u003Cp\u003E修改代码后,需要重新生成wrap文件(点击菜单栏的Lua→Clear wrap files和Lua→Generate All)。然后编写lua代码调试它吧!这里演示的是先播放背景音乐,3秒后停止播放,每隔0.3秒播放一次音效的功能。\u003C\u002Fp\u003E\u003Ccode lang=\&text\&\u003E--主入口函数。从这里开始lua逻辑\nfunction Main()\t\t\t\t\t\n\tLuaHelper = LuaFramework.LuaH\n\tsoundMgr = LuaHelper.GetSoundManager();\n\tsoundMgr:PlayBackSound(\&sound\&, \&motor\&)\n\tUpdateBeat:Add(Update, self)\nend\n \n \nlocal lastTime = 0\n \nfunction Update()\n\tif Time.time & 3 then\n\t\tsoundMgr:StopBackSound();\n\tend\n\t\n\t\n\tif Time.time - lastTime & 0.3 then\n\t\tsoundMgr:PlaySound(\&sound\&, \&shoot\&)\n\t\tlastTime = Time.time\n\tend\nend\u003C\u002Fcode\u003E\u003Cp\u003E读者还可以使用类似 LoadAudioClip的方法加载其他资源,笔者也是刚刚接触LuaFramework不久,文章错误之处在所难免,请大家多加包涵。\u003C\u002Fp\u003E\u003Cbr\u003E\u003Cp\u003E最后是广告时间:\u003C\u002Fp\u003E\u003Cp\u003E《16年的长度 记录中国独立游戏》从十多年前程序员写的小玩儿,到如今使用游戏引擎开发的炫酷产品,独立游戏作者的故事见证了我国游戏业的发展历程。来看看国产单机的造梦者们,在这十几年中做出怎么的作品,现在又过得如何。\u003C\u002Fp\u003E\u003Cp\u003E\u003Ca href=\&http:\u002F\u002Fgames.sina.com.cn\u002Fzl\u002Fduanpian\u002F\u002F1538151.shtml\& data-editable=\&true\& data-title=\&16年的长度 记录中国独立游戏\&\u003E16年的长度 记录中国独立游戏\u003C\u002Fa\u003E\u003C\u002Fp\u003E\u003Cp\u003E《仙剑5前传之心愿》是笔者两年前发起的一款仙剑同人游戏,使用Unity3D制作,是市面上第一款能够完成的3D仙剑同人游戏。如今我们各自踏上游戏开发一途,似乎要做点什么以致敬国产经典之作,在追求商业成就的同时,勿忘初心。可以在\u003Ca href=\&http:\u002F\u002Fwww.pal5h.com\& data-editable=\&true\& data-title=\&仙剑5前传之心愿\&\u003E仙剑5前传之心愿\u003C\u002Fa\u003E下载该游戏。《仙剑5前传之心愿》截图如下。\u003C\u002Fp\u003E\u003Cimg src=\&89c22952d3fee3b8e37b.png\& data-rawwidth=\&625\& data-rawheight=\&338\&\u003E\u003Cbr\u003E&,&updated&:new Date(&T13:29:28.000Z&),&canComment&:false,&commentPermission&:&anyone&,&commentCount&:1,&likeCount&:11,&state&:&published&,&isLiked&:false,&slug&:&&,&isTitleImageFullScreen&:false,&rating&:&none&,&sourceUrl&:&&,&publishedTime&:&T21:29:28+08:00&,&links&:{&comments&:&\u002Fapi\u002Fposts\u002F2Fcomments&},&url&:&\u002Fp\u002F&,&titleImage&:&https:\u002F\u002Fpic4.zhimg.com\u002Faa4d7bd7bec7e9eca27eb_r.jpg&,&summary&:&&,&href&:&\u002Fapi\u002Fposts\u002F&,&meta&:{&previous&:null,&next&:null},&snapshotUrl&:&&,&commentsCount&:1,&likesCount&:11},&&:{&title&:&Unity3D热更新LuaFramework入门实战(9)——线程管理器&,&author&:&pyluo&,&content&:&\u003Cp\u003ELuaFramework内置了线程管理器ThreadManager,一开始我以为这是个创建线程、终止线程等方法的封装。然而不是,它是热更新时使用线程下载资源的具体实现。那让我们来看看线程管理器的工作原理吧。\u003C\u002Fp\u003E\u003Cp\u003E@罗培羽\u003C\u002Fp\u003E\u003Ch2\u003E1、GameManager的调用\u003C\u002Fh2\u003E\u003Cp\u003E那么先看看在热更新过程中哪些地方调用到ThreadManager。热更新由GameManager执行(相关代码如下图所示),它在对比本地文件和网络资源的差异后,将需要下载的文件名存放到列表中,然后遍历列表,调用BeginDownload下载。从代码可以看出,它通过ISDownOK判断该文件是否下载完成,然后下载下一个文件,一个个的下载文件。\u003C\u002Fp\u003E\u003Cimg src=\&v2-9d2ec6aa2bda6504025a.png\& data-rawwidth=\&692\& data-rawheight=\&347\&\u003E\u003Cp\u003EBeginDownload(代码如下所示)便调用ThreadManager的AddEvent方法。ThreadManager并不是真正意义上的线程管理器,它只管理一条“下载线程”,通过AddEvent将要下载的文件名放到“代办列表”中,该线程依次下载它们。其中的OnThreadCompleted是“回调函数”,在下载该文件后,会通过消息的方式回调它。\u003C\u002Fp\u003E\u003Cimg src=\&v2-8bcf6b58df897c65d2f8.png\& data-rawwidth=\&663\& data-rawheight=\&188\&\u003E\u003Cp\u003E在“下载线程”下载完一个文件后,它以通知的形式调用“回调函数”OnThreadCompleted(代码如下所示),该方法将会设置“下载完成列表”downloadFiles。\u003C\u002Fp\u003E\u003Cimg src=\&v2-bc9da8e0c52fb864c71f7d2.png\& data-rawwidth=\&604\& data-rawheight=\&322\&\u003E\u003Cp\u003E再看看IsDownOk(代码如下所示)方法,当“下载完成列表”包含该文件时,说明下载已经完成,可以进行下一个文件的下载。\u003C\u002Fp\u003E\u003Cimg src=\&v2-c5246dcbef061ee5be76bef416ef31f7.png\& data-rawwidth=\&429\& data-rawheight=\&155\&\u003E\u003Ch2\u003E2、ThreadManager的启动\u003C\u002Fh2\u003E\u003Cp\u003EThreadManager启动时,开启一个线程“下载线程”,相关代码如下所示。由此ThreadManager仅仅是管理一条线程,而不是真正意义的线程管理器。\u003C\u002Fp\u003E\u003Cimg src=\&v2-ca7ca068f4bd3b9db078d86c94c6a35c.png\& data-rawwidth=\&437\& data-rawheight=\&227\&\u003E\u003Cimg src=\&v2-8f440fdb7b832b13c1b6f2cfd85a49ba.png\& data-rawwidth=\&610\& data-rawheight=\&27\&\u003E\u003Cbr\u003E\u003Ch2\u003E3、AddEvent方法\u003C\u002Fh2\u003E\u003Cp\u003EAddEvent是给线程添加任务的方法,代码如下,其实就是给events队列添加一个值。\u003C\u002Fp\u003E\u003Cimg src=\&v2-9c070f5ecfffe553c27ef51fdace5300.png\& data-rawwidth=\&639\& data-rawheight=\&205\&\u003E\u003Cp\u003EEvents的定义如下所示:\u003C\u002Fp\u003E\u003Cimg src=\&v2-8f440fdb7b832b13c1b6f2cfd85a49ba.png\& data-rawwidth=\&610\& data-rawheight=\&27\&\u003E\u003Cp\u003EThreadEvent包含事件名key和参数evParams,代码如下所示。\u003C\u002Fp\u003E\u003Cimg src=\&v2-6eeb42027aff6c71cd301bbed0da3651.png\& data-rawwidth=\&558\& data-rawheight=\&100\&\u003E\u003Ch2\u003E3、下载过程\u003C\u002Fh2\u003E\u003Cp\u003E“下载线程”执行了OnUpdate方法(代码如下所示),它调用OnDownloadFile下载文件。\u003C\u002Fp\u003E\u003Cimg src=\&v2-2fbd6f850e.png\& data-rawwidth=\&692\& data-rawheight=\&478\&\u003E\u003Cp\u003EOnDownloadFile(代码如下所示)又调用了DownloadFileAsync下载文件,下载文件过程中ProgressChanged方法会被调用。\u003C\u002Fp\u003E\u003Cimg src=\&v2-bf56ebec48.png\& data-rawwidth=\&692\& data-rawheight=\&193\&\u003E\u003Cp\u003EProgressChanged方法记录了下载进度,当进度为100%时,使用m_SyncEvent发送通知,相当于调用“回调函数”OnThreadCompleted。\u003C\u002Fp\u003E\u003Cimg src=\&v2-582eacd240acad3e08aca6fc9fbc7502.png\& data-rawwidth=\&692\& data-rawheight=\&271\&\u003E\u003Cbr\u003E\u003Ch2\u003E4、改进\u003C\u002Fh2\u003E\u003Cp\u003E这套线程管理器依然有“杀鸡用牛刀”之嫌,“任务列表”并没有实际作用(因为GameManager控制了下载进度,一个个下载),消息分发部分也太复杂,实际上只用回调函数之类的方法便能够实现。\u003C\u002Fp\u003E\u003Cp\u003E个人认为线程管理器应当提供线程调度的方法,具体的下载逻辑可在GameManager中实现。而且下载功能不一定非要用线程,协程也能够解决,而且更简单。代码如下所示。\u003C\u002Fp\u003E\u003Cimg src=\&v2-eabafd8932.png\& data-rawwidth=\&545\& data-rawheight=\&178\&\u003E\u003Cp\u003E由于热更新需要下载不少的文件,一个个下载实在太慢。如果能开启多个线程,同时下载,可在一定程度上提高下载速度。\u003C\u002Fp\u003E\u003Cp\u003E框架并没有处理下载失败的情况,一般情况下,当一个文件下载失败,应当重试,在重试多次依然无法下载时,才弹出错误。\u003C\u002Fp\u003E\u003Cbr\u003E\u003Ch2\u003E最后是广告时间:\u003C\u002Fh2\u003E\u003Cp\u003E《16年的长度 记录中国独立游戏》从十多年前程序员写的小玩儿,到如今使用游戏引擎开发的炫酷产品,独立游戏作者的故事见证了我国游戏业的发展历程。来看看国产单机的造梦者们,在这十几年中做出怎么的作品,现在又过得如何。\u003C\u002Fp\u003E\u003Cp\u003E\u003Ca href=\&http:\u002F\u002Fgames.sina.com.cn\u002Fzl\u002Fduanpian\u002F\u002F1538151.shtml\& data-editable=\&true\& data-title=\&16年的长度 记录中国独立游戏\& class=\&\&\u003E16年的长度 记录中国独立游戏\u003C\u002Fa\u003E\u003C\u002Fp\u003E\u003Cbr\u003E\u003Cp\u003E《仙剑5前传之心愿》是笔者两年前发起的一款仙剑同人游戏,使用Unity3D制作,是市面上第一款能够完成的3D仙剑同人游戏。如今我们各自踏上游戏开发一途,似乎要做点什么以致敬国产经典之作,在追求商业成就的同时,勿忘初心。可以在\u003Ca href=\&http:\u002F\u002Fwww.pal5h.com\u002F\& data-editable=\&true\& data-title=\&仙剑5前传之心愿\& class=\&\&\u003Ewww.pal5h.com\u003C\u002Fa\u003E下载该游戏。《仙剑5前传之心愿》截图如下。\u003C\u002Fp\u003E\u003Cimg src=\&v2-4b12ef4dbc4aa0af3dbb89.png\& data-rawwidth=\&625\& data-rawheight=\&338\&\u003E&,&updated&:new Date(&T13:54:21.000Z&),&canComment&:false,&commentPermission&:&anyone&,&commentCount&:5,&likeCount&:4,&state&:&published&,&isLiked&:false,&slug&:&&,&isTitleImageFullScreen&:false,&rating&:&none&,&sourceUrl&:&&,&publishedTime&:&T21:54:21+08:00&,&links&:{&comments&:&\u002Fapi\u002Fposts\u002F2Fcomments&},&url&:&\u002Fp\u002F&,&titleImage&:&&,&summary&:&&,&href&:&\u002Fapi\u002Fposts\u002F&,&meta&:{&previous&:null,&next&:null},&snapshotUrl&:&&,&commentsCount&:5,&likesCount&:4},&&:{&title&:&Unity3D热更新LuaFramework入门实战(10)——示例程序&,&author&:&pyluo&,&content&:&\u003Cp\u003E终于到了本系列完结的时候了。\u003C\u002Fp\u003E\u003Cp\u003E现在,大家对LuaFramework有个全方位的理解了吧!接下来通过一个例子总结ulua,作为“lua逻辑”的延伸,说明lua的写法。这个例子中玩家能够控制2D游戏角色走动,并且发射炮弹。\u003C\u002Fp\u003E\u003Ch2\u003E1、目标\u003C\u002Fh2\u003E\u003Cp\u003E制作如图所示的游戏,玩家可以通过键盘控制角色上下左右移动,角色有4个面向,走动过程中会播放行走动画。当玩家点击鼠标左键,角色会发射一颗炮弹。\u003C\u002Fp\u003E\u003Cimg src=\&v2-0bba3766f7cec9f313c7ab33f7884ba1.png\& data-rawwidth=\&564\& data-rawheight=\&367\&\u003E\u003Ch2\u003E2、游戏资源\u003C\u002Fh2\u003E\u003Cp\u003E使用下图所示的图片作为游戏角色(该图片来自rpg maker),在导入Unity后将它切割成12张小图。\u003C\u002Fp\u003E\u003Cimg src=\&v2-afd34cc68c372bee35b3ab.png\& data-rawwidth=\&180\& data-rawheight=\&240\&\u003E\u003Cimg src=\&v2-0ff319fc86b1c5c2e9e5b8.png\& data-rawwidth=\&692\& data-rawheight=\&77\&\u003E\u003Cbr\u003E\u003Cp\u003E使用如下图所示的图片作为炮弹。\u003C\u002Fp\u003E\u003Cimg src=\&v2-b4c8d9ee317d96d6f2ec9b3.png\& data-rawwidth=\&62\& data-rawheight=\&62\&\u003E\u003Cp\u003E在游戏场景中新建画布,画布下摆放一个名为Panel的面板,代表游戏场景。面板下有res和map两个子物体,map(Image)为一张场景图,role(Image)为游戏中的角色,bullet(Image)为游戏中的子弹(同一时间只能发射一颗子弹)。\u003C\u002Fp\u003E\u003Cimg src=\&v2-bc89b5f2240.png\& data-rawwidth=\&692\& data-rawheight=\&325\&\u003E\u003Cp\u003ERes子物体存放12张角色图片(Image),之后会使用这些资源替换map.role的图片,以实现动画效果。\u003C\u002Fp\u003E\u003Cimg src=\&v2-f5e4fd51fb7.png\& data-rawwidth=\&692\& data-rawheight=\&340\&\u003E\u003Cp\u003E然后将Panel做成预设,存放到SimpleGame目录下。并且在GameManager空物体上添加Game组件,以启动框架。\u003C\u002Fp\u003E\u003Cimg src=\&v2-8ab54e8ea13bd4ac254b4.png\& data-rawwidth=\&693\& data-rawheight=\&596\&\u003E\u003Cp\u003E修改Packager.cs,在HandleExampleBundle添加如下代码,将SimpleGame目录下的预设打包。然后点击LuaFramework→Build Windows Resource打包。\u003C\u002Fp\u003E\u003Ccode lang=\&text\&\u003E\u002F\u002F小游戏\nAddBuildMap(\&SimpleGame\& + AppConst.ExtName, \&*.prefab\&, \&Assets\u002FSimpleGame\&);\u003C\u002Fcode\u003E\u003Cp\u003E具体的框架设置请参加第一篇和第二篇,这里仅做简单描述。\u003C\u002Fp\u003E\u003Ch2\u003E3、编写行走代码\u003C\u002Fh2\u003E\u003Cp\u003E游戏使用UI组件,在CustomSettings.cs中添加如下两行,使tolua生成Image和Sprite相关的调用。\u003C\u002Fp\u003E\u003Ccode lang=\&text\&\u003E_GT(typeof(Image)),\n_GT(typeof(Sprite)),\u003C\u002Fcode\u003E\u003Cp\u003E打开main.lua(如何运行main.lua请参见第一篇)开始编写代码。程序从Main方法开始执行,使用LoadPrefab(请参见第二篇)加载之前打包的资源文件Panel。这里还定义几个变量,其中map代表游戏场景(panel.map),role代表游戏角色(panel.map.role),roleImage是游戏角色中的图片组件,roleRes代表各个面向的角色图片,比如roleRes[“UP”]将会包含panel.res中3张角色朝上的图。roleAnm代表当前角色的动画,每个面向有3个动画,对应于不同的图片。lastAnmTime代表展现角色动画帧的时间,用于控制动画播放速度。\u003C\u002Fp\u003E\u003Ccode lang=\&text\&\u003E--主入口函数。从这里开始lua逻辑\nfunction Main()\t\t\t\t\t\n\tLuaHelper = LuaFramework.LuaH\n\tresMgr = LuaHelper.GetResManager();\n\tresMgr:LoadPrefab('SimpleGame', { 'Panel' }, OnLoadFinish);\nend\n\nlocal map\nlocal role\nlocal roleImage\nlocal roleRes = {\n\t[\&UP\&] = {},\n\t[\&DOWN\&] = {},\n\t[\&LEFT\&] = {},\n\t[\&RIGHT\&] = {},\n}\nlocal roleAnm = 1;\nlocal lastAnmTime = 0;\n\n--加载完成后的回调--\nfunction OnLoadFinish(objs)\n
--暂略\nend\u003C\u002Fcode\u003E\u003Cp\u003E接着编写加载完成的回调方法OnLoadFinish,它处理下面几件事情。\u003C\u002Fp\u003E\u003Cp\u003E1、使用Instantiate实例化面板,并且设置面板的坐标,具体请参见第5篇。\u003C\u002Fp\u003E\u003Cp\u003E2、获取面板中的部件,给map、role、roleImage赋值。\u003C\u002Fp\u003E\u003Cp\u003E3、获取素材res中的图片,赋值给roleRes,之后roleRes [\&UP\&],roleRes [\&DOWN\&],roleRes [\&LEFT\&],roleRes [\&RIGHT\&]都包含3张同面向不同动画的图片。\u003C\u002Fp\u003E\u003Cp\u003E4、使用UpdateBeat:Add()初始化Update方法(具体参照第三篇)。\u003C\u002Fp\u003E\u003Ccode lang=\&text\&\u003Efunction OnLoadFinish(objs)\n\t--显示面板\n\tgo = UnityEngine.GameObject.Instantiate(objs[0])\n\tlocal parent = UnityEngine.GameObject.Find(\&Canvas\&)\n
go.transform:SetParent(parent.transform, false)\n\t--获取元素\n\tmap = go.transform:FindChild(\&map\&).gameObject\n\trole = map.transform:FindChild(\&role\&).gameObject\n\troleImage = role:GetComponent(\&Image\&)\n\t--获取素材\n\tlocal res = go.transform:FindChild(\&res\&).gameObject\n\troleRes[\&DOWN\&][1] = res.transform:FindChild(\&role (0)\&).gameObject:GetComponent(\&Image\&).sprite\n\troleRes[\&DOWN\&][2] = res.transform:FindChild(\&role (1)\&).gameObject:GetComponent(\&Image\&).sprite\n\troleRes[\&DOWN\&][3] = res.transform:FindChild(\&role (2)\&).gameObject:GetComponent(\&Image\&).sprite\n\troleRes[\&LEFT\&][1] = res.transform:FindChild(\&role (3)\&).gameObject:GetComponent(\&Image\&).sprite\n\troleRes[\&LEFT\&][2] = res.transform:FindChild(\&role (4)\&).gameObject:GetComponent(\&Image\&).sprite\n\troleRes[\&LEFT\&][3] = res.transform:FindChild(\&role (5)\&).gameObject:GetComponent(\&Image\&).sprite\n\troleRes[\&RIGHT\&][1] = res.transform:FindChild(\&role (6)\&).gameObject:GetComponent(\&Image\&).sprite\n\troleRes[\&RIGHT\&][2] = res.transform:FindChild(\&role (7)\&).gameObject:GetComponent(\&Image\&).sprite\n\troleRes[\&RIGHT\&][3] = res.transform:FindChild(\&role (8)\&).gameObject:GetComponent(\&Image\&).sprite\n\troleRes[\&UP\&][1] = res.transform:FindChild(\&role (9)\&).gameObject:GetComponent(\&Image\&).sprite\n\troleRes[\&UP\&][2] = res.transform:FindChild(\&role (10)\&).gameObject:GetComponent(\&Image\&).sprite\n\troleRes[\&UP\&][3] = res.transform:FindChild(\&role (11)\&).gameObject:GetComponent(\&Image\&).sprite\n\t--UpdateBeat\n\tUpdateBeat:Add(Update, self)\nend\u003C\u002Fcode\u003E\u003Cp\u003E编写Update方法,它根据用户输入改变坐标(具体参见第三篇),并且根据不同的移动方向设置角色图片素材,将roleImage.sprite替换成roleRes[方向][动画索引]。最后判断“if Time.time - lastAnmTime & 0.1 then”,每隔0.1秒切换一次动画。\u003C\u002Fp\u003E\u003Ccode lang=\&text\&\u003E--每帧执行\nfunction Update()\n\t\n\t--移动\n\tlocal Input = UnityEngine.I\n\tlocal horizontal = Input.GetAxis(\&Horizontal\&);\n\tlocal verticla = Input.GetAxis(\&Vertical\&);\n\t\n\tlocal x = role.transform.position.x + horizontal\n\tlocal y = role.transform.position.y + verticla\n\trole.transform.position = Vector3.New(x,y,0)\n\t--转向\n\tif horizontal & 0 then\n\t\troleImage.sprite = roleRes[\&LEFT\&][roleAnm]\n\telseif horizontal & 0 then\n\t\troleImage.sprite = roleRes[\&RIGHT\&][roleAnm]\n\telseif verticla & 0 then\n\t\troleImage.sprite = roleRes[\&UP\&][roleAnm]\n\telseif verticla & 0 then\n\t\troleImage.sprite = roleRes[\&DOWN\&][roleAnm]\n\tend\n\t--步伐(动画索引)\n\tif Time.time - lastAnmTime & 0.1 then\n\t\troleAnm = roleAnm+1\n\t\tif roleAnm & 3 then roleAnm = 1 end\n\t\tlastAnmTime = Time.time\n\tend\n\t\nend\u003C\u002Fcode\u003E\u003Cp\u003E运行游戏,玩家可以通过键盘的方向键控制角色移动。\u003C\u002Fp\u003E\u003Cimg src=\&v2-59f762a794afcfcb6130e0.png\& data-rawwidth=\&593\& data-rawheight=\&337\&\u003E\u003Ch2\u003E3、编写射击代码\u003C\u002Fh2\u003E\u003Cp\u003E在main.lua中添加炮弹相关的变量,如下所示。其中bullet代表炮弹元件(panel.map.bullet),lastShootTime 代表上一次发射炮弹的时间,bulletSpeedX代表炮弹的水平移动速度,bulletSpeedY代表炮弹的垂直移动速度,roleFace代表角色的面向。然后在OnLoadFinish中给bullet赋值。\u003C\u002Fp\u003E\u003Ccode lang=\&text\&\u003Elocal bullet\nlocal lastShootTime = -100\nlocal bulletSpeedX = 0\nlocal bulletSpeedY = 0\nlocal roleFace = 0\n\nfunction OnLoadFinish(objs)\n\t……\n\t--子弹元素\n\tbullet = map.transform:FindChild(\&bullet\&).gameObject\nEnd\u003C\u002Fcode\u003E\u003Cp\u003E在Update中给roleFace赋值。\u003C\u002Fp\u003E\u003Ccode lang=\&text\&\u003E--每帧执行\nfunction Update()\n\t\n\t--移动\n\t……\n\t--转向\n\tif horizontal & 0 then\n\t\troleImage.sprite = roleRes[\&LEFT\&][roleAnm]\n\t\troleFace = 1\n\telseif horizontal & 0 then\n\t\troleImage.sprite = roleRes[\&RIGHT\&][roleAnm]\n\t\troleFace = 2\n\telseif verticla & 0 then\n\t\troleImage.sprite = roleRes[\&UP\&][roleAnm]\n\t\troleFace = 3\n\telseif verticla & 0 then\n\t\troleImage.sprite = roleRes[\&DOWN\&][roleAnm]\n\t\troleFace = 4\n\tend\n\t--步伐\n\t……\nend\u003C\u002Fcode\u003E\u003Cp\u003E在Update中添加处理炮弹的代码,它处理如下几件事情。\u003C\u002Fp\u003E\u003Cp\u003E1、炮弹在飞行1.2秒后,燃尽消失;\u003C\u002Fp\u003E\u003Cp\u003E2、当玩家按下鼠标左键时,发射炮弹,根据角色面向,bulletSpeedX和bulletSpeedY会有不同的值。\u003C\u002Fp\u003E\u003Cp\u003E3、根据bulletSpeedX和bulletSpeedY移动炮弹。\u003C\u002Fp\u003E\u003Ccode lang=\&text\&\u003E--每帧执行\nfunction Update()\n\t……\n\t--子弹\n\tif Time.time - lastShootTime & 1.2 then\n\t\t--消失\n\t\tif bullet.transform.position.x ~= -999 then\n\t\t\tbullet.transform.position = Vector3.New(-999,-999,0)\n\t\tend\n\t\t--发射\n\t\tif Input.GetMouseButton(0) then\n\t\t\tbullet.transform.position = Vector3.New(x,y,0)\n\t\t\tif roleFace == 1 then\n\t\t\t\tbulletSpeedX = -10\n\t\t\t\tbulletSpeedY = 0\n\t\t\telseif roleFace == 2
then\n\t\t\t\tbulletSpeedX = 10\n\t\t\t\tbulletSpeedY = 0\n\t\t\telseif roleFace == 3 then\n\t\t\t\tbulletSpeedX = 0\n\t\t\t\tbulletSpeedY = 10\n\t\t\telseif roleFace == 4
then\n\t\t\t\tbulletSpeedX = 0\n\t\t\t\tbulletSpeedY = -10\n\t\t\tend\n\t\t\tlastShootTime = Time.time\n\t\tend\n\telse\n\t\t--运动\n\t\tlocal x = bullet.transform.position.x + bulletSpeedX\n\t\tlocal y = bullet.transform.position.y + bulletSpeedY\n\t\tbullet.transform.position = Vector3.New(x,y,0)\n\tend\nend\u003C\u002Fcode\u003E\u003Cp\u003E运行游戏,点击鼠标左键,角色发射炮弹。另外也可以用基于组件的方法实现,这里就不展开了。\u003C\u002Fp\u003E\u003Cimg src=\&v2-2a28e210b4e23f2998ac6.png\& data-rawwidth=\&598\& data-rawheight=\&337\&\u003E\u003Cp\u003E最后依然到了广告时间:笔者即将出版的一本Unity3D实战类书籍《Unity3D网络游戏实战》。该书通过一个完整的多人坦克对战实例,详细介绍网络游戏开发过程中涉及到的知识和技巧。书中还介绍了服务端框架、客户端网络模块、UI系统的架构等内容。相信透过本书,读者能够掌握Unity3D网络游戏开发的大部分知识,也能够从框架设计中了解商业游戏的设计思路,感谢大家支持。\u003C\u002Fp\u003E\u003Cimg src=\&v2-9e629e8fa3c93fe1f563be632d3a1ff2.png\& data-rawwidth=\&692\& data-rawheight=\&692\&\u003E&,&updated&:new Date(&T14:46:58.000Z&),&canComment&:false,&commentPermission&:&anyone&,&commentCount&:2,&likeCount&:3,&state&:&published&,&isLiked&:false,&slug&:&&,&isTitleImageFullScreen&:false,&rating&:&none&,&sourceUrl&:&&,&publishedTime&:&T22:46:58+08:00&,&links&:{&comments&:&\u002Fapi\u002Fposts\u002F2Fcomments&},&url&:&\u002Fp\u002F&,&titleImage&:&&,&summary&:&&,&href&:&\u002Fapi\u002Fposts\u002F&,&meta&:{&previous&:null,&next&:null},&snapshotUrl&:&&,&commentsCount&:2,&likesCount&:3},&&:{&title&:&Unity特效(1)
梦幻旋屏&,&author&:&pyluo&,&content&:&\u003Cp\u003E游戏开发中,往往会用到一些屏幕特效。下图展现的是一种“旋屏”效果,它会旋转屏幕图像,且距离中心点越远的点旋转角度越大。这种效果特别适合营造“梦幻”感,比如,在RPG游戏中,经过一段“旋屏”特效,主角穿越到了10年前。\u003C\u002Fp\u003E\u003Cimg src=\&v2-c55abe1938a8.png\& data-rawwidth=\&748\& data-rawheight=\&571\&\u003E\u003Cbr\u003E\u003Ch2\u003E\u003Cb\u003E1、编写Shader\u003C\u002Fb\u003E\u003C\u002Fh2\u003E\u003Cp\u003E下面的着色器代码使用了顶点\u002F片元着色器处理旋屏特效的功能。这里定义3个属性,其中_MainTex代表屏幕贴图,_Rot 代表基准的旋转角度。核心代码在片元着色器frag中实现。\u003C\u002Fp\u003E\u003Cp\u003E如下图所示,屏幕图像被归一到[0,1]的空间中,中心点为(0.5,0.5)。假设某个点的uv坐标为(x,y),经过一系列处理,它的坐标变为(x1,y1),而(x1,y1)便是实现旋转效果后的uv坐标。\u003C\u002Fp\u003E\u003Cimg src=\&v2-c874b5045afd.png\& data-rawwidth=\&678\& data-rawheight=\&639\&\u003E\u003Cp\u003E由“float distance = sqrt((i.uv.x - 0.5)*(i.uv.x - 0.5) +(i.uv.y - 0.5)*(i.uv.y - 0.5));”可以计算点到屏幕中心的距离distance。由于距离越远旋转角度越大,使用“_Rot *=distance”将角度增量基准与距离联系起来,即可获取需要旋转的角度:angle = _Rot*distance + A。\u003C\u002Fp\u003E\u003Cp\u003E由反正切公式可得∠A = atan((y - 0.5)\u002F(x - 0.5)),由于atan的取值为[-π\u002F2,π\u002F2],还需根据y值确定∠A所在的象限,故而∠A = step(x,0.5)*PI+ atan((y - 0.5)\u002F(x - 0.5)) 。计算∠A 后,便可由angle = _Rot*distance + A计算总的旋转角度。\u003C\u002Fp\u003E\u003Cp\u003E前面已经计算了点到屏幕中心的距离distance,故而:\u003C\u002Fp\u003E\u003Cp\u003Ex1 = 0.5 + distance *cos(angle)\u003C\u002Fp\u003E\u003Cp\u003Ey1 = 0.5 + distance *sin(angle)\u003C\u002Fp\u003E\u003Cp\u003E\u003Cb\u003EShader代码如下所示:\u003C\u002Fb\u003E\u003C\u002Fp\u003E\u003Ccode lang=\&text\&\u003EShader \&Lpy\u002FScreenRot\&\n{\n
Properties\n
_MainTex (\&Main Tex\&, 2D) = \&white\& {}\n
_Rot (\&Rotation\&, float) = 0\n
SubShader\n
Tags {\&Queue\&=\&Geometry\&}\n
Tags { \&LightMode\&=\&ForwardBase\& }\n
ZWrite Off\n\n
CGPROGRAM\n
#pragma vertex vert
#pragma fragment frag\n
#include \&UnityCG.cginc\&\n
#define PI 3.79
sampler2D _MainT\n
float _R\n
struct a2v\n
float4 vertex : POSITION;\n
float3 texcoord : TEXCOORD0;\n
struct v2f\n
float4 pos : SV_POSITION;\n
float2 uv : TEXCOORD0;\n
v2f vert (a2v v)\n
o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
o.uv = v.\n
fixed4 frag (v2f i) : SV_Target\n
\u002F\u002F与中心点(0.5,0.5)的距离\n
float distance = sqrt((i.uv.x - 0.5)*(i.uv.x - 0.5) +(i.uv.y - 0.5)*(i.uv.y - 0.5));\n
\u002F\u002F距离越大,旋转角度越大\n
\u002F\u002F计算旋转角度\n
float angle = step(i.uv.x,0.5)*PI+ atan((i.uv.y - 0.5)\u002F(i.uv.x - 0.5)) + _R\n
\u002F\u002F计算坐标\n
i.uv.x = 0.5 +
distance *cos(angle);\n
i.uv.y = 0.5 +
distance *sin(angle);\n \n
fixed4 c = tex2D(_MainTex, i.uv);\n
FallBack \&Specular\&\n}\u003C\u002Fcode\u003E\u003Cbr\u003E\u003Ch2\u003E\u003Cb\u003E2、使用材质\u003C\u002Fb\u003E\u003C\u002Fh2\u003E\u003Cp\u003E新建c#文件,编写ScreenRot类,它由一个共有变量mtl,在它的OnRenderImage方法中调用Graphics.Blit将屏幕图像(对应shader中的_MainTex)与材质混合起来。\u003C\u002Fp\u003E\u003Ccode lang=\&text\&\u003Eusing UnityE\nusing System.C\n \npublic class ScreenRot : MonoBehaviour \n{\n
public M\n \n
void OnRenderImage(RenderTexture src, RenderTexture dest)\n
Graphics.Blit (src, dest,mtl);\n
}\n}\u003C\u002Fcode\u003E\u003Cp\u003E然后给新建一个名为ScreenRot的材质,使用上述编写的Shader。然后给摄像机添加ScreenRot组件,设置刚刚创建的材质,如下图所示。\u003C\u002Fp\u003E\u003Cimg src=\&v2-8fbdcaad79fc3de9cdec.png\& data-rawwidth=\&383\& data-rawheight=\&339\&\u003E\u003Cp\u003E运行游戏,调整材质的“Rotation”属性,即可看到旋转特效。\u003C\u002Fp\u003E\u003Cimg src=\&v2-48ec859e357a2d46ef253a36ed7849df.png\& data-rawwidth=\&692\& data-rawheight=\&340\&\u003E\u003Ch2\u003E\u003Cb\u003E3、代码中引用\u003C\u002Fb\u003E\u003C\u002Fh2\u003E\u003Cp\u003EShader中并没有涉及时间的控制,旋转速度需要由c#代码控制,将ScreenRot修改成下面的代码,即可让屏幕自动旋转。\u003C\u002Fp\u003E\u003Ccode lang=\&text\&\u003Eusing UnityE\nusing System.C\n \npublic class ScreenRot : MonoBehaviour \n{\n
public M\n \n\n
\u002F\u002F Update is called once per frame\n
void Update ()\n
rot += 0.1f;\n
void OnRenderImage(RenderTexture src, RenderTexture dest)\n
if (rot == 0.0)\\n
mtl.SetFloat(\&_Rot\&, rot);\n
Graphics.Blit (src, dest,mtl);\n
}\n}\u003C\u002Fcode\u003E\u003Cp\u003E这个效果能够运用在很多场合,比如使用“正向旋转→切换场景→反向旋转”实现切屏特效。\u003C\u002Fp\u003E\u003Cbr\u003E\u003Cp\u003E最后依然到了广告时间:笔者出版了一本Unity3D实战类书籍《Unity3D网络游戏实战》。该书通过一个完整的多人坦克对战实例,详细介绍网络游戏开发过程中涉及到的知识和技巧。书中还介绍了服务端框架、客户端网络模块、UI系统的架构等内容。相信透过本书,读者能够掌握Unity3D网络游戏开发的大部分知识,也能够从框架设计中了解商业游戏的设计思路,感谢大家支持。\u003C\u002Fp\u003E\u003Cimg src=\&v2-9e629e8fa3c93fe1f563be632d3a1ff2.png\& data-rawwidth=\&692\& data-rawheight=\&692\&\u003E\u003Cp\u003EUnity3D热更新框架教程:\u003Ca href=\&https:\u002F\u002Fzhuanlan.zhihu.com\u002Fp\u002F\& data-editable=\&true\& data-title=\&https:\u002F\u002Fzhuanlan.zhihu.com\u002Fp\u002F?refer=pyluo\& class=\&\&\u003Ehttps:\u002F\u002Fzhuanlan.zhihu.com\u002Fp\u002F3C\u002Fa\u003E\u003C\u002Fp\u003E&,&updated&:new Date(&T12:56:18.000Z&),&canComment&:false,&commentPermission&:&anyone&,&commentCount&:24,&likeCount&:63,&state&:&published&,&isLiked&:false,&slug&:&&,&isTitleImageFullScreen&:false,&rating&:&none&,&sourceUrl&:&&,&publishedTime&:&T20:56:18+08:00&,&links&:{&comments&:&\u002Fapi\u002Fposts\u002F2Fcomments&},&url&:&\u002Fp\u002F&,&titleImage&:&https:\u002F\u002Fpic1.zhimg.com\u002Fv2-48ec859e357a2d46ef253a36ed7849df_r.jpg&,&summary&:&&,&href&:&\u002Fapi\u002Fposts\u002F&,&meta&:{&previous&:null,&next&:null},&snapshotUrl&:&&,&commentsCount&:24,&likesCount&:63},&&:{&title&:&Unity特效(2) 图片切割&,&author&:&pyluo&,&content&:&\u003Cp\u003E游戏开发中,常常把多张图片素材合并成图集,然后程序读取所需的部分显示。如下展示的是一张人物行走图,程序需要把它切分成12张小图加以显示。一种做法是使用Sprite Editor切分图集,当做多张小图来处理。如果Image能够只显示图集的一部分,程序还是把图集当做1张图片处理,可以减少不小工作量。本文提供一种使用shader实现上述功能的例子。\u003C\u002Fp\u003E\u003Cimg src=\&v2-833faedb6e4cdb54a189f.png\& data-rawwidth=\&692\& data-rawheight=\&388\&\u003E\u003Cbr\u003E\u003Ch2\u003E1、编写Shader\u003C\u002Fh2\u003E\u003Cp\u003E下面的着色器代码使用了顶点\u002F片元着色器处理图片切割功能。这里定义5个属性,其中_MainTex代表图片贴图,_ColCount和_RowCount代表图片的列数和行数,_ColIndex和_RowIndex表示要显示哪一行哪一列的图片。核心代码是“o.uv.x = (_ColIndex + v.texcoord.x)\u002F_ColCount”和“o.uv.y = (_RowIndex + v.texcoord.y)\u002F_RowCount”,它们实现了UV坐标的变换。“o.uv.x = (_ColIndex + v.texcoord.x)\u002F_ColCount”即是“o.uv.x = _ColIndex*(1\u002F_ColCount) + v.texcoord.x *(1\u002F_ColCount)”的化简式,由于纹理坐标被归一化到[0,1]的范围,1\u002F_ColCount即表示每一张小图的宽度。\u003C\u002Fp\u003E\u003Ccode lang=\&text\&\u003EShader \&Lpy\u002FImageClip\& \n{\n\tProperties \n\t{\n\t\t_MainTex (\&Main Tex\&, 2D) = \&white\& {}\n
\t_ColCount (\&Column Count\&, int) = 4\n
\t_RowCount (\&Row Count\&, int) = 4\n
\t_ColIndex (\&Col Index\&, int) = 0\n
\t_RowIndex (\&Row Index\&, int) = 0\n\t}\n\t\n\tSubShader \n\t{\n\t\tTags {\&Queue\&=\&Transparent\& \&IgnoreProjector\&=\&True\& \&RenderType\&=\&Transparent\&}\n\t\t\n\t\tPass \n\t\t{\n\t\t\tTags { \&LightMode\&=\&ForwardBase\& }\n\t\t\tZTest off\n\t\t\tZWrite Off\n\t\t\tBlend SrcAlpha OneMinusSrcAlpha\n\t\t\t\n\t\t\tCGPROGRAM\n\t\t\t#pragma vertex vert
\n\t\t\t#pragma fragment frag\n\t\t\t#include \&UnityCG.cginc\&\n\t\t\n\t\t\tsampler2D _MainT\n\t\t\tint _ColC\n\t\t\tint _RowC\n\t\t\tint _ColI\n\t\t\tint _RowI\n\t\t\t
\n\t\t\tstruct a2v \n\t\t\t{
float4 vertex : POSITION; \n\t\t\t
float2 texcoord : TEXCOORD0;\n\t\t\t};
\n\t\t\t\n\t\t\tstruct v2f \n\t\t\t{
float4 pos : SV_POSITION;\n\t\t\t
float2 uv : TEXCOORD0;\n\t\t\t};
\n\t\t\t\n\t\t\tv2f vert (a2v v) \n\t\t\t{
\n\t\t\t\tv2
\n\t\t\t\to.pos = mul(UNITY_MATRIX_MVP, v.vertex);
\n\t\t\t\t\n\t\t\t\to.uv.x = (_ColIndex + v.texcoord.x)\u002F_ColC\n\t\t\t\to.uv.y = (_RowIndex + v.texcoord.y)\u002F_RowC\n\t\t\t\\n\t\t\t}
\n\t\t\t\n\t\t\tfixed4 frag (v2f i) : SV_Target \n\t\t\t{\n\t\t\t\tfixed4 c = tex2D(_MainTex, i.uv);\n\t\t\t\\n\t\t\t}\n\t\t\tENDCG\n\t\t}
\n\t}\n\tFallBack \&Transparent\u002FVertexLit\&\n}\u003C\u002Fcode\u003E\u003Cbr\u003E\u003Cbr\u003E\u003Ch2\u003E2、使用材质\u003C\u002Fh2\u003E\u003Cp\u003E新建一个名为ImageClip的材质,选择上述编写的shader。将ColumnCount和RowCount设置为图集的列数和行数,如下图所示。\u003C\u002Fp\u003E\u003Cimg src=\&v2-ae98f27d3c4ecf3344d90a.png\& data-rawwidth=\&400\& data-rawheight=\&254\&\u003E\u003Cbr\u003E\u003Cp\u003E将刚创建的材质应用于图片上,如下图所示。\u003C\u002Fp\u003E\u003Cimg src=\&v2-c11ba699f4e20889fae575c242f0ee74.png\& data-rawwidth=\&383\& data-rawheight=\&193\&\u003E\u003Cp\u003E在Scene或Game视图中观察图片,改变材质的ColIndex和RowIndex属性,即可显示不同的小图。如下图所示。\u003C\u002Fp\u003E\u003Cimg src=\&v2-84c9c825d1ca32dc9c4d4cfece0f4432.png\& data-rawwidth=\&390\& data-rawheight=\&267\&\u003E\u003Cbr\u003E\u003Ch2\u003E3、代码控制\u003C\u002Fh2\u003E\u003Cp\u003E如下代码展示使用脚本控制材质属性的方法,当按下空格键时,改变材质的RowIndex属性,展现不同小图。\u003C\u002Fp\u003E\u003Ccode lang=\&text\&\u003Eusing UnityE\nusing System.C\nusing UnityEngine.UI;\n\npublic class RoleCtrl : MonoBehaviour \n{\n\tpublic I\n\tprivate M\n\t\u002F\u002F Use this for initialization\n\tvoid Start () \n\t{\n\t\tmtl = image.\n\t}\n\t\n\t\u002F\u002F Update is called once per frame\n\tvoid Update () \n\t{\n\t\tif (Input.GetKeyDown (KeyCode.Space)) \n\t\t{\n\t\t\tint row = mtl.GetInt(\&_RowIndex\&);\n\n\t\t\trow++;\n\t\t\tif(row &= 4) \n\t\t\t\trow = 0;\n\n\t\t\tmtl.SetInt(\&_RowIndex\&, row);\n\t\t}\n\t}\n}\n\u003C\u002Fcode\u003E\u003Cbr\u003E\u003Cp\u003E最后依然到了广告时间:笔者即将出版的一本Unity3D实战类书籍《Unity3D网络游戏实战》。该书通过一个完整的多人坦克对战实例,详细介绍网络游戏开发过程中涉及到的知识和技巧。书中还介绍了服务端框架、客户端网络模块、UI系统的架构等内容。相信透过本书,读者能够掌握Unity3D网络游戏开发的大部分知识,也能够从框架设计中了解商业游戏的设计思路,感谢大家支持。\u003C\u002Fp\u003E\u003Cimg src=\&v2-9e629e8fa3c93fe1f563be632d3a1ff2.png\& data-rawwidth=\&692\& data-rawheight=\&692\&\u003E&,&updated&:new Date(&T14:14:02.000Z&),&canComment&:false,&commentPermission&:&anyone&,&commentCount&:2,&likeCount&:2,&state&:&published&,&isLiked&:false,&slug&:&&,&isTitleImageFullScreen&:false,&rating&:&none&,&sourceUrl&:&&,&publishedTime&:&T22:14:02+08:00&,&links&:{&comments&:&\u002Fapi\u002Fposts\u002F2Fcomments&},&url&:&\u002Fp\u002F&,&titleImage&:&&,&summary&:&&,&href&:&\u002Fapi\u002Fposts\u002F&,&meta&:{&previous&:null,&next&:null},&snapshotUrl&:&&,&commentsCount&:2,&likesCount&:2},&&:{&title&:&Unity特效(3) 图片翻转&,&author&:&pyluo&,&content&:&\u003Cp\u003E2D游戏开发中,往往会使用翻转的图片(如下图),然而Transform的旋转并不能完成这一功能,那么什么办法将图片翻转呢?\u003Cbr\u003E\u003C\u002Fp\u003E\u003Cimg src=\&v2-f5ab4e30fe05aeb15bfdab172d2d5f09.png\& data-rawwidth=\&502\& data-rawheight=\&614\&\u003E\u003Ch2\u003E1、编写Shader\u003C\u002Fh2\u003E\u003Cp\u003E下面的着色器代码使用了顶点\u002F片元着色器处理图片翻转功能。这里定义3个属性,其中_MainTex代表图片贴图,_Hor代表是否启用水平翻转,_Ver代表是否启用垂直翻转。核心代码是“o.uv.x = (1-v.texcoord.x)*_Hor + v.texcoord.x*(1-_Hor)”和“o.uv.y = (1-v.texcoord.y)*_Ver + v.texcoord.y*(1-_Ver);”它们实现了UV坐标的变换。在o.uv.x的计算式中,如果_Hor为0,那么“o.uv.x =
v.texcoord.x”即为原始UV,如果_Hor为1,由于纹理坐标被归一化到[0,1]的范围,那么“o.uv.x = 1-v.texcoord.x”即为翻转后的UV。\u003C\u002Fp\u003E\u003Ccode lang=\&text\&\u003EShader \&Lpy\u002FImageFlip\& \n{\n\tProperties \n\t{\n\t\t_MainTex (\&Main Tex\&, 2D) = \&white\& {}\n\t\t\n
\t_Hor (\&Is Horizontal Filp\&, Range (0, 1)) = 0\n
\t_Ver (\&Is Vertical Filp\&, Range (0, 1)) = 0\n\t}\n\t\n\tSubShader \n\t{\n\t\tTags {\&Queue\&=\&Transparent\& \&IgnoreProjector\&=\&True\& \&RenderType\&=\&Transparent\&}\n\t\t\n\t\tPass \n\t\t{\n\t\t\tTags { \&LightMode\&=\&ForwardBase\& }\n\t\t\tZTest off\n\t\t\tZWrite Off\n\t\t\tBlend SrcAlpha OneMinusSrcAlpha\n\t\t\t\n\t\t\tCGPROGRAM\n\t\t\t#pragma vertex vert
\n\t\t\t#pragma fragment frag\n\t\t\t#include \&UnityCG.cginc\&\n\t\t\n\t\t\tsampler2D _MainT\n\t\t\tint _H\n\t\t\tint _V\n\t\t\t
\n\t\t\tstruct a2v \n\t\t\t{
float4 vertex : POSITION; \n\t\t\t
float2 texcoord : TEXCOORD0;\n\t\t\t};
\n\t\t\t\n\t\t\tstruct v2f \n\t\t\t{
float4 pos : SV_POSITION;\n\t\t\t
float2 uv : TEXCOORD0;\n\t\t\t};
\n\t\t\t\n\t\t\tv2f vert (a2v v) \n\t\t\t{
\n\t\t\t\tv2
\n\t\t\t\to.pos = mul(UNITY_MATRIX_MVP, v.vertex);
\n\t\t\t\t\n\t\t\t\to.uv.x = (1-v.texcoord.x)*_Hor + v.texcoord.x*(1-_Hor);\n\t\t\t\to.uv.y = (1-v.texcoord.y)*_Ver + v.texcoord.y*(1-_Ver);\n\t\t\t\\n\t\t\t}
\n\t\t\t\n\t\t\tfixed4 frag (v2f i) : SV_Target \n\t\t\t{\n\t\t\t\tfixed4 c = tex2D(_MainTex, i.uv);\n\t\t\t\\n\t\t\t}\n\t\t\tENDCG\n\t\t}
\n\t}\n\tFallBack \&Transparent\u002FVertexLit\&\n}\u003C\u002Fcode\u003E\u003Cbr\u003E\u003Ch2\u003E2、使用材质\u003C\u002Fh2\u003E\u003Cp\u003E新建一个名为ImageFilp的材质,选择上述编写的shader,设置Is Horizontal Filp和Is Vertical Filp,如下图所示。\u003C\u002Fp\u003E\u003Cimg src=\&v2-c1eab9ec5c.png\& data-rawwidth=\&345\& data-rawheight=\&253\&\u003E\u003Cp\u003E将刚创建的材质应用于图片上,即可看到翻转的效果。如下图所示。\u003C\u002Fp\u003E\u003Cimg src=\&v2-babdd5f36c77.png\& data-rawwidth=\&692\& data-rawheight=\&335\&\u003E\u003Cp\u003E最后依然到了广告时间:笔者出版的一本Unity3D实战类书籍《Unity3D网络游戏实战》。该书通过一个完整的多人坦克对战实例,详细介绍网络游戏开发过程中涉及到的知识和技巧。书中还介绍了服务端框架、客户端网络模块、UI系统的架构等内容。相信透过本书,读者能够掌握Unity3D网络游戏开发的大部分知识,也能够从框架设计中了解商业游戏的设计思路,感谢大家支持。\u003C\u002Fp\u003E\u003Cimg src=\&v2-9e629e8fa3c93fe1f563be632d3a1ff2.png\& data-rawwidth=\&692\& data-rawheight=\&692\&\u003E&,&updated&:new Date(&T12:53:35.000Z&),&canComment&:false,&commentPermission&:&anyone&,&commentCount&:12,&likeCount&:11,&state&:&published&,&isLiked&:false,&slug&:&&,&isTitleImageFullScreen&:false,&rating&:&none&,&sourceUrl&:&&,&publishedTime&:&T20:53:35+08:00&,&links&:{&comments&:&\u002Fapi\u002Fposts\u002F2Fcomments&},&url&:&\u002Fp\u002F&,&titleImage&:&https:\u002F\u002Fpic3.zhimg.com\u002Fv2-f5ab4e30fe05aeb15bfdab172d2d5f09_r.jpg&,&summary&:&&,&href&:&\u002Fapi\u002Fposts\u002F&,&meta&:{&previous&:null,&next&:null},&snapshotUrl&:&&,&commentsCount&:12,&likesCount&:11},&&:{&title&:&Unity特效(4) 标题光效&,&author&:&pyluo&,&content&:&\u003Cp\u003E标题光效是一种常见的图片特效,“遮罩层”从左往右经过,起到强调游戏标题的作用,如下图所示。那么怎样用Shader实现这种效果呢?\u003Cbr\u003E\u003C\u002Fp\u003E\u003Cimg src=\&v2-cdbdff03fa.png\& data-rawwidth=\&660\& data-rawheight=\&493\&\u003E\u003Ch2\u003E1、编写Shader\u003C\u002Fh2\u003E\u003Cp\u003E
下面的着色器代码使用了顶点\u002F片元着色器处理标题光效功能。这里定义4个属性,其中_MainTex代表图片贴图,_MaskColor代表遮罩颜色,Speed代表光效的移动速度,_MaskLimit控制着光效的宽度。核心代码为“float isMask = sin(_Time.y*_Speed
-i.uv.x*2*PI );”“isMask = step(_MaskLimit,isMask);”“c.rgb += _MaskColor*isM”这3句。如果isMask为1,代表该片元被遮罩,如果为0,表示不被遮罩,通过“c.rgb += _MaskColor*isM”便可计算片元的颜色。“float isMask = sin(_Time.y*_Speed -i.uv.x*2*PI );”将根据时间和uv的x坐标计算isMask,此时isMask的取值范围为[-1,1]。step(_MaskLimit,isMask)的功能相当于“if(isMask & MaskLimit) return 1; else return 0;”通过_MaskLimit将指定区间的值设为1,其他设为0。\u003C\u002Fp\u003E\u003Ccode lang=\&text\&\u003EShader \&Lpy\u002FImageEffect\& \n{\n\tProperties \n\t{\n\t\t_MainTex (\&Main Tex\&, 2D) = \&white\& {}\n\t\t_MaskColor (\&Mask Color\&, Color) = (1, 1, 1, 1)\n\t\t\n\t\t_Speed (\&Speed\&, float) = 2\n\t\t_MaskLimit (\&MaskLimit\&, float) = 0.8\n\t}\n\t\n\tSubShader \n\t{\n\t\tTags {\&Queue\&=\&Transparent\& \&IgnoreProjector\&=\&True\& \&RenderType\&=\&Transparent\&}\n\t\t\n\t\tPass \n\t\t{\n\t\t\tTags { \&LightMode\&=\&ForwardBase\& }\n\t\t\tZTest off\n\t\t\tZWrite Off\n\t\t\tBlend SrcAlpha OneMinusSrcAlpha\n\t\t\t\n\t\t\tCGPROGRAM\n\t\t\t#pragma vertex vert
\n\t\t\t#pragma fragment frag\n\t\t\t#include \&UnityCG.cginc\&\n\t\t\t#define PI 3.79
\n\t\t\t\n\t\t\t\n\t\t\tsampler2D _MainT\n\t\t\tfixed3 _MaskC\n\t\t\tfloat _S\n\t\t\tfloat _MaskL\n\t\t\t\n\t\t\tstruct a2v \n\t\t\t{
float4 vertex : POSITION; \n\t\t\t
float3 texcoord : TEXCOORD0;\n\t\t\t};
\n\t\t\t\n\t\t\tstruct v2f \n\t\t\t{
float4 pos : SV_POSITION;\n\t\t\t
float2 uv : TEXCOORD0;\n\t\t\t};
\n\t\t\t\n\t\t\tv2f vert (a2v v) \n\t\t\t{
\n\t\t\t\tv2
\n\t\t\t\to.pos = mul(UNITY_MATRIX_MVP, v.vertex);
\n\t\t\t\to.uv = v.\n\t\t\t\\n\t\t\t}
\n\t\t\t\n\t\t\tfixed4 frag (v2f i) : SV_Target \n\t\t\t{\n\t\t\t\tfixed4 c = tex2D(_MainTex, i.uv);\n\t\t\t\t\n\t\t\t\tfloat isMask = sin(_Time.y*_Speed
-i.uv.x*2*PI );\n\t\t\t\tisMask = step(_MaskLimit,isMask);\n\t\t\t\t\n\t\t\t\tc.rgb += _MaskColor*isM\n\t\t\t\\n\t\t\t}\n\t\t\tENDCG\n\t\t}
\n\t}\n\tFallBack \&Transparent\u002FVertexLit\&\n}\u003C\u002Fcode\u003E\u003Cbr\u003E\u003Ch2\u003E2、使用材质\u003C\u002Fh2\u003E\u003Cp\u003E新建一个名为ImageEffect的材质,选择上述编写的shader。设置MaskColor、Speed、MaskLimit这3个参数,如下图所示。\u003C\u002Fp\u003E\u003Cimg src=\&v2-96d6cd5b76b1c3e5494be6.png\& data-rawwidth=\&350\& data-rawheight=\&267\&\u003E\u003Cbr\u003E\u003Cp\u003E将刚创建的材质应用于图片上,即可看到效果。如下图所示。\u003C\u002Fp\u003E\u003Cimg src=\&v2-6ca4456ae5.png\& data-rawwidth=\&693\& data-rawheight=\&317\&\u003E\u003Cbr\u003E\u003Cbr\u003E\u003Cp\u003E最后依然到了广告时间:最后依然到了广告时间:\u003C\u002Fp\u003E\u003Cp\u003E笔者在分享文章的同时也结识了一群兴趣相投的朋友,本周五将会作客游戏蛮牛,在线答疑。\u003C\u002Fp\u003E\u003Cp\u003E\u003Ca href=\&http:\u002F\u002Fwww.manew.com\u002Fthread--1.html\& data-editable=\&true\& data-title=\&【2.24 某知名游戏公司主程在线答疑 参与有机会得《Unity 3D网络游戏实战》】\& class=\&\&\u003E【2.24 某知名游戏公司主程在线答疑 参与有机会得《Unity 3D网络游戏实战》】\u003C\u002Fa\u003E\u003C\u002Fp\u003E&,&updated&:new Date(&T12:40:39.000Z&),&canComment&:false,&commentPermission&:&anyone&,&commentCount&:0,&likeCount&:1,&state&:&published&,&isLiked&:false,&slug&:&&,&isTitleImageFullScreen&:false,&rating&:&none&,&sourceUrl&:&&,&publishedTime&:&T20:40:39+08:00&,&links&:{&comments&:&\u002Fapi\u002Fposts\u002F2Fcomments&},&url&:&\u002Fp\u002F&,&titleImage&:&https:\u002F\u002Fpic4.zhimg.com\u002Fv2-cdbdff03fa_r.jpg&,&summary&:&&,&href&:&\u002Fapi\u002Fposts\u002F&,&meta&:{&previous&:null,&next&:null},&snapshotUrl&:&&,&commentsCount&:0,&likesCount&:1},&&:{&title&:&Unity特效(5) 滚动的背景&,&author&:&pyluo&,&content&:&\u003Cp\u003E制作动画时,往往会使用到“滚动的背景”。如下图所示,一开始图片只显示素材的一部分,然后素材不断滚动。该效果可以模拟横版或飞行游戏的背景图,或实现一些动画效果。尽管有很多方法实现该功能,这里提供一种基于shader的方法。\u003Cbr\u003E\u003C\u002Fp\u003E\u003Cimg src=\&v2-d9e7d6d51fa27f75b0e48436dee51b06.png\& data-rawwidth=\&692\& data-rawheight=\&240\&\u003E\u003Ch2\u003E1、编写Shader\u003C\u002Fh2\u003E\u003Cp\u003E下面的着色器代码实现了“滚动的背景”功能。这里定义了3个变量,其中_MainTex代表背景贴图,_Width代表显示背景的百分比,_Distance代表当前滚动的距离。核心代码为“i.uv.x = frac(i.uv.x*_Width + _Distance);”,其中frac是取小数的函数,如1.23 取出来是 0.23,其功能是将i.uv.x 控制在0到1的范围,进而显示出来。\u003C\u002Fp\u003E\u003Ccode lang=\&text\&\u003EShader \&Lpy\u002FImageRoll\& \n{\n\tProperties \n\t{\n\t\t_MainTex (\&Main Tex\&, 2D) = \&white\& {}\n\t\t\n
\t_Width (\&Width\&, float) = 0.5\n
\t_Distance (\&Distance\&, float) = 0\n\t}\n\t\n\tSubShader \n\t{\n\t\tTags {\&Queue\&=\&Transparent\& \&IgnoreProjector\&=\&True\& \&RenderType\&=\&Transparent\&}\n\t\t\n\t\tPass \n\t\t{\n\t\t\tTags { \&LightMode\&=\&ForwardBase\& }\n\t\t\tZTest off\n\t\t\tZWrite Off\n\t\t\tBlend SrcAlpha OneMinusSrcAlpha\n\t\t\t\n\t\t\tCGPROGRAM\n\t\t\t#pragma vertex vert
\n\t\t\t#pragma fragment frag\n\t\t\t#include \&UnityCG.cginc\&\n\t\t\n\t\t\tsampler2D _MainT\n\t\t\tfloat _W\n\t\t\tfloat _D\n\t\t\t
\n\t\t\tstruct a2v \n\t\t\t{
float4 vertex : POSITION; \n\t\t\t
float2 texcoord : TEXCOORD0;\n\t\t\t};
\n\t\t\t\n\t\t\tstruct v2f \n\t\t\t{
float4 pos : SV_POSITION;\n\t\t\t
float2 uv : TEXCOORD0;\n\t\t\t};
\n\t\t\t\n\t\t\tv2f vert (a2v v) \n\t\t\t{
\n\t\t\t\tv2
\n\t\t\t\to.pos = mul(UNITY_MATRIX_MVP, v.vertex);
\n\t\t\t\t\n\t\t\t\to.uv.x = v.texcoord.x;\n\t\t\t\to.uv.y = v.texcoord.y;\n\t\t\t\\n\t\t\t}
\n\t\t\t\n\t\t\tfixed4 frag (v2f i) : SV_Target \n\t\t\t{\n\t\t\t\ti.uv.x = frac(i.uv.x*_Width + _Distance);\n\t\t\t\tfixed4 c = tex2D(_MainTex, i.uv);\n\t\t\t\\n\t\t\t}\n\t\t\tENDCG\n\t\t}
\n\t}\n\tFallBack \&Transparent\u002FVertexLit\&\n}\u003C\u002Fcode\u003E\u003Ch2\u003E2、使用材质\u003C\u002Fh2\u003E\u003Cp\u003E新建一个名为ImageRoll的材质,选择上述编写的shader。设置WIdth和Distance两个参数,如下图所示。只要调整Distance的值,即可看到滚动到不同位置的背景。\u003C\u002Fp\u003E\u003Cimg src=\&v2-c71acc8f4a0dec5f2dc222.png\& data-rawwidth=\&692\& data-rawheight=\&230\&\u003E\u003Cimg src=\&v2-6a2f2a9e218d2c1797beed.png\& data-rawwidth=\&379\& data-rawheight=\&243\&\u003E\u003Ch2\u003E3、代码中引用\u003C\u002Fh2\u003E\u003Cp\u003E可以在代码中逐步增加distance 的值,造成背景不断向前滚动的效果。也可以在shader中使用Time相关的方法,实现同样的功能。\u003C\u002Fp\u003E\u003Ccode lang=\&text\&\u003Eusing UnityE\nusing System.C\nusing UnityEngine.UI;\n\npublic class ImageRoll : MonoBehaviour {\n\n\tpublic I\n\tprivate M\n\\n\t\u002F\u002F Use this for initialization\n\tvoid Start () {\n\t\tmtl = image.\n\t}\n\t\n\t\u002F\u002F Update is called once per frame\n\tvoid Update () {\n\t\tdistance += 0.005f;\n\t\tmtl.SetFloat(\&_Distance\&, distance);\n\t}\n}\u003C\u002Fcode\u003E\u003Cp\u003E将刚创建的材质应用于图片上,即可看到效果。如下图所示。\u003C\u002Fp\u003E\u003Cimg src=\&v2-1cd0be1d8d2ba59e6b404c7b9ec1bba0.png\& data-rawwidth=\&693\& data-rawheight=\&295\&\u003E\u003Cbr\u003E\u003Cp\u003E最后依然到了广告时间:笔者出版的一本Unity3D实战类书籍《Unity3D网络游戏实战》。该书通过一个完整的多人坦克对战实例,详细介绍网络游戏开发过程中涉及到的知识和技巧。书中还介绍了服务端框架、客户端网络模块、UI系统的架构等内容。相信透过本书,读者能够掌握Unity3D网络游戏开发的大部分知识,也能够从框架设计中了解商业游戏的设计思路,感谢大家支持。\u003C\u002Fp\u003E\u003Cimg src=\&v2-9e629e8fa3c93fe1f563be632d3a1ff2.png\& data-rawwidth=\&692\& data-rawheight=\&692\&\u003E&,&updated&:new Date(&T15:18:50.000Z&),&canComment&:false,&commentPermission&:&anyone&,&commentCount&:8,&likeCount&:25,&state&:&published&,&isLiked&:false,&slug&:&&,&isTitleImageFullScreen&:false,&rating&:&none&,&sourceUrl&:&&,&publishedTime&:&T23:18:50+08:00&,&links&:{&comments&:&\u002Fapi\u002Fposts\u002F2Fcomments&},&url&:&\u002Fp\u002F&,&titleImage&:&https:\u002F\u002Fpic1.zhimg.com\u002Fv2-d9e7d6d51fa27f75b0e48436dee51b06_r.jpg&,&summary&:&&,&href&:&\u002Fapi\u002Fposts\u002F&,&meta&:{&previous&:null,&next&:null},&snapshotUrl&:&&,&commentsCount&:8,&likesCount&:25},&&:{&title&:&作为程序员,如何规划成长路线&,&author&:&pyluo&,&content&:&\u003Cp\u003E前不久参与了游戏蛮牛的专家在线活动,几十位网友提出了他们的问题,其中有些问题较为普遍,于是决定把这些问题整理出来,加以完善,希望能够帮助到更多人。\u003C\u002Fp\u003E\u003Cp\u003E
原贴地址:\u003Ca href=\&http:\u002F\u002Fwww.manew.com\u002Fthread--1.html\& class=\&\& data-editable=\&true\& data-title=\&【2.24 某知名游戏公司主程在线答疑 参与有机会得《Unity 3D网络游戏实战》】-论坛活动-【游戏蛮牛】-ar增强现实,虚拟现实,unity3d,unity3d教程下载首选u3d,unity3d官网\&\u003E【2.24 某知名游戏公司主程在线答疑 参与有机会得《Unity 3D网络游戏实战》】-论坛活动-【游戏蛮牛】-ar增强现实,虚拟现实,unity3d,unity3d教程下载首选u3d,unity3d官网\u003C\u002Fa\u003E\u003C\u002Fp\u003E\u003Cbr\u003E\u003Cbr\u003E\u003Ch2\u003E作为程序员,如何规划职业成长路线\u003C\u002Fh2\u003E\u003Cp\u003E 问:\u003C\u002Fp\u003E\u003Cp\u003E
接触游戏开发也有一年多,感觉这一年基本上没学到什么东西。在机构学习的时候就常常听老师们说,框架,面向对象等,可是到做项目的时候基本都没用到过,每次做项目就是实现功能。到最后代码就乱得一塌糊涂。因为没有一套明确的方向,也不知道该去学那些。\u003C\u002Fp\u003E\u003Cp\u003E答:\u003C\u002Fp\u003E\u003Cp\u003E其中的一条可能的学习途径可以参考下面的三个阶段。\u003C\u002Fp\u003E\u003Cp\u003E第一年:能够做功能。\u003C\u002Fp\u003E\u003Cp\u003E尽量接触公司内比较完善的游戏项目,在参与编写逻辑的同时,不断完善自己的编码水平。同时了解该项目的设计思想、用到了哪些技术、用到了哪些第三方库,这些第三方库又是怎样使用的。\u003C\u002Fp\u003E\u003Cp\u003E第二年:用得起现有框架。\u003C\u002Fp\u003E\u003Cp\u003E经过第一年的学习,应该对游戏项目很熟悉了。此时要熟悉这一套框架的各部分功能,假如要让你做一款新的游戏,你能够在这套框架的基础上把游戏做出来。同时也多了解几套可用的框架,积累自己能够“撬得动”的代码资源。\u003C\u002Fp\u003E\u003Cp\u003E第三年:深入底层。\u003C\u002Fp\u003E\u003Cp\u003E深入底层了解这些源码,能够修改它们,或者能够重新写一个。同时再次学习计算机原理、图形学、数据库实现等课程,能够有不同的体会\u003C\u002Fp\u003E\u003Cp\u003E客户端、服务端具体的方向可能会有所不同,但大致的路径都是一样的。就是先能够使用、再能够使用某个现有资源重新搭建,再到深入底层。经过这3个阶段,相信便能够独当一面了。\u003C\u002Fp\u003E\u003Cbr\u003E\u003Ch2\u003E想做游戏服务端,应该学些什么 \u003C\u002Fh2\u003E\u003Cp\u003E年少不懂事
问:\u003C\u002Fp\u003E\u003Cp\u003E
如果走服务器需要会那些技能\u003C\u002Fp\u003E\u003Cp\u003E答:\u003C\u002Fp\u003E\u003Cp\u003E其实看看各大公司招聘基本就能够知道所需的技能了,大概有如下几点\u003C\u002Fp\u003E\u003Cp\u003E1、熟悉掌握一门主要编程语言,如c++或java\u003C\u002Fp\u003E\u003Cp\u003E2、熟悉掌握某一门脚本语言,如lua或python\u003C\u002Fp\u003E\u003Cp\u003E3、了解网络编程知识,了解TCP\u002FUDP\u002FIP协议的使用和实现细节。了解并能够使用一些现成的网络库,如libevent\u003C\u002Fp\u003E\u003Cp\u003E4、熟悉linux操作系统,能够操作它,并知道它的实现原理\u003C\u002Fp\u003E\u003Cp\u003E5、熟悉数据库,及其实现原理\u003C\u002Fp\u003E\u003Cbr\u003E\u003Cp\u003E目前服务端相关的资料很少,推荐书籍的话首先当然是推荐我自己的书《Unity3D网络游戏实战》啦,里面第6和7章有实现一套简易的服务端程序,还有下面几本书对能够让读者对服务端有更好的了解\u003C\u002Fp\u003E\u003Cp\u003E《Linux多线程服务端编程 使用muduo C++网络库》
陈硕\u003C\u002Fp\u003E\u003Cp\u003E《Redis源码涉及与实现(第二版)》
黄健宏\u003C\u002Fp\u003E\u003Cp\u003E《TCP\u002FIP详解:卷一》
看前面几章就行\u003C\u002Fp\u003E\u003Cbr\u003E\u003Ch2\u003EC++是必学的吗?能不能只用c#\u003C\u002Fh2\u003E\u003Cp\u003E 问:\u003C\u002Fp\u003E\u003Cp\u003E做游戏开发,lua和c++是必学的吗,我只用c#,unity不可以吗\u003C\u002Fp\u003E\u003Cbr\u003E\u003Cp\u003E答:\u003C\u002Fp\u003E\u003Cp\u003E游戏开发分前端和后端,使用到不同的技术。如果是后端,c++和lua是其中一种方案,如果是unity前端,c#是必须的,lua也有可能涉及,c++几乎不会用到。\u003C\u002Fp\u003E\u003Cbr\u003E\u003Cp\u003E然而一些面试中,会以c++水平去代表编程水平,一般c++水平高的话,c#、lua都不在话下。但无论如何,数据结构和算法肯定是要很扎实的。\u003C\u002Fp\u003E\u003Cbr\u003E\u003Cbr\u003E\u003Ch2\u003E大学生想学游戏开发,该怎样规划\u003C\u002Fh2\u003E\u003Cp\u003EFlyingFishF 问:\u003C\u002Fp\u003E\u003Cp\u003E
作为一名有部分java编程语言基础的大学生请问应当如何规划自己的unity3d学习路线\u003C\u002Fp\u003E\u003Cbr\u003E\u003Cp\u003E答:\u003C\u002Fp\u003E\u003Cp\u003E学习路线大概分为下面几个步骤\u003C\u002Fp\u003E\u003Cp\u003E1、先入门,能做小demo。这个阶段可以参考《Unity3D\\2D手机游戏开发》等书籍\u003C\u002Fp\u003E\u003Cp\u003E2、实战做一款稍有规模的游戏,这里就推荐我的《Unity3D网络游戏实战》,哈哈。\u003C\u002Fp\u003E\u003Cp\u003E3、解析别人的做法,在蛮牛上下载一些较大型的游戏源码,尝试改动他们、然后能够使用相应的框架去修改\u003C\u002Fp\u003E\u003Cp\u003E4、行为树、热更新、MVC等应用\u003C\u002Fp\u003E\u003Cp\u003E5、学习图形学和shader\u003C\u002Fp\u003E\u003Cp\u003E6、学习物理引擎\u003C\u002Fp\u003E\u003Cbr\u003E\u003Ch2\u003EAR\u002FVR的前景如何? \u003C\u002Fh2\u003E\u003Cp\u003EObarong问:\u003C\u002Fp\u003E\u003Cp\u003E《Oculus:VR杀手级应用应会是PC端大型社交网游》这个帖子说到,“杀手级应用自然而然地会成为杀手级应用,它们不是被设定是这样的。开发者从未想着开发杀手级应用,只想开发自己力所能及的最好的游戏,最终反应很好。”我认为在VR这个新领域,开发者应该着眼于自己最想玩的应用,不是为了跟房地产之类的热门行业沾上边,而强行转移关注点。老师,您认为呢?\u003C\u002Fp\u003E\u003Cbr\u003E\u003Cp\u003E答:\u003C\u002Fp\u003E\u003Cp\u003E看看股票也许能说明ARVR的现状,目前vr概念股已经不火了,杀手级应用迟迟未出现。没人知道杀手级应用会是什么样的,但如果做出来的东西自己都觉得不好,估计别人也肯定觉得不好。所以,还是要做自己认为好玩的、或者能够给大家带来便利的应用\u003C\u002Fp\u003E\u003Cp\u003EVRAR前几年的概念炒得火爆,但一直没有核心产品出现,今年有所降温。个人觉得短期内比较难有“改变世界”那样的ARVR产品出现,未来几年,大概会作为游戏、教育、房产、游乐园等领域的一种新运用。\u003C\u002Fp\u003E\u003Cbr\u003E\u003Ch2\u003E客户端服务端运算的区别\u003C\u002Fh2\u003E\u003Cp\u003EChenyici 问:\u003C\u002Fp\u003E\u003Cp\u003E请问服务端寻路和客户端自动寻路区别在哪里\u003C\u002Fp\u003E\u003Cp\u003E答:\u003C\u002Fp\u003E\u003Cp\u003E最主要的区别在于客户端寻路因为算法暴露在客户端,而客户端在用户手中,用户可以通过破解等手段修改程序,从而实现作弊。如果是服务端寻路就无法作弊了。因为每个客户端只处理自己的寻路,计算量小,而如果放到服务端,它需要计算所有角色的寻路,计算量就大很多,从技术实现上看,客户端寻路要比服务端寻路简单。\u003C\u002Fp\u003E\u003Cbr\u003E\u003Ch2\u003E战斗回放功能的实现方法\u003C\u002Fh2\u003E\u003Cp\u003EDonot001 问:\u003C\u002Fp\u003E\u003Cp\u003E我们游戏为3d回合制游戏,客户端用unity开发,目前要做战斗的回放,请问您有什么高效简单的办法么 \u003C\u002Fp\u003E\u003Cp\u003E答:\u003C\u002Fp\u003E\u003Cp\u003E回放功能一般是记录状态,如果是服务端运算,只需要将服务端发送的协议全部记录下来,客户端一定可以根据这些协议恢复战斗现场的。也就是说,把战斗中的每一个状态或者状态切换都记录下来,后面客户端再恢复现场,即是按照时间轴记录玩家行为。\u003C\u002Fp\u003E\u003Ch2\u003E怎样实现多人pvp对战?\u003C\u002Fh2\u003E\u003Cp\u003ESislcb问:\u003C\u002Fp\u003E\u003Cp\u003E请问《Unity3D网络游戏实战》有涉及多人PVP战斗,客户端跟服务器同步的详细交互过程吗?如果有的话,对于多人及时PVP战斗,都是用帧同步吗?有比较成熟的开源实现吗?有一些坑的经验吗?比如,多少人一个房间,不会卡?或者同步的周期如何?当网络卡的时候,如何进行帧补偿?如果没有,考虑为了版本增加这方面的知识吗?\u003C\u002Fp\u003E\u003Cp\u003E答:\u003C\u002Fp\u003E\u003Cp\u003E书中会实现多人pvp的战斗,使用客户端计算服务端转发的方式,描述应该还算是非常详细的。同步方式使用客户端计算、服务端转发(以及一些简单的校验)、其他客户端使用预测算法计算轨迹的方式,例子中同步周期约0.2秒,6个人一个房间。可以很简单的修改为10+个人同房间,服务端应该也还行。\u003C\u002Fp\u003E\u003Cp\u003E网络卡会影响到自己的显示,但不会影响他人,帧同步会拖慢所有人的操作,并不适合实时性很高的游戏。\u003C\u002Fp\u003E&,&updated&:new Date(&T14:00:53.000Z&),&canComment&:false,&commentPermission&:&anyone&,&commentCount&:4,&likeCount&:71,&state&:&published&,&isLiked&:false,&slug&:&&,&isTitleImageFullScreen&:false,&rating&:&none&,&sourceUrl&:&&,&publishedTime&:&T22:00:53+08:00&,&links&:{&comments&:&\u002Fapi\u002Fposts\u002F2Fcomments&},&url&:&\u002Fp\u002F&,&titleImage&:&&,&summary&:&&,&href&:&\u002Fapi\u002Fposts\u002F&,&meta&:{&previous&:null,&next&:null},&snapshotUrl&:&&,&commentsCount&:4,&likesCount&:71},&&:{&title&:&《球球大作战》源码解析——(1)运行起来&,&author&:&pyluo&,&content&:&\u003Cp\u003E鉴于agar.io类型游戏的火爆场面,一些公司纷纷效仿,一时间出现各种《XX大作战》类型的游戏。出于学习的目的,亦是做些技术和方案储备,接下来会有大概10篇文章,分析下面这款使用nodejs编写的开源“球球大作战”。由于该游戏采用服务端运算、客户端显示的方式,服务端的逻辑处理是该源码的重点,故而系列文章主要针对服务端。通过这套源码,可以学习到“一种基于nodejs的简单服务器实现方法”“一种简单的服务端物理逻辑的实现方式”“一种基于redis pub\u002Fsub的跨服设计思想”“nodejs语法、框架及其使用方式”等内容。\u003Cbr\u003E\u003C\u002Fp\u003E\u003Cbr\u003E\u003Cp\u003E系列文章将会分析\u003Ca href=\&https:\u002F\u002Fgithub.com\u002Fhuytd\u002Fagar.io-clone\& data-editable=\&true\& data-title=\&huytd\u002Fagar.io-clone\& class=\&\&\u003Ehuytd\u002Fagar.io-clone\u003C\u002Fa\u003E的源码,这是一套简约而不简单的Agar.IO实现。该项目使用NodeJS开发,使用socket.IO作为网络通信,使用HTML5实现客户端。\u003C\u002Fp\u003E\u003Cp\u003E下图为游戏运行画面,游戏规则如下。\u003C\u002Fp\u003E\u003Cp\u003E1、玩家可以移动鼠标控制小球\u003C\u002Fp\u003E\u003Cp\u003E2、当小球吞食场景中的食物或其他玩家控制的小球时,玩家控制的小球会变大\u003C\u002Fp\u003E\u003Cp\u003E3、小球越大,移动速度越慢\u003C\u002Fp\u003E\u003Cp\u003E4、小球的质量代表它的大小,质量为它吞食的食物或其他玩家的质量之和\u003C\u002Fp\u003E\u003Cp\u003E5、游戏目标是尽可能的吞食其他玩家,使小球变大\u003C\u002Fp\u003E\u003Cp\u003E6、玩家刚出生时会有无敌属性,直到它吞食食物\u003C\u002Fp\u003E\u003Cp\u003E7、每当有玩家进入游戏,场景中会生成3个食物\u003C\u002Fp\u003E\u003Cp\u003E8、每当吞食食物时,场景中亦会生成一个新的食物\u003C\u002Fp\u003E\u003Cimg src=\&v2-e163e9c18c851b9b40bc1.png\& data-rawwidth=\&693\& data-rawheight=\&422\&\u003E\u003Cp\u003E第一步便是要让游戏运行起来,只有运行起来了,才谈得上后续的源码分析。为了“从零开始”,笔者购买Ubuntu系统的腾讯云,新的系统几乎没有安装额外软件,一步一步安装所需的软件,然后将游戏运行起来吧。笔者选用了最低一档配置的服务器,花费近50大洋(此处是不是应该发个求赞助的链接?)配置如下图所示。\u003C\u002Fp\u003E\u003Cimg src=\&v2-45b58b4ef367bbdb80853aa.png\& data-rawwidth=\&692\& data-rawheight=\&286\&\u003E\u003Ch2\u003E1、安装nodeJs \u003C\u002Fh2\u003E\u003Cp\u003E游戏使用nodejs开发,那就必须要安装nodejs,可以有两种方法安装。\u003C\u002Fp\u003E\u003Cp\u003E方法1 :输入sudo apt install nodejs,这是最简单的安装方法了。不过使用该方式安装的程序名叫为nodejs,而不是普遍使用的node。可以使用sudo ln -s \u002Fusr\u002Fbin\u002Fnodejs \u002Fusr\u002Fbin\u002Fnode建立名为node的连接,以解决这个问题。\u003C\u002Fp\u003E\u003Cp\u003E方法2:下载源码、编译、安装。具体可以参考这篇文章\u003Ca href=\&https:\u002F\u002Flinux.cn\u002Farticle-5766-1.html\& data-editable=\&true\& data-title=\&在Ubuntu下安装Node.JS的不同方式-技术 ◆ 学习|Linux.中国-开源社区\& class=\&\&\u003E在Ubuntu下安装Node.JS的不同方式-技术 ◆ 学习|Linux.中国-开源社区\u003C\u002Fa\u003E (文章里使用的node-v6.9.5 要改为最新版的)\u003C\u002Fp\u003E\u003Cp\u003E完成后,可以使用node -v查看nodejs版本号,以验证是否成功安装。\u003C\u002Fp\u003E\u003Ch2\u003E2、上传代码文件\u003C\u002Fh2\u003E\u003Cp\u003E从github上下载源码,然后上传到linux服务器上。如下图所示,笔者将源码上传到\u002Fhome\u002Fubuntu\u002Fagar.io-clone-master目录下\u003C\u002Fp\u003E\u003Cimg src=\&v2-4a98a80d201d4bb9dc3e9b482aa32d35.png\& data-rawwidth=\&485\& data-rawheight=\&114\&\u003E\u003Ch2\u003E3、安装npm\u003C\u002Fh2\u003E\u003Cp\u003Enpm(node package manager)是nodejs的包管理和分发工具,一般安装nodejs后都需要安装该软件,可以使用以下命令安装:sudo apt install
npm\u003C\u002Fp\u003E\u003Ch2\u003E4、安装gulp\u003C\u002Fh2\u003E\u003Cp\u003E项目使用到了gulp,需要安装它。gulp是一个前端构建工具,开发者可以使用它在项目开发过程中自动执行常见任务,比如复制文件,比如替换文件中某些字符。进入源码目录,执行sudo npm install -g gulp 即可安装。\u003C\u002Fp\u003E\u003Ch2\u003E5、安装项目所需的包文件\u003C\u002Fh2\u003E\u003Cp\u003E进入源码目录,执行npm install即可安装项目所需包文件。npm install会检查当前目录下的package.json文件,文件包含了项目所需的模块,npm根据该文件的描述下载这些文件并把模块放到.\u002Fnode_modules目录下。关于package.json的格式可以参考这篇文章\u003Ca href=\&http:\u002F\u002Fju.outofmemory.cn\u002Fentry\u002F130809\& data-editable=\&true\& data-title=\&package.json for NPM 文件详解\&\u003Epackage.json for NPM 文件详解\u003C\u002Fa\u003E\u003C\u002Fp\u003E\u003Ch2\u003E6、运行服务器\u003C\u002Fh2\u003E\u003Cp\u003E在源码目录下执行gulp run,可以看到服务器启动的提示信息。\u003C\u002Fp\u003E\u003Ch2\u003E7、运行客户端\u003C\u002Fh2\u003E\u003Cp\u003E运行浏览器,输入地址即可,笔者的腾讯云ip为139.199.179.39,由于默认配置了3000端口,所以要输入\u003Ca href=\&http:\u002F\u002F139.199.179.39:F\& data-editable=\&true\& data-title=\&199.179.39 的页面\& class=\&\&\u003Ehttp:\u002F\u002F139.199.179.39:F\u003C\u002Fa\u003E ,即可看到如下的游戏界面。\u003C\u002Fp\u003E\u003Cimg src=\&v2-e387db51d37a5eae40648.png\& data-rawwidth=\&692\& data-rawheight=\&625\&\u003E\u003Cbr\u003E\u003Cp\u003E在笔者的试验中,该页面报错,点击按钮没有反应。原因是src\u002Fclient中的index.html最后面有这么一句,&script src=\&\u002F\u002Fcode.jquery.com\u002Fjquery-2.2.0.min.js\&&&\u002Fscript&,该语句用于加载jquery的,而code.jquery.com\u002Fjquery-2.2.0.min.js无法访问(或国内网络访问速度慢),导致报错。只要换个文件地址即可,例如改成下面这样:
\u003C\u002Fp\u003E\u003Ccode lang=\&text\&\u003E &script src=\&http:\u002F\u002Flibs.baidu.com\u002Fjquery\u002F1.9.0\u002Fjquery.js\&&&\u002Fscript &\n\u003C\u002Fcode\u003E\u003Cbr\u003E\u003Cp\u003E运行游戏,服务端也会打印出相应的信息,如下图所示。\u003C\u002Fp\u003E\u003Cimg src=\&v2-0d517a2bae8d.png\& data-rawwidth=\&684\& data-rawheight=\&82

我要回帖

更多关于 java让线程暂停 的文章

 

随机推荐