王者荣耀实时对战服务器Photon之PUN实现摄像机跟随
本节将完成Camera摄像机的跟随角色功能,创建CameraWork脚本,来实现以跟随角色的功能,这个脚本可以通用在不同的角色上。
这个部分和Photon pub网络没有什么关系,只是单纯的CameraWork脚本的功能实现和代码讲解。
Creating the CameraWork Script
1.创建一个名为CameraWork的新C#脚本
2.将CameraWork的内容替换为以下内容:
using UnityEngine;
using System.Collections;
namespace Com.MyCompany.MyGame
{
/// <summary>
/// Camera work. Follow a target
/// </summary>
public class CameraWork : MonoBehaviour
{
#region Public Properties
[Tooltip("The distance in the local x-z plane to the target")]
public float distance = 7.0f;
[Tooltip("The height we want the camera to be above the target")]
public float height = 3.0f;
[Tooltip("The Smooth time lag for the height of the camera.")]
public float heightSmoothLag = 0.3f;
[Tooltip("Allow the camera to be offseted vertically from the target, for example giving more view of the sceneray and less ground.")]
public Vector3 centerOffset = Vector3.zero;
[Tooltip("Set this as false if a component of a prefab being instanciated by Photon Network, and manually call OnStartFollowing() when and if needed.")]
public bool followOnStart = false;
#endregion
#region Private Properties
// cached transform of the target
Transform cameraTransform;
// maintain a flag internally to reconnect if target is lost or camera is switched
bool isFollowing;
// Represents the current velocity, this value is modified by SmoothDamp() every time you call it.
private float heightVelocity = 0.0f;
// Represents the position we are trying to reach using SmoothDamp()
private float targetHeight = 100000.0f;
#endregion
#region MonoBehaviour Messages
/// <summary>
/// MonoBehaviour method called on GameObject by Unity during initialization phase
/// </summary>
void Start()
{
// Start following the target if wanted.
if (followOnStart)
{
OnStartFollowing();
}
}
/// <summary>
/// MonoBehaviour method called after all Update functions have been called. This is useful to order script execution. For example a follow camera should always be implemented in LateUpdate because it tracks objects that might have moved inside Update.
/// </summary>
void LateUpdate()
{
// The transform target may not destroy on level load,
// so we need to cover corner cases where the Main Camera is different everytime we load a new scene, and reconnect when that happens
if (cameraTransform == null && isFollowing)
{
OnStartFollowing();
}
// only follow is explicitly declared
if (isFollowing)
{
Apply ();
}
}
#endregion
#region Public Methods
/// <summary>
/// Raises the start following event.
/// Use this when you don't know at the time of editing what to follow, typically instances managed by the photon network.
/// </summary>
public void OnStartFollowing()
{
cameraTransform = Camera.main.transform;
isFollowing = true;
// we don't smooth anything, we go straight to the right camera shot
Cut();
}
#endregion
#region Private Methods
/// <summary>
/// Follow the target smoothly
/// </summary>
void Apply()
{
Vector3 targetCenter = transform.position + centerOffset;
// Calculate the current & target rotation angles
float originalTargetAngle = transform.eulerAngles.y;
float currentAngle = cameraTransform.eulerAngles.y;
// Adjust real target angle when camera is locked
float targetAngle = originalTargetAngle;
currentAngle = targetAngle;
targetHeight = targetCenter.y + height;
// Damp the height
float currentHeight = cameraTransform.position.y;
currentHeight = Mathf.SmoothDamp( currentHeight, targetHeight, ref heightVelocity, heightSmoothLag );
// Convert the angle into a rotation, by which we then reposition the camera
Quaternion currentRotation = Quaternion.Euler( 0, currentAngle, 0 );
// Set the position of the camera on the x-z plane to:
// distance meters behind the target
cameraTransform.position = targetCenter;
cameraTransform.position += currentRotation * Vector3.back * distance;
// Set the height of the camera
cameraTransform.position = new Vector3( cameraTransform.position.x, currentHeight, cameraTransform.position.z );
// Always look at the target
SetUpRotation(targetCenter);
}
/// <summary>
/// Directly position the camera to a the specified Target and center.
/// </summary>
void Cut( )
{
float oldHeightSmooth = heightSmoothLag;
heightSmoothLag = 0.001f;
Apply();
heightSmoothLag = oldHeightSmooth;
}
/// <summary>
/// Sets up the rotation of the camera to always be behind the target
/// </summary>
/// <param name="centerPos">Center position.</param>
void SetUpRotation( Vector3 centerPos )
{
Vector3 cameraPos = cameraTransform.position;
Vector3 offsetToCenter = centerPos - cameraPos;
// Generate base rotation only around y-axis
Quaternion yRotation = Quaternion.LookRotation( new Vector3( offsetToCenter.x, 0, offsetToCenter.z ) );
Vector3 relativeOffset = Vector3.forward * distance + Vector3.down * height;
cameraTransform.rotation = yRotation * Quaternion.LookRotation( relativeOffset );
}
#endregion
}
}
3.保存脚本
跟随玩家脚本的关键问题是数学知识,如果你刚刚开始使用3d编程,需要有矢量和四元数学的基本了解和认识。
通常,让我们摄像机始终跟随玩家。当你连接并进入到一个拥有玩家的房间时,其他玩家实例上的每个CameraWork脚本都会争取控制“主镜头”,以便它看起来它的角色...我们不想要,我们只想跟随本机用户对应的本机的角色。
一旦我们明确了一个问题,我们只有一个摄像头,但有几个角色实例,我们可以很容易地找到几种方法来解决。
1.仅将CameraWork脚本附加到本地角色身上上。
2.通过关闭和启动CameraWork行为来控制,具体取决于角色是否为本地角色。
3.将CameraWork附加到相机,并注意当场景中有本地角色实例时,仅跟随该实例。
这3个选项并不详尽,可以找到更多的方法,但是在这3个选项中,我们将随意选择第二个。
我们已经拥有了一个公共属性followOnStart,如果我们想在非联网环境中使用它,例如在我们的测试场景中,或者在完全不同的场景中,我们可以设置为true
当在我们基于网络的游戏中运行时,当我们检测到Player是本地角色时,我们将调用OnStartFollowing()的公共方法。这将在“角色预制网络”一章中创建和说明的Script PlayerManager中完成。
不管你有关于Photon产品的问题或者是Photon价格问题或者Photon教程方面的问题或者其他问题都可以联系我们给我我们留言,我们真诚的为您服务。关注我们公众号PhotonServer获取等多新鲜资讯。