【小沐学Unity3d】Unity播放视频(VideoPlayer组件)

news2024/9/20 10:44:52

文章目录

  • 1、简介
  • 2、脚本播放示例
  • 3、界面播放示例
    • 3.1 2d界面全屏播放
    • 3.2 2d界面部分区域播放
    • 3.3 3d模型表面播放
  • 结语

1、简介

使用视频播放器组件可将视频文件附加到游戏对象,然后在运行时在游戏对象的纹理上播放。

  • 视频播放器 (Video Player) 组件:

在这里插入图片描述

属性功能
Source选择视频源类型。Video Clip:将视频剪辑分配给视频编辑器。使用此字段来定义分配给视频播放器组件的视频剪辑。将视频文件拖放到此字段中,或单击该字段右侧的圆圈,然后从资源列表中选择文件(如果该文件位于 Project 文件夹中)。
Play On Awake勾选 Play On Awake 复选框可在场景启动时播放视频。如果希望在运行时的另一个点触发视频播放,请取消勾选此复选框。此情况下可使用 Play() 命令通过脚本触发视频播放。
Render Mode使用下拉选单来定义视频的渲染方式。Camera Far Plane:在摄像机的远平面上渲染视频。Camera Near Plane:在摄像机的近平面上渲染视频。Render Texture:将视频渲染到渲染纹理中。Material Override:通过游戏对象渲染器的材质将视频渲染到游戏对象的选定纹理属性中。API Only:将视频渲染到 VideoPlayer.texture 脚本 API 属性中。必须使用脚本将纹理分配给其预期目标。

2、脚本播放示例

以下脚本演示了 VideoPlayer 组件的一些功能。

  • (1)在层级树上新建一个空对象

在这里插入图片描述

  • (2)在项目面板通过鼠标右键菜单,新建一个脚本对象,内容如下:
    在这里插入图片描述
// VideoPlayer 函数示例

using UnityEngine;

public class Example : MonoBehaviour
{
    void Start()
    {
        // 将一个 VideoPlayer 附加到主摄像机。
        GameObject camera = GameObject.Find("Main Camera");

        // 将 VideoPlayer 添加到摄像机对象时,
        // 它会自动瞄准摄像机背板,无需更改 videoPlayer.targetCamera。
        var videoPlayer = camera.AddComponent<UnityEngine.Video.VideoPlayer>();

        // Play on Awake 默认为 true。将它设置为 false 以避免下面设置的 URL
        // 自动开始播放,因为我们处于 Start() 状态。
        videoPlayer.playOnAwake = false;

        // 默认情况下,添加到摄像机的 VideoPlayer 将使用远平面。
        // 让我们改为瞄准近平面。
        videoPlayer.renderMode = UnityEngine.Video.VideoRenderMode.CameraNearPlane;

        // 这将使场景通过正在播放的视频可见。
        videoPlayer.targetCameraAlpha = 0.5F;

        // 设置要播放的视频。URL 支持本地绝对或相对路径。
        // 此处使用绝对路径。
        videoPlayer.url = "file:///D:/basketball.mp4";

        // 跳过前 100 帧。
        videoPlayer.frame = 100;

        // 完成后从头重新开始。
        videoPlayer.isLooping = true;

        // 每次到达结尾时,我们都会将播放速度减慢 10 倍。
        videoPlayer.loopPointReached += EndReached;

        // 开始播放。这意味着 VideoPlayer 可能需要做好准备工作(预留
        // 资源、预加载几帧等)。为了更好地控制此项准备工作
        // 带来的延迟,您可以使用 videoPlayer.Prepare() 及其
        // prepareCompleted 事件。
        videoPlayer.Play();
    }

    void EndReached(UnityEngine.Video.VideoPlayer vp)
    {
        vp.playbackSpeed = vp.playbackSpeed / 10.0F;
        Debug.Log("Video: End reached!");
    }
}
  • (3)将上面的脚本对象Example.script挂在上面新建的空对象上。
    在这里插入图片描述
  • (4)点击上面的播放按钮,
    在这里插入图片描述
  • (5)运行如下:
    在这里插入图片描述

注意:URL 源选项会绕过资源管理,这意味着您必须手动确保 Unity 可以找到源视频。例如,一个 Web URL 需要由 Web 服务器托管源视频,而普通文件必须位于 Unity 可以找到该文件的位置(用脚本表示)。但是,如果内容不在 Unity 的直接控制之下,或者您希望避免在本地存储大型视频文件,则此功能非常有用。如果将视频播放器组件源设置为 URL,也可通过 http:// 和 https:// 从 Web 源读取视频。在这些情况下,Unity 会执行必要的预缓冲和错误管理。置于 Unity 的 StreamingAssets 文件夹中的文件可通过视频播放器组件的 URL 选项(见上文)进行使用,也可借助特定于平台的路径 (Application.streamingAssetsPath) 进行使用。

提示:Unity3d 拖拽脚本报错Can’t add the script component “” because the script class cannot be found
报错原因:文件名与文件内容中的类名不相符。c#文件创建以后再改名,会报错找不到对应类。类名和文件名要一致才行。(这个是Unity要求,c#本身不要求一致)

这里提供两段网上的示例脚本如下:

  • VideoScript1.cs:
using UnityEngine;
using UnityEngine.Video;
 
public class VideoScript1 : MonoBehaviour
{
    void Start () {
        var vPlayer = gameObject.AddComponent<VideoPlayer>();
        vPlayer.URL = "https://images.nvidia.cn/cn/youtube-replicates/p7RniXWvYhY.mp4";
        vPlayer.target = UnityEngine.Video.VideoTarget.CameraFrontPlane;
        vPlayer.alpha = 0.8f;
        vPlayer.prepareCompleted += Prepared;
        vPlayer.Prepare();
        Debug.Log("Video: Start!");
    }
 
    void Prepared(VideoPlayer vPlayer)
    {
        Debug.Log("Video: End reached!");
        vPlayer.Play();
    }
}
  • VideoScript2.cs:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Video;
using UnityEngine.UI;
using System;
 
public class VideoScript2: MonoBehaviour {
    //图像
    public RawImage image;
    //播放器
    public VideoPlayer vPlayer;
    public string urlNetWork = "http://www.quirksmode.org/html5/videos/big_buck_bunny.mp4";//网络视频路径
    //播放
    public Button btn_Play;
    //暂停
    public Button btn_Pause;
    //前进
    public Button btn_Fornt;
    //后退
    public Button btn_Back;
    //下一个
    public Button btn_Next;
    //视频控制器
    public Slider sliderVideo;
    //音量控制器
    public Slider sliderSource;
    //音量大小
    public Text text;
    //当前视频时间
    public Text text_Time;
    //视频总时长
    public Text text_Count;
    //音频组件
    public AudioSource source;
    //需要添加播放器的物体
    public GameObject obj;
    //是否拿到视频总时长
    public bool isShow;
    //前进后退的大小
    public float numBer = 20f;
    //时 分的转换
    private int hour, mint;
    private float time;
    private float time_Count;
    private float time_Current;
    //视频是否播放完成
    private bool isVideo;
 
    // Use this for initialization
    void Start () {
        image = obj.GetComponent<RawImage>();
        //一定要动态添加这两个组件,要不然会没声音
        vPlayer = obj.AddComponent<VideoPlayer>();
        source = obj.AddComponent<AudioSource>();
 
        //这3个参数不设置也会没声音 唤醒时就播放关闭
        vPlayer.playOnAwake = false;
        source.playOnAwake = false;
        source.Pause();
 
        //初始化
        Init(urlNetWork);
 
        btn_Play.onClick.AddListener(delegate { OnClick(0); });
        btn_Pause.onClick.AddListener(delegate { OnClick(1); });
        btn_Fornt.onClick.AddListener(delegate { OnClick(2); });
        btn_Back.onClick.AddListener(delegate { OnClick(3); });
        btn_Next.onClick.AddListener(delegate { OnClick(4); });
 
        sliderSource.value = source.volume;
        text.text = string.Format("{0:0}%", source.volume * 100);
        sliderSource.onValueChanged.AddListener(delegate { ChangeSource(sliderSource.value); });
    }
 
    /// <summary>
    ///     初始化VideoPlayer
    /// </summary>
    /// <param name="url"></param>
    private void Init(string url) {
        isVideo = true;
        isShow = true;
        time_Count = 0;
        time_Current = 0;
        sliderVideo.value = 0;
        //设置为URL模式
        vPlayer.source = VideoSource.Url;
        //设置播放路径
        vPlayer.url = url;
        //在视频中嵌入的音频类型
        vPlayer.audioOutputMode = VideoAudioOutputMode.AudioSource;
 
        //把声音组件赋值给VideoPlayer
        vPlayer.SetTargetAudioSource(0, source);
 
        //当VideoPlayer全部设置好的时候调用
        vPlayer.prepareCompleted += Prepared;
        //启动播放器
        vPlayer.Prepare();
    }
 
    /// <summary>
    ///     改变音量大小
    /// </summary>
    /// <param name="value"></param>
    public void ChangeSource(float value) {
        source.volume = value;
        text.text = string.Format("{0:0}%", value * 100);
    }
 
    /// <summary>
    ///     改变视频进度
    /// </summary>
    /// <param name="value"></param>
    public void ChangeVideo(float value) {
        if (vPlayer.isPrepared)
        {
            vPlayer.time = (long)value;
            Debug.Log("VideoPlayer Time:"+vPlayer.time);
            time = (float)vPlayer.time;
            hour = (int)time / 60;
            mint = (int)time % 60;
            text_Time.text = string.Format("{0:D2}:{1:D2}", hour.ToString(), mint.ToString());
        }
    }
 
    private void OnClick(int num) {
        switch (num)
        {
            case 0:
                vPlayer.Play();
                Time.timeScale = 1;
                break;
            case 1:
                vPlayer.Pause();
                Time.timeScale = 0;
                break;
            case 2:
                sliderVideo.value = sliderVideo.value + numBer;
                break;
            case 3:
                sliderVideo.value = sliderVideo.value - numBer;
                break;
            case 4:
                vPlayer.Stop();
                Init(Application.streamingAssetsPath + "/EasyMovieTexture.mp4");
                break;
            default:
                break;
        }
    }
     
    // Update is called once per frame
    void Update ()
    {
        if (vPlayer.isPlaying && isShow)
        {
            //把图像赋给RawImage
            image.texture = vPlayer.texture;
            //帧数/帧速率=总时长    如果是本地直接赋值的视频,我们可以通过VideoClip.length获取总时长
            sliderVideo.maxValue = vPlayer.frameCount/vPlayer.frameRate;
 
            time = sliderVideo.maxValue;
            hour = (int)time / 60;
            mint = (int)time % 60;
            text_Count.text = string.Format("/  {0:D2}:{1:D2}", hour.ToString(), mint.ToString());
 
            sliderVideo.onValueChanged.AddListener(delegate { ChangeVideo(sliderVideo.value); });
            isShow = !isShow;
        }
 
        if (Mathf.Abs((int)vPlayer.time - (int)sliderVideo.maxValue) == 0)
        {
            vPlayer.frame = (long)vPlayer.frameCount;
            vPlayer.Stop();
            Debug.Log("播放完成!");
            isVideo = false;
            return;
        }
        else if (isVideo && vPlayer.isPlaying)
        {
            time_Count += Time.deltaTime;
            if ((time_Count - time_Current) >= 1)
            {
                sliderVideo.value += 1;
                Debug.Log("value:" + sliderVideo.value);
                time_Current = time_Count;
            }
        }
    }
 
    private void FixedUpdate()
    {
 
    }
 
    void Prepared(VideoPlayer player) {
        player.Play();
    }
}

Unity5.6提供了多种生成Video Player控件的方式:

1、新建一个空白的Video Player:选择菜单栏的GameObject->Video->Video Player或者在Hierarchy面板上选择Create->Video->Video Player或者右击Hierarchy面板空白处选择Video->Video Player。
2、直接将导入的VideoClip拖入场景或者Hierarchy面板,生成的VideoPlayer控件的VideoClip将会自动被赋值,如果场景中存在MainCamera,Camera也会被自动赋值为MainCamera。
3、将导入的VideoClip拖动到场景中的Camera物体上,生成的VideoPlayer控件的VideoClip和MainCamera将会自动被赋值,模式默认选择Camera Far Plane。
4、将导入的VideoClip拖动到场景中的2D或者3D物体上,生成的VideoPlayer控件的VideoClip和Renderer将会自动被赋值,模式默认选择Material Override。
5、将导入的VideoClip拖动到场景中的UI物体上,生成的VideoPlayer控件的VideoClip将会自动被赋值,模式默认选择Render Texture。

VideoPlayer的脚本控制与AudioSource相似,有常规的Play,Pause,Stop方法,也有用于进度控制的time,isPlaying,isLooping,frame,frameCount等属性。
VideoPlayer可以使用一系列事件来监听播放的各个动作:

errorReceived: 错误监听到时被执行。
frameDropped :有丢帧发生时被执行。
frameReady :新的一帧准备好时被执行。
loopPointReached :播放结束或播放到循环的点时被执行。
prepareCompleted :视频准备完成时被执行。
seekCompleted :查询帧操作完成时被执行。
started:在Play方法调用之后立刻调用。

3、界面播放示例

3.1 2d界面全屏播放

  • (1)在层级树上鼠标右键新建一个视频播放对象如下:

在这里插入图片描述

  • (2)设置视频对象的参数
    在这里插入图片描述
    Source:设置视频源,Video Clip或URL。这里使用Video Clip,它的视频资源在项目面板的Assets里面需要提前配置好相关视频资源。
    Render Mode:这里设置为在主相机上播放视频。

  • (3)新建一个脚本对象,绑定在视频播放对象上(当然也可以绑定在其他对象上),用来监控视频播放过程的事件。
    在这里插入图片描述

Example2.cs:

using UnityEngine;
using UnityEngine.Video;

public class Example2 : MonoBehaviour
{
    public VideoPlayer vPlayer;

    void Awake()
    {
        vPlayer = GetComponent<VideoPlayer>();
        Debug.Log("Video: Awake";
    }

    void Start()
    {
        vPlayer.loopPointReached += VideoEnd;

        vPlayer.Play();//播放视频
        //vPlayer.Pause();//暂停视频
        //vPlayer.Stop();//停止视频
        //vPlayer.playbackSpeed = 1;//播放速度
        Debug.Log("Video: Start";
    }

    void Update()
    {
        Debug.Log("Video: Frame " + vPlayer.frame);
    }

    /// <summary>
    /// 监听视频是否播放结束,结束时调用
    /// </summary>
    /// <param name="vp"></param>
    void VideoEnd(VideoPlayer vp)
    {
        Debug.Log("爱看书的小沐:视频播放结束");
        Vp.Play();//重新播放视频
    }
}

点击系统的播放按钮运行如下:
在这里插入图片描述

3.2 2d界面部分区域播放

在2D界面播放视频和在3D游戏体上播放,原理及代码是一样的,区别是要把Mesh组件换成RawImage,然后VideoPlayer的RenderMode选项选择RenderTexture或者其他选项。

这里需要把RenderMode 渲染模式改为 Rendertexture ,Canvas画布下创建 RawImage , 在Project 视图下创建 RenderTexture,将RenderTexture 拖入RawImage 的Texture中。

(1)新建一个视频播放对象,并改名为“小沐视频播放”。
在这里插入图片描述

(2)在层级树上,新建一个raw image对象
在这里插入图片描述
新建之后在Canvas下面出现一个RawImage节点。
在这里插入图片描述
修改RawImage在屏幕上的位置;
在这里插入图片描述

(3)Project 视图下创建 RenderTexture。它的属性可以保持默认,不修改。
在这里插入图片描述
(4)修改上面的RawImage对象的属性。将Texture属性关联上面新建的RenderTexture对象。
在这里插入图片描述
(4)修改上面的视频播放对象的属性。将Target Texture属性关联上面新建的RenderTexture对象。
在这里插入图片描述
(5)点击系统的播放按钮运行如下:
在这里插入图片描述

3.3 3d模型表面播放

  • (1)新建一个视频播放对象,如上。

  • (2)新建一个立方体对象,如下
    在这里插入图片描述

  • (3)修改视频对象的属性:
    设置视频源:Source
    设置渲染目标:Render Mode修改为Material Override,同时将Renderer修改为Cude(上面新建的立方体对象)。
    在这里插入图片描述

  • (4)预览如下:
    在这里插入图片描述
    如果想在立方体的某一个面上播放的话,方法如下:

  • (5)在Cude对象下面新建一个网格对象Quad.
    在这里插入图片描述

  • (6)并在三维空间中调整网格对象的位置,相对立方体。
    在这里插入图片描述

  • (7)修改视频对象的属性:
    将Renderer的值修改为网格对象Quad.
    在这里插入图片描述

  • (8)预览如下:
    在这里插入图片描述

结语

如果您觉得该方法或代码有一点点用处,可以给作者点个赞,或打赏杯咖啡;╮( ̄▽ ̄)╭
如果您感觉方法或代码不咋地//(ㄒoㄒ)//,就在评论处留言,作者继续改进;o_O???
如果您需要相关功能的代码定制化开发,可以留言私信作者;(✿◡‿◡)
感谢各位大佬童鞋们的支持!( ´ ▽´ )ノ ( ´ ▽´)っ!!!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/709209.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Java实现OpenAI 模型训练(fine-tune)

本文章介绍如何用java实现OpenAI模型训练&#xff0c;仅供参考 提前准备工作 OpenAI KEY&#xff0c;获取方式可自行百度需要自备VPN 或 使用国外服务器转发需要训练的数据集&#xff0c;文章格式要求为JSONL&#xff0c;格式内容详见下图&#xff08;尽量不要低于500个问答&…

openai

⭐作者介绍&#xff1a;大二本科网络工程专业在读&#xff0c;持续学习Java&#xff0c;努力输出优质文章 ⭐作者主页&#xff1a;逐梦苍穹 ⭐所属专栏&#xff1a;人工智能。 目录 1、简介2、如何实现3、api文档 1、简介 OpenAI 提供了一个名为 OpenAI API 的库&#xff0c;用…

npm构建vite项目

基础环境 npm init vitelatest 依次输入项目名称、使用框架、使用语言。 生成的项目 进入目录&#xff0c;安装依赖&#xff0c;启动项目。 cd 0702_demo01npm installnpm run dev

网络安全进阶学习第四课——SSRF服务器请求伪造

文章目录 一、什么是SSRF&#xff1f;二、SSRF成因三、SSRF简析四、PHP存在SSRF的风险函数五、后台源码获取方式六、SSRF危害七、SSRF漏洞挖掘从WEB功能上寻找&#xff0c;从URL关键字中寻找 八、SSRF具体利用ssrf常利用的相关协议PHP伪协议读取文件端口扫描 九、SSRF存在的必要…

架构分层方法指导

在《不过时的经典层架构》里讲了经典的四层架构怎样对易变性做封装。咱们实际项目中&#xff0c;如果没有足够的实践和关键性思考&#xff0c;还是很可能使用名义上科学的分类理论&#xff0c;却在按照功能进行架构分层。今天咱们就通过一些简单的指导来尽量减少这种风险。 四问…

LeetCode 75 —— 70. 爬楼梯

LeetCode 75 —— 70. 爬楼梯 一、题目描述&#xff1a; 假设你正在爬楼梯。需要 n 阶你才能到达楼顶。 每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢&#xff1f; 示例 1&#xff1a; 输入&#xff1a;n 2 输出&#xff1a;2 解释&#xff1a;有两种方法…

机器学习笔记 - 基于OpenCV和Vantage-point tree构建图像哈希搜索引擎

一、关于图像哈希 上一篇文章中,了解到了图像哈希是使用算法为图像分配唯一哈希值的过程。在深度学习普及之前,一些搜索引擎使用散列技术来索引图像。 言外之意目前的图像搜索引擎主要都是基于深度学习的技术,不过思路都是一样的,我们这里基于OpenCV提供的图像哈希技术构建…

python实现削苹果小游戏

也不用998只有199源码发你。 支付完发我邮箱发你源代码。

RISC-V处理器的设计与实现(三)—— 上板验证(基于野火征途Pro开发板)

文章目录 RISC-V处理器的设计与实现&#xff08;一&#xff09;—— 基本指令集_Patarw_Li的博客-CSDN博客 RISC-V处理器的设计与实现&#xff08;二&#xff09;—— CPU框架设计_Patarw_Li的博客-CSDN博客 RISC-V处理器的设计与实现&#xff08;三&#xff09;—— 上板验…

Gradle安装与配置(8.2)

一、下载地址 https://gradle.org/releases/ https://downloads.gradle.org/distributions/gradle-8.2-bin.zip 解压后放到合适的位置 二、配置环境变量并测试 D:\ProgramFiles\gradle-8.2\bin gradle -v 三、配置镜像 D:\ProgramFiles\gradle-8.2\init.d init.gradle&…

算法第36天:数组中出现次数超过一半的数字【摩尔投票法】

算法介绍 摩尔投票法&#xff1a;求众数的方法。 就是维护一个集合&#xff0c;然后我们遍历我们的数组&#xff0c;假如现在我们遍历到的数为x&#xff0c;当集合中都是x的话我们就将x放入集合中&#xff0c;如果我们遍历到的数为x&#xff0c;但是集合中有y&#xff0c;那么…

【VulnHub系列】West-Wlid1.1

实验信息 Kali&#xff1a;192.168.10.106 WestWild&#xff1a;192.168.104 实验过程 通过arp-scan查找目标主机&#xff0c;确定目标主机IP192.168.10.104 sudo arp-scan --interface eth0 192.168.10.0/24 探测靶机开放的端口 sudo nmap -sT --min-rate 10000 -p- 192.1…

Redis的持久化机制(1)

RDB&#xff0c;即Redis DataBase的简称。RDB是Redis默认的持久化机制 RDB持久化文件&#xff0c;速度比较快&#xff0c;而且存储的是一个二进制的文件&#xff0c;传输起来很方便 在指定的时间间隔内&#xff0c;将内存中的数据集的快照写入磁盘。默认保存在/usr/local/bin目…

122.【SpringBoot - 再刷 - 基础入门 - 01】

SpringBoot2 核心技术 (一)、SpringBoot核心技术入门1.Spring能做什么?1.1、Spring 的能力1.2、Spring的生态1.3、Spring5重大升级1.3.1、响应式编程1.3.2、内部源码设计 2.为什么用SpringBoot2.1、SpringBoot优点2.2、SpringBoot缺点 3.时代背景3.1、微服务3.2、分布式的困难…

github克隆代码加速

https://www.gitclone.com/gogs/ 只需要在正常的git clone后的URL里&#xff0c;嵌入gitclone.com即可快速clone 举例&#xff1a; #原地址 git clone https://github.com/SpringSource/Spring-framework #新地址 git clone https://gitclone.com/github.com/SpringSource/…

2023年出货量预计增长75%,谁在领跑规模化量产赛道?

2023年将成为一个分水岭&#xff0c;中国智能驾驶市场已经进入了下一个竞争周期&#xff0c;卷&#xff0c;难 成为了智驾赛道新的关键词&#xff0c;对各赛道的供应商来说&#xff0c;未来几年将是比拼规模化与降本。 对各级供应商来说&#xff0c;产品规模化量产&#xff0c…

【二叉树part07】| 530.二叉搜索树的最小绝对差、501.二叉搜索树中的众数、236.二叉树的最近公共祖先

目录 &#x1f388;LeetCode530.二叉搜索树的最小绝对差 &#x1f388;LeetCode501.二叉搜索树中的众数 &#x1f388;LeetCode236.二叉树的最近公共祖先 &#x1f388;LeetCode530.二叉搜索树的最小绝对差 链接&#xff1a;530.二叉树的最小绝对差 给你一个二叉搜索树的根…

主成分分析系列(二)为什么特征向量是主成分

在主成分分析系列&#xff08;一&#xff09;概览及数据为何要中心化这篇文章中介绍了PCA算法的大概想法及数据为何要中心化&#xff0c;在这篇文章具体推导PCA算法的过程。 1. 首先 PCA 最原始的想法是&#xff1a; 设 V \mathbf{V} V 为 d {d} d 维 线性空间&#xff08;即…

python项目导入导出依赖包

1. 导出所有依赖包 进入项目路径&#xff0c;执行以下命令&#xff1a; pip freeze > requirements.txt然后在当前目录是可以看到生成“requirements.txt”文件&#xff0c;可以打开看看&#xff0c;会发现有很多个包信息&#xff0c;其实这里是把你当前python环境的所有包…

如何编写一个含有抄底信号的副图指标

如果你作为通达信软件源代码的程序维护员&#xff0c;如何编写一个含有抄底提示的副图指标&#xff1f;请看下面的的示例教程。(python语言) python # 导入所需的库 import talib # 计算移动平均线 def moving_average(data, period): ma talib.SMA(data, timeperiodperio…