推荐阅读
- 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打开文件的代码很简单:
<input type="file" /></input>
那么就可以用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();
/// <summary>
/// 点击Open按钮
/// </summary>
public static void BtnLoadEvent()
{
clickSelectFileBtn();
}
void Start()
{
BtnLoad.onClick.AddListener(BtnLoadEvent);
}
/// <summary>
/// 接收base64字符串
/// </summary>
/// <param name="base64Str"></param>
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;
}
}
/// <summary>
/// 读取图片
/// </summary>
/// <param name="path"></param>
/// <param name="action"></param>
/// <returns></returns>
IEnumerator ReadTexture(string path,UnityAction<Texture> action)
{
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));
}
}
/// <summary>
/// 加载图片
/// </summary>
/// <param name="texture"></param>
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;
}
/// <summary>
/// 读取文本
/// </summary>
/// <param name="path"></param>
/// <param name="action"></param>
/// <returns></returns>
IEnumerator ReadData(string path, UnityAction<string> action)
{
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);
}
}
/// <summary>
/// 加载文本
/// </summary>
/// <param name="text"></param>
void LoadText(string text)
{
showText.text = text;
}
}
注意:
clickSelectFileBtn函数用来调用Js函数,GetBase64函数用来接收数据。
2-3、打包WEBGL后修改
注意:我用的Unity2019.4.9f1版本。高版本打包出来的index.html以及Build里面的文件跟我的不一致,这个后面有空再说如何匹配高版本吧,先用2019版本演示。
打包之后:
修改index.html文件:
<!DOCTYPE html>
<html lang="en-us">
<head>
<meta charset="utf-8">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Unity WebGL Player | Demo_WEBGLLoadFile</title>
<link rel="shortcut icon" href="TemplateData/favicon.ico">
<link rel="stylesheet" href="TemplateData/style.css">
<script src="TemplateData/UnityProgress.js"></script>
<script src="Build/UnityLoader.js"></script>
<script>
var unityInstance = UnityLoader.instantiate("unityContainer", "Build/WEBGL_LoadFile.json", {onProgress: 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));
}
</script>
</head>
<body>
<input type="file" id="files" style="display:none" onchange="fileImport()">
<div class="webgl-content">
<div id="unityContainer" style="width: 960px; height: 600px"></div>
<div class="footer">
<div class="webgl-logo"></div>
<div class="fullscreen" onclick="unityInstance.SetFullscreen(1)"></div>
<div class="title">Demo_WEBGLLoadFile</div>
</div>
</div>
</body>
</html>
代码解释一下:
(1)首先是加了一个<input type="file" id="files" style="display:none" onchange="fileImport()">
用来响应打开文件的操作。
(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和坑,让后来人可以有些参考。 |