是跟着Siki上的网站进行的,整理思路,原网址如下:
http://www.sikiedu.com/course/78 点击打开链接
打开课程的素材,只有两张图,即圆圈和针棒:
可以把Image文件夹整个拖到Project-Assets下,除此之外在这里再create几个folder:
Scene:存放场景,这个游戏就只有main场景一个
Prefabs:存放“预设”,在Unity3D的工程建设中,Prefabs(预设)是最非常用的一种资源类型,是一种可被重复使用的游戏对象。 特点1:它可以被置入多个场景中,也可以在一个场景中多次置入。 特点2:当你在一个场景中增加一个Prefabs,你就实例化了一个Prefabs。这里将要存入组合好的带圆圈的针
Scripts:存放C#脚本,处理游戏中组件的属性、操作等
设置一个mainCamara;拖入圆,调节大小,调为黑色,作为“被插针”的圆;添加Canvas下面的Text也就是UI->Text,记录分数;添加两个位置,起始位置和生成位置,分别表示屏幕上点击之前针的位置和屏幕外游戏中实例化针的位置;然后添加GameManager处理整个游戏的逻辑
对Circle的处理
调节成黑色;居中(x坐标为0);调节合适的大小,添加旋转的运动:也就是在Scripts下新建C#脚本RotateSelf,并拖拽到Circle的属性中;打开后在update()函数中添加旋转的代码:
void Update () {
transform.Rotate(new Vector3(0, 0, -speed*Time.deltaTime));
}
这里的update函数在打开之初就有,每帧执行一次;
transform是unity组件,每个游戏对象都有组件,transition下常见的属性包括position(组件位置)、parent(组件父级)等用来描述物体的各种属性
transform.Rotate()为旋转物体的函数,参数为一个vector3也就是三维向量x,y,z,这里围绕Z轴旋转;而Time类包下面的一个重要重要的类变量deltaTime,它表示距上一次调用Update或FixedUpdate所用的时间。
对Text的处理:
需要调节好大小,这里的单位与圆的单位不一致,要比圆的单位大100倍,所以需要缩小,将其canvas一起缩小,最后拖拽到圆的中心,修改颜色,默认字符可以为0,居中显示
对针的处理:
这里处理完后整体拖入到Prefabs中做预设,就得在这一栏删掉了,窦泽屏幕上凭空多一个
可以先添加针的图片,再加入一个圆,但是把圆放在Pin的下面,这样整个Pin可以作为一个整体。调节针头的大小和颜色,然后移动的合适的位置做针头;针同样要调节到合适的大小和长度,然后可以把整个Pin拖到prefabs中作为一个预设,后面不断实例化和使其运动就可以了。其中这个circle针头的Add component中要添加Circle colider2D 和Rigidbody2D两个组件(搜索即可),是为了之后做碰撞检测。其中Circle colider2D中要勾选IsTrigger使得碰撞后还能继续做处理;Rigidbody2D里gravity要设为0,否则针头就会离针而去啦!
当然还得添加PinHead脚本(scripts文件夹下),才能具体的处理针头碰撞。另外在针头添加Tag PinHead以区分大圆做碰撞处理,需要Add tag之后再次选择,然后apply应用
在PinHead脚本中,添加下面的函数:
private void OnTriggerEnter2D(Collider2D collision)
{
if(collision.tag=="PinHead")
GameObject.Find("GameManager").GetComponent().GameOver();
}
Gameobject是一个类型,所有的游戏物件都是这个类型的对象,是由component组成的;GameObject.find()通过名字来查找场景中的游戏对象,找到里面的GameManager组件下面的GameOver()方法;其中GameManager也是在Scripts下面添加的脚本文件,掌控整个游戏逻辑,里面会有涉及到游戏结束的函数,这里针头碰撞时要调用,可想而知,GameOver()是public的
整个针也有脚本Pin,需要控制针的运动;使其插上后一起跟圆旋转,Pin中的变量和函数,核心就两个函数
public float speed = 20;//针移动的速度
private bool isFly = false;//针是否在从起始点到圆的过程中
private bool isReach = false;//针是否实例化后到达了屏幕起始位置
private Transform startPoint;//屏幕上点击之前针的位置
private Transform circle;//获取组件大圆
private Vector3 targetCirclePosition;//由于不是插到圆心位置,需要另求目标位置
// Use this for initialization
void Start () {
startPoint = GameObject.Find("StartPosition").transform;
circle = GameObject.Find("Circle").transform;
targetCirclePosition = circle.position;
targetCirclePosition.y -= 1.55f;//这里是理想碰撞下圆的y坐标和针的y坐标的差,也就是目标的插入位置
}
///
/// 从起始点到插入,具体的移动见Update
///
public void StartFly()
{
isFly = true;
isReach = true;
}
// Update is called once per frame
void Update () {
if(isFly == false)
{
if(isReach==false)
{//这一段是从屏幕外的生成位置,到屏幕上的开始位置,参数:当前位置,目标位置,速度
transform.position= Vector3.MoveTowards(transform.position, startPoint.position, speed * Time.deltaTime);
if (Vector3.Distance(transform.position, startPoint.position) < 0.05f)//计算距离
isReach = true;//已到达起始位置
}
}
//从屏幕起始位置移动到圆
else
{
transform.position = Vector3.MoveTowards(transform.position, targetCirclePosition, speed * Time.deltaTime);
if(Vector3.Distance(transform.position,targetCirclePosition)<0.05f)
{
transform.position = targetCirclePosition;
transform.parent = circle;//这样就会和圆一起rotate
isFly = false;
}
}
}
GameManager
这里要拖入GameManager脚本,这个脚本就是和其他脚本的图标不一样QAQ
这个脚本主要是实例化针;响应鼠标点击事件;记录修改游戏得分;处理碰撞后游戏结束事件
其中实例化针:
//生成针:在spawnpoint位置实例化
void SpawnPin()
{
currentPin= GameObject.Instantiate(pinPrefab, spawnPoint.position, pinPrefab.transform.rotation).GetComponent();
}
其中pinPrefab是public 的GameObject类型的对象,可以拖拽赋值为之前保存的预设;
开始函数,初始化获取参数,生成针:
void Start()
{
//获取具体位置
startPoint = GameObject.Find("StartPosition").transform;
spawnPoint = GameObject.Find("SpawnPoint").transform;
mainCamera = Camera.main;//主相机
SpawnPin();
animationSpeed = 3;//不在这里初始化可能会被初始化为0
}
Update随时响应鼠标点击事件:
// Update is called once per frame
void Update()
{
if (isGameOver) return;//游戏结束不响应鼠标点击了
//鼠标点击事件
if(Input.GetMouseButtonDown(0))
{
currentPin.StartFly();//从起始位置向上
score++;//更新分数
scoreText.text = score.ToString();
SpawnPin();//重新实例化针
}
}
GameOver处理函数:
public void GameOver()
{
if (isGameOver) return;
GameObject.Find("Circle").GetComponent().enabled = false;//停止旋转
StartCoroutine(GameOverAnimation());//游戏结束动画,自己另写一个协程
isGameOver = true;
}
GameOver动画,将主相机的背景色渐变,大小渐变:
IEnumerator GameOverAnimation()
{
while(true)
{
//lerp()进行差值计算。背景色和大小都线性变化
mainCamera.backgroundColor = Color.Lerp(mainCamera.backgroundColor, Color.red, animationSpeed* Time.deltaTime);
mainCamera.orthographicSize = Mathf.Lerp(mainCamera.orthographicSize, 4, animationSpeed * Time.deltaTime);
Debug.Log(animationSpeed);
if (Mathf.Abs(mainCamera.orthographicSize - 4) < 0.01f) break;
yield return 0;//每次暂停一帧
}
yield return new WaitForSeconds(0.2f);//动画暂停0.5秒
SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex);//重新加载场景
}
unity协程是一个能暂停执行,暂停后立即返回,直到中断指令完成后继续执行的函数。
它类似一个子线程单独出来处理一些问题,性能开销较小,但是他在一个MonoBehaviour提供的主线程里只能有一个处于运行状态的协程。
效果如图:
这样就好啦
正常的游戏效果: