unity为我们提供了许多人机交互的方式,包括鼠标、键盘、手柄等等,这些具体的设置我们可以通过Edit->ProjectSettings->Input中查看
这里我讲一下鼠标左键的点击,我们点开Fire1
这里Alt Positive Button显示的是mouse 0,表示鼠标左键点击就会有该响应,而且是积极相应,这些可以自己修改
下面我做一个小游戏:
- 用 Plane 或其他物体做地面, tag 为“Finish”
- 点击地面后,出现一个圆形攻击标记,两秒后自动消失。注意:该攻击标记不能挡住点击。
首先我们做一个Terrain,上次我们说过美化的方法,所以我做出了这样子的
进入Inspector,将Tag改为Finish
然后我们制作一个圆形攻击标志,在Assert中创建文件夹Resources->Prefabs,然后创建一个圆柱,将其高度设为0.001(设为0会变成一个黑色圆),拖入Prefabs,然后在当前目录创建Material,给它添加喜欢的颜色,然后再拖入我们的预设,圆形标志就做好了
现在我们考虑如何编写脚本,这里我采用了工厂单例模式。意思很简单,就是有一个脚本在鼠标点击后告诉一个工厂“我需要一个圆形标志,放在哪里”,工厂接到小心以后就先看看自己库存还有没有,有就直接拿给它,否则就创建一个拿给它。因为unity创建一个游戏对象、销毁一个游戏对象会占很大的资源,所以有什么办法可以少生产,少销毁甚至不销毁呢?很简单,把用完的拿回来。那这些库存放哪呢,也在游戏场景中,只是并不在摄像机的视角范围内。
这样我们思路就很清晰了,一个人机交互,并给工厂下达指令的脚本、一个生产、回收的工厂
Factory
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Factory : MonoBehaviour {
private static Factory instance;
public static List<GameObject> free = new List<GameObject>();
public static List<GameObject> used = new List<GameObject>();
public static Factory GetInstance()
{
if (instance == null)
{
instance = new Factory();
}
return instance;
}
public void placeAttackMark(Vector3 position)
{
GameObject t;
if (free.Count == 0) // 空余组中没有多余的,此时需要创建
{
t = Instantiate<GameObject>(Resources.Load<GameObject>("Prefabs/Cylinder"), Vector3.zero, Quaternion.identity);
} else
{
t = free[0];
free.Remove(t);
}
used.Add(t);
t.transform.position = position;
t.AddComponent<disappear>();
}
}
为什么要用static呢,原因很简单,单例模式,整个游戏只需要一个工厂。用了两个List,一个用于表示库存,一个用于记录用过的,以便可以回收。placeAttackMark是作为交互脚本调用的,首先判断是否有库存,有的话把这个调到指定位置,并移到已用记录中,否则直接创造一个。由于要求两秒以后自动消失,我们为每个拿出去的产品添加一个计时器(组件)disappear。
disappear
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class action : Factory { }
public class disappear : action {
private float time = 2;
void Update()
{
time -= Time.deltaTime;
if (time <= 0)
{
transform.position = Vector3.zero;
used.Remove(gameObject);
free.Add(gameObject);
Destroy(this);
}
}
}
当时间到了以后,把这个标记移到我们看不见的地方,再从已用list中删除,同时把它重新加入库存中,完成回收,值得一提的是,要删掉这个组件,不然它会每一帧都运行。
Shot
首先我说一下是如何判断鼠标是否点击到了物体,简单来说,就是以摄像机为原点,朝鼠标点击的位置发出一条射线,如果撞击到了物体就是点击到了这个物体的意思。所以Shot中我们要添加一个摄像机成员,还要一个工厂
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Shot : MonoBehaviour {
private Factory MyFactory;
public GameObject Cam;
// Use this for initialization
void Start ()
{
MyFactory = Factory.GetInstance();
}
// Update is called once per frame
void Update () {
if (Input.GetButtonDown("Fire1"))
{
Vector3 mp = Input.mousePosition;
Camera ca = Cam.GetComponent<Camera>();
Ray ray = ca.ScreenPointToRay(mp);
RaycastHit hit;
if (Physics.Raycast(ray, out hit))
{
if (hit.collider.gameObject.tag.Contains("Finish"))
{
print(mp);
MyFactory.placeAttackMark(hit.point);
}
}
}
}
}
Raycasr(ray, out hit){}的意思就是如果这条射线发生了碰撞就执行以下事件:告诉工厂我要在点击的位置生成一个圆形标志
这样我们就完成了这样一个有(无)趣(聊)的小游戏