由于我自身知识的局限,下面Object有可能被称为对象有可能被称为物体,其实都是指的Game Object。
认识基本界面
工具栏, 提供手形工具克控制按钮,如播放暂停等。
scene 场景,应该相当于story board,是集中所有元素的地方。
hierarchy 当前场景下所有物体的堆栈,包括播放器,UI,摄像头,玩家,背景纹理等等
assets 所有资源的管理器,包括纹理,bgm等等
game 游戏预览,通过工具栏的播放按钮,可以在这里
游戏中所有对象都是Game Object,它的表现通过Properties来定义, Inspector窗口可以查看选中对象的所有组件Component, 以及每个组件的属性
项目基本概念
游戏是由一个一个的"场景"组成的。组成场景的基本单位是Game Object,它可以有多个Component,每个Component拥有自己的属性。Game Object可以被存储在Asset里,以在多个地方复用。Prefab就是这样一类物体,它是预制的建筑材料。在Asset里定义的Prefab相当于类文件,而在Hierarchy里的东西相当于类实例,我们可以从Asset里拖动物体到Hierarchy中,这叫做实例化(initiate/clone)。
在示例工程里,从Assets进到PlatformerTemplate文件夹,里面有个Prefabs文件夹,预定义了一套物体,包括砖块平台,按钮等,通过组合这些物体,可以构造出我们的环境场景。
构造好场景,物体,交互之后,需要将游戏导出成可执行文件,以便在Unity以外运行,导出时可选择运行平台,有PC,Android,PS4,XBox等等可选。
试玩
导出了demo工程进行试玩,手感太差了,主要有三个问题:
- 贴墙跳和挨着物体跳的判定很难受,无法跳到上方的下个块,会被判定碰撞。在高台边缘也有这种情况,会被判定下落
- 开头的隐藏路径是死路,没有任何奖励,这不合理
- 要是有加速跑和二段跳就好了
- (说好的三个问题呢?)有一个地方浮空砖块的右边块错用成了中间砖块的贴图
下面我们就拿着新手村Lv.1的木剑(+百度buff),试着搞定以上三(si)个问题。
1. 贴墙跳受阻:砖块碰撞判定
猜测挨着砖块边缘跳不起来是因为被判定为碰撞了。查看player属性,发现player就是将一个Controller与动作贴图,实体模型,动作音效,结合在一起组成的物体(顺手改了一下生命值,加速度和最大速度,跳跃的初始速度和重力加速度决定了跳跃的高度,横向速度决定了跳跃距离)。
贴墙跳会顶住砖块而卡住跳不高,是不是因为跟墙壁有摩擦导致上升速度降为0?那我们可不可以当人物跳起来时,墙的边缘摩擦变为0,这样就不卡了。那么一是判断人物跳跃,二是更改摩擦。(网上搜了一下,发现示例的Assets里有代码)找到Assets的Scripts,找到PlayerController,里面有个跳跃状态机,可以看到将跳跃以状态模式进行管理,那么判断人物跳跃只要看其状态即可。我们需要在跳跃时和落地时修改摩擦。新建两个PhysicsMaterial2D材质,分别赋值摩擦系数为0和0.4, 注意属性friction是浮点型,需要在数值后面加F。然后找到Player的碰撞体collider,把他的sharedMaterial赋值为我们创建的材质即可。
打开Unity编辑器,Window->General>Console可以调出控制台窗口,代码里打的Log(Debug.Log)可以在这里看到。
实际上修改了摩擦系数后,现象仍然存在,说明不是摩擦系数的缘故(假设我实现正确)。猜测应该是跳起后碰到墙面时判断为碰撞,将向上运动的速度直接置为了0,那么我们找找看哪里控制上升速度。然后我在KinematicObject里面找到了这段代码:
...
else
{
//We are airborne, but hit something, so cancel vertical up and horizontal velocity.
velocity.x *= 0;
velocity.y = Mathf.Min(velocity.y, 0);
}
...
显然,我们去掉这段就可以了。实际上我们只需要碰墙壁的时候继续保持纵向移动,所以只需要去掉第二行。经测试已经能达到目的了,但是天花板磕脑袋的效果也消失了,显然是因为我们没有判断碰到的是墙壁还是天花板。暂时还不知道怎么区分天花板和墙壁,这个问题就这样吧。
2. 隐藏要素设计不合理
这个比较简单,设置一个弹簧装置和通道,让角色可以弹上出生地。通道其实是背景+物体,可以仿照场景中的隐藏通道来做,也可以直接显示背景。
事实上一条隐藏的死路很有可能就是设计意图,并不是不合理。
3. 加速跑和二段跳
加速跑的关键是按住某个加速按键后,横向速度增加一个随时间衰减的加速度。假设我们以Shift键为加速键,那么我们仿照Jump键的判断,就可以判断Shift键。这里需要做两件事:新增加速按键的定义,以及当加速按下和松开时的逻辑。我们查看Edit->Project Setting->Input,发现预定义的按键已经够用了,left shift按键绑定的名称为Fire3,不需要新增。如果要新增,在Input界面新增按键配置。
// 本段代码未经验证
if (Input.GetButtonDown("Fire3")) {// this is accelerate key
if (!isAcce && acce == 0) {
acce = 50;
isAcce = true;
}
velocity.x += acce * 0.001F;
acce -= 1;
} else if (Input.GetButtonUp("Fire3")){
acce = 0;
isAcce = false;
}
二段跳的关键是判断身处空中以及是否已经进行过二段跳,我们用一个计数器来解决。修改了两处地方,一处是跳跃状态判断, 当空中再次按跳跃键时判断是否满足二段跳条件。另一处是纵向速度计算的条件,当二段跳时无论处于什么速度,再给一个纵向速度。目标完成,代码片段如下:
public bool CanJump() {
return jumpState == JumpState.Grounded ||
jumpState != JumpState.Grounded && jumpCount < 2;
}
protected override void Update() {
...
if (CanJump() && Input.GetButtonDown("Jump")) {
jumpState = JumpState.PrepareToJump;
}
...
}
void UpdateJumpState()
{
jump = false;
switch (jumpState)
{
...
case JumpState.Jumping:
if (!IsGrounded)
{
Schedule<PlayerJumped>().player = this;
collider.sharedMaterial = p1;
jumpState = JumpState.InFlight;
jumpCount += 1;
}
break;
...
case JumpState.Landed:
jumpState = JumpState.Grounded;
jumpCount = 0;
break;
}
}
protected override void ComputeVelocity()
{
if (jump && (IsGrounded || CanJump()))
{
velocity.y = jumpTakeOffSpeed * model.jumpModifier;
jump = false;
}
...
}
- 背景/前景贴图错误
怎么修改现有的背景贴图还没搞明白(Hierarchy里点击Level它不会显示单独的一块砖的属性,在Assets里看了半天,也试着将Assets里的RightTile拖到Scene中但没有效果),这个跟前面区分天花板,墙壁和地面的问题一起留待后续理解。
上面几个问题搞了接近5个小时, 效果还算满意(也遗留了很多疑问,例如地面判断,斜坡/跳台/异形障碍物时如何判断,弹簧效果/阻尼效果如何实现,不过暂时无法解答),就到此为止吧,明天学习下一个官方示例,查看Unity的API文档,顺便回顾一下C#的基本语法。