赞
踩
从Asset Store中获取的prefab⾃带两个控制其移动的脚本以及与移动⽅式相匹配的动画。⽬前来说,⾓⾊移动已经不⽤再编写代码,可以直接使⽤,⽽在之后添加额外功能时再对这部分代码进⾏修改即可。这个实例的主要⽬的是熟悉物理系统,因此摄像机跟随⾓⾊移动也使⽤现成的⼯具来实现。选择主菜单中的Window→Package Manager,待加载完成后选择Cinemachine插件并安装,如图3-16所⽰。
安装完成后会在菜单栏内多出⼀个Cinemachine选项卡,打开它后单击Create 2DCamera以创建⼀个2D虚拟摄像机,如图3-17所⽰。
这个虚拟摄像机组件上有很多可以调整的参数,但这些不必去管,只需要让摄像机跟随⾓⾊移动就可以。把场景中的⾓⾊prefab拖⼊Cinemachine Virtual Camera组件中的Follow栏,如图3-18所⽰。完成后再运⾏游戏,摄像机就可以跟随⾓⾊移动了。
⼩知识
⾼级摄像机功能⼤家应该注意到了,虚拟摄像机组件在跟随⾓⾊移动时并⾮⽣硬地同步移动,⽽是有⼀个平滑的过渡,这只是其最基本的功能。
在第1章中是直接让摄像机作为⾓⾊⼦物体移动,第2章则是编写了⼀个简易的跟随物体移动的脚本。如果是⼀个复杂的3D游戏,可能还会涉及摄像机的视⾓切换、视⾓变化和障碍遮挡等功能,这时再采⽤之前简单的摄像机处理⽅法就很难实现了。
⽽Cinemachine是⼀个能满⾜⼤多数游戏需求的摄像机组件,但是限于书本篇幅,⽆法详细介绍。功能⻬全的摄像机实现起来难度较⾼,不适合在⼊门阶段死磕,可作为后续学习的⼀个重点,如作为3D数学的实践练习。
要想使⽤物理系统实现关卡内的游戏机制,可以从以下3个机制进⾏。
1. 跷跷板
新建⼀个Sprite,然后在SpriteRenderer组件上放⼊合适的精灵图素材,如资源包中的PlatformWhiteSprite,最后将其缩放到合适⼤⼩。由于要与⾓⾊进⾏物理上的交互,因此再添加Box Collider 2D和Rigidbody 2D组件,并且勾选Rigidbody 2D组件“Constraints(物理约束)”中的X、Y选项,如图3-19所⽰。
此时控制⾓⾊跳上去,会发现跷跷板已经完成了。这个平台就像中⼼被钉了⼀个钉⼦⼀样,可以左右倾斜,那么就会有⼀个问题,旋转的⼒矩该怎么调整?结合⽜顿第⼆定律和动量定律可知,⼀个物体的质量越⼤,改变其运动状态越难。因此这⾥只需要适当增加平台的质量和⾓阻尼(AngularDrag)即可,质量和⾓阻尼越⼤,跷跷板就越不容易转动。
将跷跷板调整到⼀个合适的⼿感后修改精灵图的颜⾊以⽰区分,然后再将其制作为预制体。
2. 蹦床
复制⼀份场景中的跷跷板,由于蹦床是不会动的,因此它不再需要刚体了,删除Rigidbody 2D组件即可。然后要做的是修改蹦床的弹⼒,可以通过创建⼀个物理材质来实现。在Project窗⼝中创建⼀个Physics Material 2D(2D物理材质),如图3-20所⽰。
可以看到其上只有两个参数,Friction(摩擦系数)和Bounciness(弹性系数)。修改弹性系数到⼀个合适的值,然后再将物理材质拖曳到蹦床的碰撞体组件的Material属性上(⻅图3-21),最后再换⼀个颜⾊并将其制作成prefab。
⼩提⽰
弹性系数不宜过⼤弹性系数的值⼀般不宜超过0.9,超过1则表⽰反弹⼒会⽐作⽤⼒本⾝还⼤。不考虑阻⼒的情况下⾓⾊就永远停不下来了,这既不符合现实中的物理理念,⼜容易浪费计算资源,进⽽造成各种bug。
3. 秋千
要实现秋千⼀样的效果,⾸先就得有绳索,这⾥使⽤Unity的Joint(关节)组件来实现。新建⼀个精灵,选择⾃带的konb图⽚作为精灵图素材,并添加Rigidbody 2D和HingeJoint 2D组件,如图3-22所⽰。然后将物体命名为Node并复制出若⼲个,个数取决于绳⼦⻓度。然后让节点保持⼀定且统⼀的间距,再向最上⾯的节点的Hinge Joint 2D组件的Connected Rigid Body栏拖⼊第2个节点物体的Rigidbody 2D组件。最后按照上述⽅法使第2个节点连接第3个,第3个连接第4个,以此类推,就好似⼀个锁链⼀样,如图3-23所⽰。
图3-22 添加Rigidbody 2D和Hinge Joint 2D
新建⼀个⻓条状平台精灵作为最后⼀个节点连接的⽬标,要注意给平台添加刚体。由于绳⼦的⼀端应该是固定的,因此将最上⾯的节点的刚体设置为Static。完成后在场景中新建⼀个空物体,把除平台外的所有节点设为其⼦物体,并给空物体起名为String。调整空物体⾓度并镜像复制⼀份,然后将其整个保存为预制体,如图3-24所⽰。
现在游戏中的3个基本机制就完成了,已经⾜以⽤它们制作⼀个关卡,下⼀⼩节再对游戏进⾏⼀些有趣的改动。
跳跃次数重置点
多数平台跳跃类游戏跳跃的⽅式与⼿感都会是开发者关注的重点。⼿感调整这⼀部分的内容⽐较主观且较为烦琐,本书篇幅⼜有限,因此这⾥添加⼀个常⻅的扩展功能:⼆段跳或跳跃次数重置点。这两个功能从原理上来说是⼀回事,都是通过添加变量来控制跳跃的重置,这需要阅读⾓⾊控制部分的代码来确定修改的位置。
(1)修改跳跃条件。
在CharacterRobotBoy上可以找到PlatformerCharacter2D和Platformer2DUserControl两个脚本,通过阅读代码可知整个控制移动部分的代码都在前者⾥,接着就是修改代码以实现需要的功能。额外添加⼀个布尔变量m_JumpReset作为跳跃重置的条件,在⾓⾊触地检测部分添加⼀个对跳跃重置物的检测,使⽤⼀个新的Tag作为其标签。然后在Move⽅法内修改允许跳跃的条件,并把起跳后的m_JumpReset赋值为false。
(2)重置点制作。
新建⼀个Sprite,选择素材⾥的Button图⽚作为精灵图,然后添加⼀个CircleCollider2D组件。添加⼀个新Tag(JumpPoint),并将该物体修改为这个Tag,如图3-25所⽰。
按此⽅法修改完之后测试效果,如果前⾯步骤都对,依然可能会发现在跳跃重置之后的⼆段跳时⼿感会有些奇怪,特别是⾓⾊下落后触碰到重置点时。阅读Move()⽅法内的跳跃相关部分,会发现跳跃的实现⽅式是对刚体添加⼒,⽽⾓⾊在下落时其向下的动量会与跳跃的⼒相抵消,从⽽造成奇怪的⼿感。解决的办法是在跳跃时把⾓⾊沿y轴⽅向的速度置零,修改后的完整代码如下。(代码⼤部分内容是主⾓⾃带的PlatformerCharacter2D脚本,读者可以整体阅读,重点是Move()函数的跳跃部分。
- using System;
- using UnityEngine;
- namespace UnityStandardAssets. _ 2D
- {
- public class PlatformerCharacter2D : MonoBehaviour
- {
- [SerializeField] private float m _ MaxSpeed = 10f;
- [SerializeField] private float m _ JumpForce = 400f;
- [Range(0, 1)] [SerializeField] private float m _ CrouchSpeed = .36f;
- [SerializeField] private bool m _ AirControl = false;
- [SerializeField] private LayerMask m _ WhatIsGround;
- private Transform m _ GroundCheck;
- const float k _ GroundedRadius = .2f;
- private bool m _ Grounded;
- private Transform m _ CeilingCheck;
- const float k _ CeilingRadius = .01f;
- private Animator m _ Anim;
- private Rigidbody2D m _ Rigidbody2D;
- private bool m _ FacingRight = true;
- private bool m _ JumpReset=false;
- private void Awake()
- {
- m _ GroundCheck = transform.Find("GroundCheck");
- m _ CeilingCheck = transform.Find("CeilingCheck");
- m _ Anim = GetComponent<Animator>();
- m _ Rigidbody2D = GetComponent<Rigidbody2D>();
- }
- private void FixedUpdate()
- {
- m _ Grounded = false;
- Collider2D[] colliders = Physics2D.OverlapCircleAll(m_GroundCheck.
- position, k _ GroundedRadius, m _ WhatIsGround);
- for (int i = 0; i < colliders.Length; i++)
- {
- if (colliders[i].gameObject != gameObject)
- {
- if(colliders[i].gameObject.tag=="JumpPoint")
- {
- m _ JumpReset = true;
- Destroy(colliders[i].gameObject);
- }
- else
- {
- m _ Grounded = true;
- }
- }
- }
- m _ Anim.SetBool("Ground", m _ Grounded);
- m _ Anim.SetFloat("vSpeed", m _ Rigidbody2D.velocity.y);
- }
- public void Move(float move, bool crouch, bool jump)
- {
- if (!crouch && m _ Anim.GetBool("Crouch")){
- if (Physics2D.OverlapCircle(m_CeilingCheck.position, k_
- CeilingRadius, m _ WhatIsGround))
- {
- crouch = true;
- }
- }
- m _ Anim.SetBool("Crouch", crouch);
- if (m _ Grounded || m _ AirControl)
- {
- move = (crouch ? move*m _ CrouchSpeed : move);
- m _ Anim.SetFloat("Speed", Mathf.Abs(move));
- m _ Rigidbody2D.velocity = new Vector2(move*m _ MaxSpeed, m
- _
- Rigidbody2D.velocity.y);
- if (move > 0 && !m _ FacingRight)
- {
- Flip();
- }
- else if (move < 0 && m _ FacingRight)
- {
- Flip();
- }
- }
- if ((m _ Grounded||m _ JumpReset) && jump)
- {
- m _ Grounded = false;
- m _ JumpReset = false;
- m _ Anim.SetBool("Ground", false);
- Vector2 resetVelocity = m _ Rigidbody2D.velocity;
- // 这种写法可以保留沿Y轴的正向速度,如果不需要也可以直接改为0
- resetVelocity.y = Mathf.Max(0, resetVelocity.y);
- m _ Rigidbody2D.velocity = resetVelocity;
- m _ Rigidbody2D.AddForce(new Vector2(0f, m _ JumpForce));
- }
- }
- private void Flip()
- {
- m _ FacingRight = !m _ FacingRight;
- Vector3 theScale = transform.localScale;
- theScale.x *= -1;
- transform.localScale = theScale;
- }
- }
- }
伽利略说:“数学是上帝⽤来书写宇宙的⽂字。”这句话⽤在游戏开发领域再合适不过了——游戏引擎这个虚拟的⼩宇宙,就是以纯粹的数学为基础搭建⽽成的。本章就重点来讲解⼀下游戏开发⽅⾯的数学基础,内容有点枯燥,但是⼜必不可少。
以3D游戏为例,原始的3D模型是⼀系列顶点和顶点之间的连接关系,模型制作者将坐标等数据以纯数字形式保存到⽂件⾥,游戏引擎的任务则是将数字转化成模型展现在⽤户⾯前。游戏引擎从模型的原始数据开始,逐步加⼊场景、摄像机、光照等因素,按⼀套标准的流程进⾏计算,最终将模型展现出来,如图4-1所⽰。
在渲染的基本流程中,有很多“坐标系转换”的⼯作。“坐标系转换”有着深刻的数学原理,但从实⽤层⾯来看并不复杂,仅仅是⼀系列向量和矩阵的乘法运算⽽已,如图4-2所⽰。
在3D游戏的“开荒”时代,以《毁灭战⼠》《雷神之锤》为代表的3D游戏将当时最前沿的图形学技术进⾏改造和优化,达成了在⼀秒内渲染数⼗次的⽬标,奠定了现代3D游戏的基础。到了今天,游戏引擎得到了充分的发展,已经不需要再从计算顶点、渲染像素开始从头制作游戏了。
虽然如此,当需要制作⼀款游戏时,依然有很多⾄关重要的问题需要考虑:玩家的输⼊如何转化为⾓⾊的⾏动,⾓⾊的⾏动和动画如何拟合,摄像机如何配合⾓⾊的移动等。这些问题关系到了游戏的⼿感、表现⼒和游戏性。⽽要完美地实现所需要的效果,也需要有完备的数学算法的⽀持。
因此,数学不仅构建了游戏引擎这个⼩宇宙,⽽且要进⼀步填充这个⼩宇宙、创造丰富多彩的世界,依然离不开数学⼯具的⽀持。⽽值得庆幸的是,现在只需要掌握最基本的3D数学知识,如坐标、⽅向、位移和旋转等概念,就⾜以实现⼤部分游戏玩法了。本章会引领读者逐步掌握必要的基础知识,为实践扫平障碍。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。