1.道路的自动生成

道路自动生成概述:

3D跑酷游戏的核心就是跑,在跑这一过程中增加趣味性使得游戏具有更多的可玩性。道路的自动生成和自由拼接,为游戏增设了更多的不可预见性。这种不可预见性使得玩家在游戏中更多的体验到探索精神,进而开发玩家对游戏的兴趣。因此在跑酷游戏中,并不建议开发者设定好固定的场景道路,道路的自动生成模式更能吸引玩家。开发者可以通过不同的方式来实现道路的自动生成,将角色固定点场景后移的方式实现;或者固定道路的坐标,通过角色的向前奔跑产生位移变化。

原理:

通过使角色不断奔跑,产生相应位移变化,来达到道路的自动生成为例。将道路抽象的想象成一块块的板子,道路的不同场景转换和消失就如同板子的拼接和掉落。其原理流程,如图1-1所示。


图1-1

实现方法:

步骤1:

导入美术资源。将制作好的道路美术资源导入Genesis-3D引擎中。以shanggu01.fbx为例。将shanggu01.fbx文件导入项目文件夹->将项目文件里的资源文件拖入场景->附材质。这里需要注意,为了使道路可以完美拼接,道路场景制作接口处尺寸应该一样。并将文件转换为template。方便重复利用资源,方法如下图1-1-1所示。


图1-1-1

步骤2:

道路的拼接原理及实现:

2.1拼接原理:以两个道路拼接为例,抽象理解为板子A、B。

引擎中在板首尾的同侧方向创建两个空对象,按照下图原则,将所有道路场景文件都标记好。如图1-2-1-1所示


图1-2-1-1

通过创建Template,把下一个板的中心点,放到前一个板的连接点就可以了,即将当前游戏角色所在A板的连接点坐标覆盖为下一块板B中心点的坐标。


图1-2-1-2

2.2道路的拼接与生成实现。道路自动生成与拼接的相关代码框架,如下所示。。

在RunTimeBoardMgr文件中,Init初始化函数里加上你要新添加的模板类型:

01 public void Init ()
02 {                    
03  AddTemplate("ShanDong_01.template", GroundBoardType.Beginner, 0, 0);
04  AddTemplate("ShanDong_01.template", GroundBoardType.ShanDong1, 0, 0);
05  AddTemplate("ShanDong_02.template", GroundBoardType.ShanDong2, 0, 0);
06  AddTemplate("ShanDong_03.template", GroundBoardType.ShanDong3, 0, 0);
07  AddTemplate("ShanGu_01.template", GroundBoardType.ShanGu, 0, 0);
08  AddTemplate("ShanGu_02.template", GroundBoardType.ShanGu, 0, 0);
09  _boardConnectionMgr.Init();
10  Reset();
11  Preload();
12 }

其中AddTemplate()函数的参数分别是你要添加的模板名字、地形块儿类型、地形块儿等级以及地形块儿的障碍物类型。

01  void AddTemplate (string templateName, GroundBoardType type, int level, int barrierType)
02 {
03  nt templateListIndex = (int)type;
04  if (templateListIndex < 0 || templateListIndex >= _templateList.Length)
05  {
06   return;
07  }
08  if (_templateList[templateListIndex] == null)
09  {
10   _templateList[templateListIndex] = new BoardTemplateGroup();
11  }
12   BoardTemplate newTemplate = new BoardTemplate(templateName, level, barrierType);
13   _templateList[templateListIndex].Add(newTemplate);
14 }

AddTemplate()函数会创建一个新的BoardTemplate对象,并把它放到模板列表中,BoardTemplate类,如下所示。

01 public class BoardTemplate
02 {
03  string _templateName;// 模板名字
04  int _level;//板子的等级
05  int _barrierType;//障碍物类型
06  public BoardTemplate(string name, int level, int barrierType)
07  {
08   _templateName = name;
09   _level = level;
10   _barrierType = barrierType;
11  }
12  
13  public string Name
14  {
15   get{return _templateName;}
16  }
17  public int Level
18  {
19   get{return _level;}
20  }
21  public int BarrierType
22  {
23   get{return _barrierType;}
24  }
25 }

接着在LogicMgr.cs的Tick里面,每一帧都会用角色的位置信息,去判定是否要更新地形块儿。

1 public void Tick (float elapseTime)
2 {
3  …………
4  …………
5  _runtimeBoardMgr.CheckUpdateBoard(PlayerDataMgr.Singleton.Pos.Z);
6  …………
7  …………
8 }

当满足判定条件时,就会自动的创建一块儿新板子拼接上去。

01 public void CheckUpdateBoard (float playerPosZ)
02 {
03  if (playerPosZ > _EndPos - StaticData.CreateBoardDistance)
04  {
05   if(LogicMgr.Singleton.IsBeginner && _boardList.Count > 0)
06   {
07    CreateNewBorad (RandomBoardType.Beginner);
08   }
09   else
10   {
11    CreateNewBorad (RandomBoardType.Normal);
12   }
13  }
14  …………
15  …………
16 }

创建新板子的代码,如下所示。

01 void CreateNewBorad (RandomBoardType randomBoardType)
02 {
03  //是否是第一块儿板子
04  bool firstBoard = _boardList.Count > 0 ? false true;
05  //创建一个新的GroundBoardBase
06  GroundBoardBase newBoard = null;
07  //根据板子的随机类型调用不同的随机板子函数
08  if (randomBoardType == RandomBoardType.Beginner)
09  {
10   newBoard = RandomBeginnerBoard ();
11  }
12  else
13  {
14   newBoard = RandomNextBoard (firstBoard);
15  }
16  if (newBoard == null)
17  {return; }
18  //初始化这个newBoard上面的Item
19  GroundBoardBase.InitData initData = new GroundBoardBase.InitData ();
20  initData.PlayerZSpeed = PlayerDataMgr.Singleton._zSpeed;
21  if (newBoard.IsHaveItem)
22  {
23   initData.RandomItemType = _randomItemMgr.RandomItem ();
24  }
25  else
26  {
27   initData.RandomItemType = Item.ItemType.Nothing;
28  }
29  newBoard.Init(initData);
30  newBoard.ResetBoard();
31  //根据上一块板子的连接点位置,来摆放这块儿新板子
32  if (firstBoard)
33  {
34   newBoard.SetPos (StaticData.kBoardWidth / 2, 0, 0);
35  }
36  else
37  {               
38   GroundBoardBase preBoard = _boardList [_boardList.Count - 1];
39   newBoard.SetPos(preBoard.EndPos.X,preBoard.EndPos.Y,preBoard.EndPos.Z);
40  }
41   _EndPos += newBoard.Length;
42   _boardList.Add (newBoard);
43 }

创建普通板子举例:

01 GroundBoardBase RandomNextBoard (bool firstBoard)
02 {
03  //根据自行定义的拼接规则,随机出一个下一块板子的模板文件
04  AreaType nextBarrierType = AreaType.Rest;
05  if (firstBoard)
06  {
07   _lastBoardType = StaticData.FirstBoardType;
08  }
09  else
10  {
11   _lastBoardType=_boardConnectionMgr.RandomNextBoardType (_lastBoardType);
12   nextBarrierType = RandomNextAreaType();
13  }
14   BoardTemplateGroup boardGroup = _templateList[(int)_lastBoardType];
15   BoardTemplate template = boardGroup.Random (nextBarrierType);
16   //根据模板文件的名字创建新板子
17   if (template == null)
18   {return null;}
19   GroundBoardBase newBoard = null;                   
20   newBoard = new GroundBoardFlat (template.Name, _lastBoardType);
21   eturn newBoard;
22 }

这里创建一个新的GroundBoardBase的时候,会根据模板文件的名字来创建这个Actor:

1 public GroundBoardBase (string templateName)
2 {
3  _groundActor=ActorManager.CreateFromTemplate (StaticData.BoardTemplatePath + templateName,false);
4   }

如果开发者的设计思路,与游戏DEMO相同的话,可以直接套用上面的代码,只需要在最上面的AddTemplate(模板文件名, 板子类型, 板子等级, 障碍物类型);稍作修改,即可使用。


引擎官方网站:http://www.genesis-3d.com.cn/

官方论坛:http://bbs.9tech.cn/genesis-3d/

官方千人大群:59113309   135439306

YY频道-游戏开发大讲堂(完全免费,定期开课):51735288

Genesis-3D开源游戏引擎:游戏起源,皆因有我!!!

 


《Genesis-3D开源游戏引擎完整实例教程-跑酷游戏篇01:道路的自动生成》的更多相关文章

  1. 简单物联网:外网访问内网路由器下树莓派Flask服务器

    最近做一个小东西,大概过程就是想在教室,宿舍控制实验室的一些设备. 已经在树莓上搭了一个轻量的flask服务器,在实验室的路由器下,任何设备都是可以访问的:但是有一些限制条件,比如我想在宿舍控制我种花 ...

  2. 利用ssh反向代理以及autossh实现从外网连接内网服务器

    前言 最近遇到这样一个问题,我在实验室架设了一台服务器,给师弟或者小伙伴练习Linux用,然后平时在实验室这边直接连接是没有问题的,都是内网嘛.但是回到宿舍问题出来了,使用校园网的童鞋还是能连接上,使 ...

  3. 外网访问内网Docker容器

    外网访问内网Docker容器 本地安装了Docker容器,只能在局域网内访问,怎样从外网也能访问本地Docker容器? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动Docker容器 ...

  4. 外网访问内网SpringBoot

    外网访问内网SpringBoot 本地安装了SpringBoot,只能在局域网内访问,怎样从外网也能访问本地SpringBoot? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装Java 1 ...

  5. 外网访问内网Elasticsearch WEB

    外网访问内网Elasticsearch WEB 本地安装了Elasticsearch,只能在局域网内访问其WEB,怎样从外网也能访问本地Elasticsearch? 本文将介绍具体的实现步骤. 1. ...

  6. 怎样从外网访问内网Rails

    外网访问内网Rails 本地安装了Rails,只能在局域网内访问,怎样从外网也能访问本地Rails? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动Rails 默认安装的Rails端口 ...

  7. 怎样从外网访问内网Memcached数据库

    外网访问内网Memcached数据库 本地安装了Memcached数据库,只能在局域网内访问,怎样从外网也能访问本地Memcached数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装 ...

  8. 怎样从外网访问内网CouchDB数据库

    外网访问内网CouchDB数据库 本地安装了CouchDB数据库,只能在局域网内访问,怎样从外网也能访问本地CouchDB数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动Cou ...

  9. 怎样从外网访问内网DB2数据库

    外网访问内网DB2数据库 本地安装了DB2数据库,只能在局域网内访问,怎样从外网也能访问本地DB2数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动DB2数据库 默认安装的DB2 ...

  10. 怎样从外网访问内网OpenLDAP数据库

    外网访问内网OpenLDAP数据库 本地安装了OpenLDAP数据库,只能在局域网内访问,怎样从外网也能访问本地OpenLDAP数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动 ...

随机推荐

  1. MonoBehaviour的事件和具体功能总结

    原地址:http://blog.csdn.net/dingxiaowei2013/article/details/26215577 苦于Visual Studio 2013没有对MonoBehavio ...

  2. Ubuntu环境下手动配置Java环境

    /×××××××××××××××××××××××××××××××××××××××××/ Author:xxx0624 HomePage:http://www.cnblogs.com/xxx0624/ ...

  3. Android_Mars学习笔记_S01_001activity初步

    一.activity初步 1.程序启动会先读配置文件AndroidManifest.xml找activity 2.activity会在onCreate方法中读取activity_main.xml文件, ...

  4. delphi 反射(原理)

    关于反射的用途是『降低模块间的耦合度』这个倒未必尽然 单就delphi来说,从实现上看,它的所谓反射是基于RTTI,而RTTI的出现按照官方的说法是为了实现RAD中窗体文件DFM的持久化而产生的,其实 ...

  5. POJ1068——Parencodings

    Parencodings Description Let S = s1 s2...s2n be a well-formed string of parentheses. S can be encode ...

  6. SQL盲注修订建议

    一般有多种减轻威胁的技巧: [1] 策略:库或框架 使用不允许此弱点出现的经过审核的库或框架,或提供更容易避免此弱点的构造. [2] 策略:参数化 如果可用,使用自动实施数据和代码之间的分离的结构化机 ...

  7. Android TabHost中实现标签的滚动以及一些TabHost开发的奇怪问题

    最近在使用TabHost的时候遇到了一些奇怪的问题,在这里总结分享备忘一下. 首先说一点TabActivity将会被FragmentActivity所替代,但是本文中却是使用的TabActivity. ...

  8. hdr_beg(host) hdr_reg(host) hdr_dom(host)

    case 1 测试hdr_beg(host) 的情况 acl zjtest7_com hdr_beg(host) -i zjtest7.com use_backend zjtest7_com if z ...

  9. DIV内英文或者数字不换行的问题 解决办法

    word-wrap:break-word; word-break:break-all;

  10. 彻底搞懂javascript中的match, exec的区别

    在工作中经常发现一些同学把这两个方法搞混,以致把自己弄的很郁闷.所以我和大家一起来探讨一下这两个方法的奥妙之处吧. 我们分以下几点来讲解: 相同点: 1.两个方法都是查找符合条件的匹配项,并以数组形式 ...