You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Unity 3D:实现物体VideoPlayer在主相机播放并关闭/销毁

Unity交互播放视频问题求助

我是Unity编程新手,正在开发一款游戏,需求是:玩家按下F键与物体交互,触发该物体上VideoPlayer组件加载的视频在主相机播放,播放完成后自动关闭。目前实现遇到困难,附上两个C#脚本,恳请帮助。

我的设想是每个交互物体都自带VideoPlayer组件和对应视频,玩家点击不同物体播放不同视频。

Interactable(物体脚本)

public GameObject otherGameObject;
public VideoPlayer videoPlayer;

Outline outline;
public string message;
public UnityEvent onInteractable;

// Start is called before the first frame update
void Start()
{
    //videoPlayer = otherGameObject.GetComponent<VideoPlayer>();
    //var videoPlayer = GetComponent<Camera>().AddComponent<UnityEngine.Video.VideoPlayer>();
    //videoPlayer = GameObject.Find("Cube").GetComponent<VideoPlayer>();
    outline = GetComponent<Outline>();
    DisableOutline();
}

public void Interact()
{
    videoPlayer.Play();
    onInteractable.Invoke();
}

public void DisableOutline()
{
    outline.enabled = false;
}

public void EnableOutline()
{
    outline.enabled = true;
}

PlayerInteraction(玩家脚本)

public class PlayerInteraction : MonoBehaviour
{
    public float playerReach = 3f;
    Interactable currentInteractable;   

    // Update is called once per frame
    public void Update()
    {
        CheckInteraction();
        if(Input.GetKeyDown(KeyCode.F) && currentInteractable != null) 
        {
            currentInteractable.Interact();   
        }
    }

    void CheckInteraction()
    {
        RaycastHit hit;
        Ray ray = new Ray(Camera.main.transform.position, Camera.main.transform.forward);

        //if colliders with anything within player reach
        if(Physics.Raycast(ray, out hit, playerReach))
        {
            if(hit.collider.tag == "Interactable") //if looking at an interactable object
            {
                Interactable newInteractable = hit.collider.GetComponent<Interactable>();
                
                newInteractable.videoPlayer.Play();

                //if there is a currentInteractable and it is not the newInteractable
                if(currentInteractable && newInteractable != currentInteractable)
                {
                    currentInteractable.DisableOutline();
                }

                if(newInteractable.enabled)
                {
                    SetNewCurrentInteractable(newInteractable);
                }
                else //if new interactable is not enabled
                {
                    DisableCurrentInteractable();
                }
            }    
            else //if not an interactable
            {
                DisableCurrentInteractable();
            }
            
        }
        else //if nothing in reach
        {
            DisableCurrentInteractable();
        }
    }

    void SetNewCurrentInteractable(Interactable newInteractable)
    {
        currentInteractable = newInteractable;
        currentInteractable.EnableOutline();
    }

    void DisableCurrentInteractable()
    {
        if(currentInteractable)
        {
            currentInteractable.DisableOutline();
            currentInteractable = null;
        }
    }
}

问题排查与修复方案

1. 核心逻辑错误修复

你的PlayerInteraction脚本中,CheckInteraction方法里直接调用了newInteractable.videoPlayer.Play();——这会导致玩家视线一碰到物体就自动播放,完全跳过了按F键交互的逻辑,直接删除这行代码即可。

2. 视频渲染到主相机的配置

每个交互物体的VideoPlayer组件需要正确设置渲染目标:

  • 选中交互物体的VideoPlayer,将Render Mode设为Camera Far Plane或Camera Near Plane
  • 在Camera选项中拖入主相机对象
  • 勾选Wait For First Frame,避免视频加载前显示黑屏

3. 播放完成自动关闭的实现

修改Interactable脚本,添加视频结束监听:

void Start()
{
    outline = GetComponent<Outline>();
    DisableOutline();
    
    // 绑定视频结束事件
    if(videoPlayer != null)
    {
        videoPlayer.loopPointReached += OnVideoEnd;
        // 默认禁用VideoPlayer,避免初始状态显示
        videoPlayer.enabled = false;
    }
}

void OnVideoEnd(VideoPlayer vp)
{
    vp.enabled = false;
    // 如需恢复操作或隐藏相关UI,可在此添加逻辑
}

public void Interact()
{
    if(videoPlayer != null)
    {
        videoPlayer.enabled = true;
        videoPlayer.Play();
    }
    onInteractable.Invoke();
}

// 销毁时移除监听,防止内存泄漏
void OnDestroy()
{
    if(videoPlayer != null)
    {
        videoPlayer.loopPointReached -= OnVideoEnd;
    }
}

4. VideoPlayer引用的正确赋值

  • 每个交互物体必须挂载VideoPlayer组件,并将对应视频拖入Clip字段
  • 在Interactable脚本的Inspector面板中,直接把物体自身的VideoPlayer拖到videoPlayer变量上,不要用注释里的Find或GetComponent(除非有特殊需求)

5. 额外优化

  • 交互时停止其他正在播放的视频:在PlayerInteraction的F键触发逻辑中,先停止所有播放中的视频,避免多视频重叠
    if(Input.GetKeyDown(KeyCode.F) && currentInteractable != null) 
    {
        // 停止所有正在播放的视频
        var allPlayers = FindObjectsOfType<VideoPlayer>();
        foreach(var player in allPlayers)
        {
            if(player.isPlaying)
            {
                player.Stop();
                player.enabled = false;
            }
        }
        currentInteractable.Interact();   
    }
    
  • 给主相机添加黑色UI面板作为视频背景,防止场景内容透过视频显示

内容的提问来源于stack exchange,提问作者dan_udnas

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 20:44:50