PlayerController.cs
//PlayerController.cs
using UnityEngine;
/// <summary>
/// 挂Player身上
/// </summary>
public class PlayerController : MonoBehaviour
{
PlayerCharacter character; //声明角色功能脚本
void Start()
{
character = GetComponent<PlayerCharacter>(); //获取
}
void Update()
{
//获取水平和垂直轴输入来进移动
character.Move(Input.GetAxis("Horizontal"), Input.GetAxis("Vertical"));
character.PosLimit(); //位置限制
character.BodyCharacter(); //身体控制
//鼠标左键激活拉伸技能
if (Input.GetMouseButtonDown(0))
character.stretching = true;
character.Pull(); //拉伸
character.PickUp(); //拿起
//鼠标右键放下箱子
if (Input.GetMouseButtonDown(1))
character.PutDown();
}
}
PlayerCharacter.cs
//PlayerCharacter.cs
using UnityEngine;
/// <summary>
/// 挂Player身上
/// </summary>
public class PlayerCharacter : MonoBehaviour
{
Rigidbody rigid; //声明变量:刚体组件
Transform body; //声明变量:身体
Transform hand; //声明变量:手臂
private void Start()
{
//获取刚体组件
rigid = GetComponent<Rigidbody>();//给变量赋初值
//加载图片资源设置主角纹理
Texture image = Resources.Load<Texture>("Image");
GetComponent<MeshRenderer>().material.mainTexture = image; //动态加载网格渲染器MeshRender
//根据名称获取身体并设置成黑色
body = transform.Find("Body");//查找transform的子物体获取body对象
body.GetComponent<MeshRenderer>().material.color = Color.black;
//根据名称获取双臂,从而获取两只手臂,都并设置成黑色
hand = body.Find("Hands");//查找body的子物体获取hand对象,Hands=左手+右手
BoxCollider[] hands = hand.GetComponentsInChildren<BoxCollider>();
foreach (var hand in hands)
{
hand.GetComponent<MeshRenderer>().material.color = Color.black;
}
}
public float moveSpeed;
public void Move(float x, float z) //移动方法
{
x *= Time.deltaTime * moveSpeed;
z *= Time.deltaTime * moveSpeed;
rigid.velocity = new Vector3(x, rigid.velocity.y, z);
}
public float limit_x, limit_z; //限制X和Z轴上的最大移动距离
public void PosLimit() //移动位置限制
{
Vector3 pos = transform.position;
if (pos.x < -limit_x)
pos.x = -limit_x;
else if (pos.x > limit_x)
pos.x = limit_x;
if (pos.z < -limit_z)
pos.z = -limit_z;
else if (pos.z > limit_z)
pos.z = limit_z;
transform.position = pos;
}
public LayerMask layer; //声明一个射线照射层,让射线只能照射到地形
public void BodyCharacter()//上身控制
{
//身体始终保持在小球上方并且锁定x和z轴的旋转
body.position = transform.position + Vector3.up;
body.rotation = new Quaternion(0, body.rotation.y, 0, body.rotation.w);
//从摄像机发射射线到地面,身体始终朝向照射点
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit hit; //声明照射点
if (Physics.Raycast(ray, out hit, 100, layer))
{
Debug.DrawLine(Camera.main.transform.position, hit.point, Color.red);
//获取照射点正上方的坐标,高度同身体一样,让身体朝向该坐标
Vector3 lookTarget = new Vector3(hit.point.x, body.position.y, hit.point.z);
body.LookAt(lookTarget);
}
}
public bool stretching = false; //拉伸技能是否激活
bool stretch = true; //判断伸缩方向,初始为伸展方向
public float maxLength; //最大拉伸距离
public float pullSpeed; //伸缩速度
public void Pull() //手臂拉伸
{
if (stretching)
{
//激活拉伸技能后,手臂变长,达到最大长度则缩短
Vector3 scale = hand.localScale;
if (stretch)
scale.z += Time.deltaTime * pullSpeed;
else
scale.z -= Time.deltaTime * pullSpeed;
//手臂回缩至原有长度,恢复原样,停止拉伸技能
if (scale.z <= 1)
{
scale.z = 1;
stretching = false;
}
//初始状态往前伸展,达到最大长度往回收缩
if (scale.z == 1)
stretch = true;
else if (scale.z >= maxLength)
stretch = false;
hand.localScale = scale;
}
}
Transform box; //声明变量接收箱子
void OnTriggerEnter(Collider other) //触发第一帧
{
//如果空着手施放技能时获取碰到的是箱子,获取它
//之后我们将创建一个Box的脚本挂在箱子身上
//所以这里根据物体身上是否有Box组件来判断该物体是否为箱子
if (!box && stretching && other.GetComponent<Box>())
box = other.transform;
}
public void PickUp() //拿起箱子
{
//如果获取了箱子,手臂立刻回缩,让箱子身位身体的子物体跟随身体移动
if (box)
{
stretch = false;
box.parent = body;
//让被拿取的箱子来到身体前方,并和自己保持同一方向
Vector3 pos = body.position + body.forward * 2;
box.position = Vector3.MoveTowards(box.position, pos, Time.deltaTime * pullSpeed);
box.rotation = Quaternion.Lerp(box.rotation, body.rotation, Time.deltaTime * 5);
}
}
//放下箱子
public void PutDown()
{
//如果手上有箱子,解除父子关系,让box为空
if (box)
{
box.SetParent(null);
box = null;
}
}
}
ColorManage.cs
//ColorManage.cs
using UnityEngine;
/// <summary>
/// 颜色工具类,不用挂
/// </summary>
public class ColorManage
{
public static Color SetColor(int para) //设置自身颜色
{
switch (para) //根据不同参数设置不同颜色
{
case 0:
return Color.red;
case 1:
return Color.yellow;
case 2:
return Color.blue;
default:
return Color.green;
}
}
}
Lampstandard.cs
//Lampstandard.cs
using UnityEngine;
/// <summary>
/// 挂所有灯上
/// </summary>
public class Lampstandard : MonoBehaviour
{
[Range(0, 3)] public int para; //颜色判断参数,范围限定在0~3
Color color; //初始颜色
Material material; //声明子物体材质组件
public bool isBright; //判断灯是否亮起
void Start()
{
//获取初始化颜色
color = ColorManage.SetColor(para);
//自身附上初始化颜色
GetComponent<MeshRenderer>().material.color = color;
//获取子物体的材质
material = transform.GetChild(0).GetComponent<MeshRenderer>().material;
}
void OnTriggerEnter(Collider other) //触发
{
//如果进入的箱子的颜色和自身拥有的颜色相同,亮灯
if (other.GetComponent<MeshRenderer>().material.color == color)
{
isBright = true;
material.color = color;
}
}
void OnTriggerExit(Collider other) //离开触发
{
//如果离开的箱子的颜色和自身拥有的颜色相同,关灯
if (other.GetComponent<MeshRenderer>().material.color == color)
{
isBright = false;
material.color = Color.white;
}
}
}
LightManage.cs
//LightManage.cs
using UnityEngine;
/// <summary>
/// 挂灯柱管理器上
/// </summary>
public class LightManage : MonoBehaviour
{
public Lampstandard[] lights; //声明所有灯
public GameObject againButton; //在编辑器中将按钮物体拖进去
void Awake()
{
lights = transform.GetComponentsInChildren<Lampstandard>();
Time.timeScale = 1; //初始时游戏事件为正常值
}
void Update()
{
//所有灯都亮了,调用过关方法,并暂停游戏
if (AllLightIsBright())
{
againButton.SetActive(true);
Time.timeScale = 0;
}
}
//判断是否所有的灯都亮了
bool AllLightIsBright()
{
//发现一个灯没亮,立刻返回false,如果都没发现,返回true
foreach (var light in lights)
{
if (!light.isBright)
return false;
}
return true;
}
}
CameraFollow.cs
//CameraFollow.cs
using UnityEngine;
/// <summary>
/// 挂主摄像机上
/// </summary>
public class CameraFollow : MonoBehaviour
{
Transform player; //声明主角
public float height, distance; //和主角在Y轴及Z轴上的距离
void Start()
{
//根据名字获取主角
player = GameObject.Find("Player").transform;
}
void Update()
{
//摄像机始终看向主角
Quaternion dir = Quaternion.LookRotation(player.position - transform.position);
transform.rotation = Quaternion.Lerp(transform.rotation, dir, Time.deltaTime);
//始终在主角身后偏上方位置
transform.position = player.position + Vector3.up * height + Vector3.back * distance;
}
}
BottonEvent.cs
//ButtonEvent.cs
using UnityEngine;
using UnityEngine.SceneManagement;
/// <summary>
/// 挂EventSystem上
/// </summary>
public class ButtonEvent: MonoBehaviour
{
//再来一次
public void Again()
{
SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex);
}
}
Box.cs
//Box.cs
using UnityEngine;
/// <summary>
/// 挂所有箱子上
/// </summary>
public class Box : MonoBehaviour
{
[Range(0, 3)] public int para; //颜色判断参数
Rigidbody rigid; //刚体组件
LightManage lightManage; //灯管理器
int index; //索引
void Start()
{
//初始化颜色
GetComponent<MeshRenderer>().material.color = ColorManage.SetColor(para);
//获取刚体
rigid = GetComponent<Rigidbody>();
//获取脚本管理器
lightManage = FindObjectOfType<LightManage>();
//给一个随机索引
index = Random.Range(0, lightManage.lights.Length);
}
Transform parent; //声明父物体
void Update()
{
//获取父物体,判断是否被拿起,为空则寻路,不为空取消物理影响
parent = transform.parent;
if (!parent)
{
Wayfinding();
rigid.isKinematic = false;
}
else
rigid.isKinematic = true;
}
public float moveSpeed; //寻路速度
public float rotateSpeed; //转身速度
void Wayfinding() //寻路
{
//获取随机一个灯的位置,拿到方向,面向该方向前进
Vector3 pos = lightManage.lights[index].transform.position;
Quaternion dir = Quaternion.LookRotation(pos - transform.position);
transform.rotation = Quaternion.RotateTowards(transform.rotation, dir, rotateSpeed * Time.deltaTime);
transform.Translate(0, 0, moveSpeed * Time.deltaTime);
//接近目标索引+1,往下一个灯前进,如果索引超出则为0
if (Vector3.Distance(transform.position, pos) <= 2)
index++;
if (index == lightManage.lights.Length)
index = 0;
}
}