《Windy》Week#1

December 13, 2015

##2015.12.13

在把玩RPG Maker(并且意识到它的强大,然而)无果之后,重新开始使用Unity制作原型。与以往不同的是,为了实现类似《纪念碑谷》等游戏的斜45度效果,采用了3D而非熟悉的2D。

###完成的工作

  1. 将游戏视角调整为斜45度。
  2. 角色移动控制。

####将游戏视角调整为斜45度的方法

  1. 将Y轴旋转45度,X轴旋转30度(X轴控制高度,Y轴控制角度)。
  2. 将Projection改为Orthographic。
  3. 更改摄像机Size至合适大小。

####角色移动控制

  1. 将地面层的layer与tag设置完毕。
  2. 使用射线确定鼠标点击位置。
  3. 使用LookAt函数,使角色转向目标位置。
  4. 使用rigidbody进行移动。

####射线确定鼠标点击位置的方法

1
2
3
4
5
6
7
8
m_layerMask = 1 << 8;
// 根据鼠标在屏幕空间的位置计算射线
m_ray = Camera.main.ScreenPointToRay(Input.mousePosition);
// 进行三维场景中的射线求交
if (Physics.Raycast(m_ray, out m_hitInfo, 100, m_layerMask))
{			
	//TODO:...
}

###下一步

  1. 角色控制也许不使用rigidbody
  2. 增加可以呼唤女孩(暂名Windy)的位置,在那些位置上,玩家角色与之接触(或者按下某个键位)可以呼唤Windy,这样Windy就可以走到那里
  3. Windy自动寻路
  4. 当Windy离开这些位置的时候,用于呼唤的魔石过一段时间之后会再度生长出来

##2015.12.14

接着昨天的内容继续开发。

###完成的工作

  1. 呼唤Windy。
  2. 自动寻路。
  3. 当Windy离开这些位置的时候,用于呼唤的魔石过一段时间之后会再度生长出来。
  4. 使用自动寻路或角色控制器(Character Controller)用鼠标控制玩家角色移动。
  5. 使用rigidbody暂时代替的推箱子。

呼唤Windy与魔石生长

  1. OnTriggerEnter()开启开关,并获得目标位置,记录Windy位置。
  2. Windy自动寻路。
  3. 在Windy第二次离开目标位置之后,在Windy位置上生长魔石。

自动寻路

这是对我来说相对较新的知识点,原以为需要查找资料自造轮子或者使用插件,没想到Unity本身自带的Navigation就已经这样强大。

  1. 为Windy绑定Nav Mesh Agent。
  2. 选定墙壁、地板等不可穿越物件,选择Window - Navigation,勾选Nav Static,点击右下角Bake,生成Nav Mesh。

Nav Mesh

1
m_girl.GetComponent<NavMeshAgent>().destination = target.transform.position;

角色控制器

因为之前一直在做2D游戏,对于角色控制器没有过多关注;开始查找到的资料多为使用键盘控制角色移动。

  1. 无需添加rigidbody。
  2. 如果有重力,需要以isGrounded实现。

使用鼠标移动角色如下:

1
2
Vector3 tempMov = Vector3.ClampMagnitude(m_targetPos - this.transform.position, speed);
this.GetComponent<CharacterController>().Move(tempMov);

2015.12.15

今天并没有完成很多工作,原因是一些设计上的问题再次冒出头来,对我说“你压根没有想清楚!”。的确,这次想要开始动手编码源自于LD34,但后来因为时间的缘故并没有拿出作品参赛,总之是兴致一来就开始的行动。真正把颅内剧场实现才发现许多事情根本和自己的想象不同。

比如,今天用了一些时间考虑了一下是否应该使用“呼唤区域”这个概念,因为它似乎限制住了玩家的自由性。但是,如果玩家在任何时候都能够呼唤Windy的话,则会造成两个问题:

  1. 需要增加一个按键进行呼唤操作(当然,这个问题可以通过其他方式解决)。
  2. 对于Windy移动过于自由的掌控会使得Windy是另一个人这个概念大大弱化。移动方式只是鼠标点击移动的繁琐升级版。这个问题是设计这款游戏的时候一定要时时刻刻留意的。

于是我也意识到将之前的设计想法、思路做一个汇总的必要性。这个汇总将包括之后打算尝试的新的可能,并且会按照得出的结论进行数个版本的修订。

这样做的好处有以下几点:

  1. 避免一些不必要的重复性工作。
  2. 一定程度地将程序、美术与设计的工作分离开来。这种分离对于独立开发者是必要的,因为脑中内讧损伤的必然还是自己。
  3. 使得游戏开发的计划性更强。

最后完成的关卡示例终于展示了这款游戏的玩点之一,但是我最希望看到的玩家对于Windy的保护还没有那么强烈地展现出来,并且现在的游戏项目也没有用到真正开发游戏时需要的核心技术。尽管如此,游戏可以如此迅速地进入到使用可玩原型进行关卡搭建的阶段还是让我感到有些开心。

P.S.觅得一个制作gif的利器licecap。

完成的工作

  1. 齿轮关卡示例。
  2. 粗糙的关卡选择功能。

GearLevelDemo

##2015.12.17

昨天停工一天,理了理下一步要做的事情的头绪,也去IndieAce取了取经。

###完成的工作

  1. 为了制作开场动画而学习了几个与场景加载有关的函数,如DontDestroyOnLoad()(加载新的场景时不要销毁的物品,如各种Manager),LoadLevelAsync()等。暂时并不会用到。
  2. 研究了如何实现类似推箱子功能,但因为这个功能与移动方式本身之间关联非常紧密(我尚且没有想到使用鼠标点击移动的方式下如何推动箱子,而且不想做成键盘控制移动因为与移动平台过于不搭调),所以打算暂时使用开关移动平台功能代替。
  3. 于是制作了开关移动平台这一功能:当玩家移动到开关周围时,鼠标点击开关,平台移动。

####开关移动平台实现

  1. 开关与平台绑定。

平台相关代码:

1
2
3
4
5
6
7
8
9
10
public enum MovableType {
	left,
	right,
	up,
	down,
	forward,
	back
}

public MovableType movableType;

开关相关代码:

1
2
3
4
5
6
7
public void SwitchOn () {
	switch (Movable.GetComponent<MovableController> ().movableType) {
	case MovableController.MovableType.left:
		break;
	//...	
	}
}

####动态寻路实现

  1. 选中地面,勾选Nav Static,烘焙Nav Mesh。
  2. 为平台添加NavMeshObstable组件。
  3. 勾选Carve选框。

##2015.12.19

###完成的工作

  1. 打算实现风可以通过,但Windy不能通过的关卡,因此学习了隔离自动寻路。
  2. 以类似的方式实现了梯子与台阶的功能。
  3. 实现风与Windy行走不同道路。

####隔离自动寻路

  1. 在Navigation窗口Object选项卡,勾选Generate OffMeshLinks。
  2. 在Navigation窗口Bake选项卡,设置Generate Off Mesh Links的drop heights与jump distance。
  3. 烘焙。

2015.12.26补充:需要为Nav Mesh Agent勾选Jump选项

####梯子与台阶

  1. 建立梯子游戏对象,添加Off Mesh Link组件。
  2. 建立起始点与终结点的游戏对象,分别放置在Off Mesh Link的Start与End。
  3. 关闭Auto Traverse Off Mesh Link以控制移动速度(代码见下方)。
  4. 烘焙。
void TraverseOffMeshLink () {
	if (navMeshAgent.isOnOffMeshLink) {
		linkData = navMeshAgent.currentOffMeshLinkData;
		this.transform.DOMove(linkData.endPos, 2);
	}
	if (Vector3.Distance(this.transform.position, linkData.endPos) < 1){
			navMeshAgent.Resume();
			navMeshAgent.CompleteOffMeshLink();
	}
}

####分道

  1. 为Windy不能行走的道路Off Mesh Link设置Layer。
  2. 在Windy的Nav Mesh Agent设置行走范围。

版权声明:自由转载-非商用-非衍生-保持署名(创意共享3.0许可证