【Unity3D】相机

1 简介

        相机用于渲染游戏对象,每个场景中可以有多个相机,每个相机独立成像,每个成像都是一个图层,最后渲染的图层在最前面显示。

        相机的属性面板如下:

  • Clear Flags:设置清屏颜色,Skybox(天空盒)、Solid Color(纯色)、Depth Only(仅深度,画中画效果)、Don't Clear(不渲染);
  • Background:清屏颜色,当 Clear Flags 为 Skybox 或 Solid Color 时,才有 Background;
  • Culling Mask:剔除遮蔽,选择相机需要绘制的对象层;
  • Projection:投影方式,Perspective(透视投影)、Orthographic(正交投影);
  • Field of View:相机视野范围,默认 60°,视野范围越大,能看到的物体越多,看到的物体越小;
  • Clipping Planes:裁剪平面,视锥体中近平面和远平面的位置;
  • Viewport Rect:视口在屏幕中的位置和大小(相对值),以屏幕左下角为原点;
  • Depth:渲染图层深度,用于设置相机渲染图层的显示顺序;
  • Target Texture:将相机画面存储到一个纹理图片(Texture)中。

2 应用

        本节将通过实现小地图案例展示相机的应用。

        1)游戏界面

        2)游戏对象层级结构

        3)Transform 组件参数

        1. 相机 Transform 组件参数

Name Type Position Rotation Scale Viewport Rect
Main Camera Camera (0, 4, -5) (38, 0, 0) (1, 1, 1) (0, 0, 1, 1)
MinimapCamera Camera (0, 0.5, -5) (0, 0, 0) (1, 1, 1) (0.8, 0.7, 0.2, 0.3)

        2. 玩家 Transform 组件参数

Name Type Position Rotation Scale Color/Texture
Player Empty (0, 0.25, -5) (0, 0, 0) (1, 1, 1) #228439FF
Botton Cube (0, 0, 0) (0, 0, 0) (2, 0.5, 2) #228439FF
Top Cube (0, 0.5, 0) (0, 0, 0) (1, 0.5, 1) #228439FF
Gun Cylinder (0, 0, 1.5) (90, 0, 0) (0.2, 1, 0.4) #228439FF
FirePoint Empty (0, 1.15, 0) (0, 0, 0) (1, 1, 1) ——

        补充:Player 游戏对象添加了刚体组件。 

        3. 敌人 Transform 组件参数

Name Type Position Rotation Scale Color/Texture
Enemy1 Empty (7, 0.25, 1) (0, 120, 0) (1, 1, 1) #F83333FF
Enemy2 Enemy (-1, 0.25, 5) (0, 60, 0) (1, 1, 1) #EA9132FF
Enemy3 Enemy (-5, 0.25, -1) (0, -40, 0) (1, 1, 1) #5DC2F4FF

        说明:Enemy1~Enemy3 都是由 Player copy 而来。

        4. 地面和炮弹 Transform 组件参数

Name Type Position Rotation Scale Color/Texture
Plane Plane (0, 0, 0) (0, 0, 0) (10, 10, 10) GrassRockyAlbedo
Bullet Sphere (0, 0.5, -5) (0, 0, 0) (0.3, 0.3, 0.3) #228439FF

        补充:炮弹作为预设体拖拽到 Assets/Resources/Prefabs 目录下,并且添加了刚体组件。

        4)脚本组件

        MainCameraController.cs

using UnityEngine;
 
public class MainCameraController : MonoBehaviour {
	private Transform player; // 玩家
	private Vector3 relaPlayerPos; // 相机在玩家坐标系中的位置
	private float targetDistance = 15f; // 相机看向玩家前方的位置
 
	private void Start() {
		relaPlayerPos = new Vector3(0, 4, -8);
		player = GameObject.Find("Player/Top").transform;
	}
 
	private void LateUpdate() {
		CompCameraPos();
	}
 
	private void CompCameraPos() { // 计算相机坐标
		Vector3 target = player.position + player.forward * targetDistance;
		transform.position = transformVecter(relaPlayerPos, player.position, player.right, player.up, player.forward);
		transform.rotation = Quaternion.LookRotation(target - transform.position);
	}
 
	// 求以origin为原点, locX, locY, locZ 为坐标轴的本地坐标系中的向量 vec 在世界坐标系中对应的向量
	private Vector3 transformVecter(Vector3 vec, Vector3 origin, Vector3 locX,  Vector3 locY,  Vector3 locZ) {
		return vec.x * locX + vec.y * locY + vec.z * locZ + origin;
	}
}

        说明: CameraController 脚本组件挂在 MainCamera 游戏对象上。 

        MinmapCameraController.cs

using UnityEngine;

public class MinimapController : MonoBehaviour {
	private Transform player; // 玩家
	private float height = 12; // 相机离地面的高度
	private bool isFullscreen = false; // 小地图相机是否全屏
	private Rect minViewport; // 小地图视口位置和大小(相对值)
	private Rect FullViewport; // 全屏时视口位置和大小(相对值)
 
	private void Start() {
		player = GameObject.Find("Player/Top").transform;
		minViewport = GetComponent<Camera>().rect;
		FullViewport = new Rect(0, 0, 1, 1);
	}

	private void Update() {
		if (Input.GetMouseButtonDown(0) && IsClickMinimap()) {
			if (isFullscreen) {
				GetComponent<Camera>().rect = minViewport;
			} else {
				GetComponent<Camera>().rect = FullViewport;
			}
			isFullscreen = !isFullscreen;
		}
	}
 
	private void LateUpdate() {
		Vector3 pos = player.position;
		transform.position = new Vector3(pos.x, height, pos.z);
	}

	public bool IsClickMinimap() { // 是否单击到小地图区域
		Vector3 pos = Input.mousePosition;
		if (isFullscreen) {
			return true;
		}
		if (pos.x / Screen.width > minViewport.xMin && pos.y / Screen.height > minViewport.yMin) {
			return true;
		}
		return false;
	}
}

        说明: MinimapController 脚本组件挂在 MinimapCamera 游戏对象上。 

        PlayerController.cs

using UnityEngine;

public class PlayerController : MonoBehaviour {
	private MinimapController minimapController; // 小地图控制器
	private Transform firePoint; // 开火点
	private GameObject bulletPrefab; // 炮弹预设体
	private float tankMoveSpeed = 4f; // 坦克移动速度
	private float tankRotateSpeed = 2f; // 坦克转向速度
	private Vector3 predownMousePoint; // 鼠标按下时的位置
	private Vector3 currMousePoint; // 当前鼠标位置
	private float fireWaitTime = float.MaxValue; // 距离上次开火已等待的时间
	private float bulletCoolTime = 0.15f; // 炮弹冷却时间
 
 	private void Start() {
		minimapController = GameObject.Find("MinimapCamera").GetComponent<MinimapController>();
		firePoint = transform.Find("Top/Gun/FirePoint");
		bulletPrefab = (GameObject) Resources.Load("Prefabs/Bullet");
	}
 
	private void Update() {
		Move();
		Rotate();
		Fire();
	}
 
	private void Move() { // 坦克移动
		float hor = Input.GetAxis("Horizontal");
        float ver = Input.GetAxis("Vertical");
		if (Mathf.Abs(hor) > float.Epsilon || Mathf.Abs(ver) > float.Epsilon) {
			Vector3 vec = transform.forward * ver + transform.right * hor;
			GetComponent<Rigidbody>().velocity = vec * tankMoveSpeed;
			Vector3 dire = new Vector3(hor, ver, 0);
			dire =  dire.normalized * Mathf.Min(dire.magnitude, 1);
		}
	}
 
	private void Rotate() { // 坦克旋转
		if (Input.GetMouseButtonDown(1)) {
			predownMousePoint = Input.mousePosition;
		} else if (Input.GetMouseButton(1)) {
			currMousePoint = Input.mousePosition;
			Vector3 vec = currMousePoint - predownMousePoint;
			GetComponent<Rigidbody>().angularVelocity = Vector3.up * tankRotateSpeed * vec.x;
			predownMousePoint = currMousePoint;
		}
	}
 
	private void Fire() { // 坦克开炮
		fireWaitTime += Time.deltaTime;
		if (Input.GetMouseButtonDown(0) && !minimapController.IsClickMinimap() || Input.GetKeyDown(KeyCode.Space)) {
			if (fireWaitTime > bulletCoolTime) {
				BulletInfo bulletInfo = new BulletInfo("PlayerBullet", Color.red, transform.forward, 10f, 15f);
				GameObject bullet = Instantiate(bulletPrefab, firePoint.position, Quaternion.identity);
				bullet.AddComponent<BulletController>().SetBulletInfo(bulletInfo);
				fireWaitTime = 0f;
			}
		}
	}
}

        说明: PlayerController 脚本组件挂在 Player 游戏对象上。  

        BulletController.cs

using UnityEngine;
using UnityEngine.UI;

public class BulletController : MonoBehaviour {
	private BulletInfo bulletInfo; // 炮弹信息

	private void Start () {
		gameObject.name = bulletInfo.name;
		GetComponent<MeshRenderer>().material.color = bulletInfo.color;
		float lifeTime = bulletInfo.fireRange / bulletInfo.speed; // 存活时间
		Destroy(gameObject, lifeTime);
	}

	private void Update () {
		transform.GetComponent<Rigidbody>().velocity = bulletInfo.flyDir * bulletInfo.speed;
	}

	public void SetBulletInfo(BulletInfo bulletInfo) {
		this.bulletInfo = bulletInfo;
	}
}

        说明:BulletController 脚本组件挂在 Bullet 游戏对象上(代码里动态添加)。   

        BulletInfo.cs

using UnityEngine;

public class BulletInfo {
	public string name; // 炮弹名
	public Color color; // 炮弹颜色
	public Vector3 flyDir; // 炮弹飞出方向
	public float speed; // 炮弹飞行速度
	public float fireRange; // 炮弹射程

	public BulletInfo(string name, Color color, Vector3 flyDir, float speed, float fireRange) {
		this.name = name;
		this.color = color;
		this.flyDir = flyDir;
		this.speed = speed;
		this.fireRange = fireRange;
	}
}

        5)运行效果

猜你喜欢

转载自blog.csdn.net/m0_37602827/article/details/126078998