推荐阅读
CSDN主页
GitHub开源地址
Unity3D插件分享
QQ群:398291828
小红书
小破站
大家好,我是佛系工程师☆恬静的小魔龙☆,不定时更新Unity开发技巧,觉得有用记得一键三连哦。
一、前言
Unity3D发布的WEBGL程序是不支持直接的I/O操作,所以也就不能直接访问用户电脑的文件。
但是,也是有办法去访问电脑中的文件,打开文件的。
比如情况一:如果知道电脑文件在什么位置、什么名字。
可以参考这篇文章:
【Unity3D小技巧】Unity3D中打包WEBGL后读取本地文件数据
情况二:知道要上传什么类型的文件,但是需要弹出窗口来选择文件并打开。
这篇文章就来讨论一下WEBGL打开Window文件对话框并打开文件后上传文件,显示图片/文本。
二、实现过程
先来看一下效果:
2-1、实现分析
既然Unity3D没办法直接进行I/O操作,但是JavaScript可以进行I/O操作,那是不是就可以让Unity跟JS进行通信,来进行操作。
JavaScript打开文件的代码很简单:
那么就可以用Unity的按钮去调用这个组件,从这个组件中获取到文件流。
OK,理论存在,实践开始。
2-2、Unity3D中做的准备
(1)在Unity的工程中新建Plugins文件夹:
(2)在里面新建WebGl.jslib文件,编辑代码,这个文件是JS与WEBGL交互用的。
详情参照Unity官网:https://docs.unity3d.com/Manual/webgl-interactingwithbrowserscripting.html
文件里面的内容如下:
mergeInto(LibraryManager.library, {
clickSelectFileBtn:function () {console.log("Enter");
clickSelectFileBtn();
},
});
(3)搭建Unity程序:
一个Button用来响应Js函数,一个Image用来显示图片,Text用来显示文本内容。
(3)在Hierarchy视图新建一个Scripts对象(名字需要跟我一样,因为后面要跟js脚本),挂载脚本,脚本名随意:
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Runtime.InteropServices;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.Networking;
using UnityEngine.UI;
public class ReceiveDataHandle : MonoBehaviour
{public Button BtnLoad;
public Image showImg;
public Text showText;
[DllImport("__Internal")]
private static extern void clickSelectFileBtn();
////// 点击Open按钮
///public static void BtnLoadEvent()
{clickSelectFileBtn();
}
void Start()
{BtnLoad.onClick.AddListener(BtnLoadEvent);
}
////// 接收base64字符串
//////public void GetBase64(string base64Str)
{Debug.Log(base64Str);
string[] split = base64Str.Split('|');
if (split[0].Contains("jpg"))
{StartCoroutine(ReadTexture(split[1], LoadImg));
}
else if (split[0].Contains("txt"))
{StartCoroutine(ReadData(split[1], LoadText));
}
else
{Debug.Log("文件格式错误");
return;
}
}
////// 读取图片
////////////IEnumerator ReadTexture(string path,UnityActionaction)
{Debug.Log(path);
UnityWebRequest request = UnityWebRequestTexture.GetTexture(path);
yield return request.SendWebRequest();
if (request.isNetworkError || request.isHttpError)
{Debug.Log(request.error);
}
else
{byte[] imgdata = request.downloadHandler.data;
action(DownloadHandlerTexture.GetContent(request));
}
}
////// 加载图片
//////void LoadImg(Texture texture)
{Sprite ImgSprite = Sprite.Create((Texture2D)texture, new Rect(0, 0, texture.width, texture.height), new Vector2(0.5f, 0.5f));
showImg.sprite = ImgSprite;
}
////// 读取文本
////////////IEnumerator ReadData(string path, UnityActionaction)
{Debug.Log(path);
UnityWebRequest request = UnityWebRequest.Get(path);
yield return request.SendWebRequest();
if (request.isNetworkError || request.isHttpError)
{Debug.Log(request.error);
}
else
{Debug.Log(request.downloadHandler.text);
action(request.downloadHandler.text);
}
}
////// 加载文本
//////void LoadText(string text)
{showText.text = text;
}
}
注意:
clickSelectFileBtn函数用来调用Js函数,GetBase64函数用来接收数据。
2-3、打包WEBGL后修改
注意:我用的Unity2019.4.9f1版本。高版本打包出来的index.html以及Build里面的文件跟我的不一致,这个后面有空再说如何匹配高版本吧,先用2019版本演示。
打包之后:
修改index.html文件:
Unity WebGL Player | Demo_WEBGLLoadFileonProgress: UnityProgress});
function clickSelectFileBtn() {var tempFileLayout = document.getElementById('files');
tempFileLayout.click();
}
function fileImport() {//获取读取我文件的File对象
var selectedFile = document.getElementById('files').files[0];
if (selectedFile != null) {var reader = new FileReader();
reader.readAsDataURL(selectedFile);
reader.onload = function (e) {var base64Str = e.currentTarget.result.substring(e.currentTarget.result.indexOf(',') + 1);
sendMessageToUnity(base64Str);
}
}
}
function sendMessageToUnity(s) {//发送给unity
var file=document.getElementById('files').files[0];
SetFileUrlByDragEnd(file);
}
function SelectFile(){var file=document.getElementById('files').files[0];
SetFileUrlByDragEnd(file);
}
function SetFileUrlByDragEnd(file) {unityInstance.SendMessage("Scripts", "GetBase64", file.name+"|"+URL.createObjectURL(file));
}" _ue_custom_node_="true">Demo_WEBGLLoadFile
代码解释一下:
(1)首先是加了一个用来响应打开文件的操作。
(2)然后用Unity程序的Button响应clickSelectFileBtn函数,去触发这个组件。
(3)添加fileImport去处理打开的文件得到文件流。
(4)获得文件名和文件路径,通过unityInstance.SendMessage("Scripts", "GetBase64", file.name+"|"+URL.createObjectURL(file));传给Unity。
(5)URL.createObjectURL(file)可以获得本地文件的缓存url,直接发给Unity,然后Unity用来加载。
2-4、效果演示
三、后记
如果觉得本篇文章有用别忘了点个关注,关注不迷路,持续分享更多Unity干货文章。
你的点赞就是对博主的支持,有问题记得留言:
博主主页有联系方式。
博主还有跟多宝藏文章等待你的发掘哦:
专栏 | 方向 | 简介 |
---|---|---|
Unity3D开发小游戏 | 小游戏开发教程 | 分享一些使用Unity3D引擎开发的小游戏,分享一些制作小游戏的教程。 |
Unity3D从入门到进阶 | 入门 | 从自学Unity中获取灵感,总结从零开始学习Unity的路线,有C#和Unity的知识。 |
Unity3D之UGUI | UGUI | Unity的UI系统UGUI全解析,从UGUI的基础控件开始讲起,然后将UGUI的原理,UGUI的使用全面教学。 |
Unity3D之读取数据 | 文件读取 | 使用Unity3D读取txt文档、json文档、xml文档、csv文档、Excel文档。 |
Unity3D之数据集合 | 数据集合 | 数组集合:数组、List、字典、堆栈、链表等数据集合知识分享。 |
Unity3D之VR/AR(虚拟仿真)开发 | 虚拟仿真 | 总结博主工作常见的虚拟仿真需求进行案例讲解。 |
Unity3D之插件 | 插件 | 主要分享在Unity开发中用到的一些插件使用方法,插件介绍等 |
Unity3D之日常开发 | 日常记录 | 主要是博主日常开发中用到的,用到的方法技巧,开发思路,代码分享等 |
Unity3D之日常BUG | 日常记录 | 记录在使用Unity3D编辑器开发项目过程中,遇到的BUG和坑,让后来人可以有些参考。 |