Unity Web前端研究

 

 

原址:http://blog.csdn.net/libeifs/article/details/7200630

 

开发环境

Window7

Unity3D  3.4.1

MB525defy Android 2.2.1

        羽化的第二十五篇博客,明天就要启程回家了,所以这应该是本月的最后一篇博客。最近工作还算顺利,只是临近春节放假,大家貌似都很轻松,春节过后杰哥就要离职到别的公司,是羽化在公司唯一的机友,生活方面得到很多照顾,希望杰哥新的一年能工作顺利,万事开心~ ~前几天突然翻起了《灌篮高手》漫画来看,个性鲜明的人物和幽默精彩的故事给我们童年留下很多回忆,再翻来看很自然的融入故事之中,感动很多。最近翻了《索尼克世代》和《天使之王》,前者是曾经和马里奥并驾齐驱的王者,后者是游戏制作的又一次颠覆。天使之王在游戏中无UI概念,基本上和暴雨类似,羽化个人很喜欢这种设计,UI做得越简洁游戏代入感越强,看看PS3的暴雨就知道,交互式电影的手法,扣人心悬的故事,玩起来就是种享受。索尼克系列羽化原来基本没玩过,这作应该算是历代的翻版,,速度感一直是系列的主题,关卡设计十分巧妙,可以一直飞速过关,可玩度极高,这次特效做的相当棒,话说世嘉做游戏感觉真的越来越好了。

这次是羽化最近看Web版的一些心得,很多脚本来自帮助文档,送上一个自己用的小工具脚本,可以在运行时保存和自动保存,最后送上一首《王国之心385/2》版的《Dearly Beloved》

 

本次学习:

1.  Unity Web版

2.  发布的HTML解析

3.  Unity与网页通信

4.  附送Unity编辑模式下自动保存和运行保存小插件


1.Unity Web版

Unity网页版其实有两种,一种是需要Unity插件支持,另一种是即将到来的Unity3.5 Flash版,虽然羽化对Flash方面不是很了解,但也知道Flash从一个开发者角度上来看,是个成功又失败的作品,最近的网页发展趋势也在慢慢脱离Flash,这些只是羽化个人的一些看法,所以不对Flash版抱有太大幻想,所以开始看第一种方式,由于是网页版,必须要通过下载的方式获取资源,这里就会面临两个问题:

1.缓存50M限制:网页版打包一般用AssetBundle,用WWW方法下载,如果你开发的是个小型网页游戏,那么缓存就不是问题,但如果开发的是个大型MMO网游,这个就要考虑一下了, WWW.LoadFromCacheOrDownload是Unity自带的下载写缓存方式,意味着不能通过此方法下载累计超过50M的缓存,但羽化测试结果还不能肯定这么一种说法,所以这里要等游戏放在外部网络的时候在看看,还有一种解决方法就是在Unity官方购买缓存权限,但价格不菲。。。至少个人无法承担。

2.插件本地下载:很多情况下用户并没有Unity Web Player插件,而且这个插件有两种版本,一个是最小版,大概400KB左右,一个是完全版,大概5M左右,前一个版本下载后自动下载后一个版本,所以羽化认为还不如直接下载完全版- - 对于网页游戏来说最不能做的就是让用户等和复杂的安装手段,所以这5M完全版必须想办法放在一个良好的服务器端下载,而不是Unity官网。。。安装最好自动安装,而不是手动安装。。。


2.发布的HTML解析

在Build Settings里面的切换成Web Player后几个勾选作用在帮助文档里面有说明,羽化就不多说,Player Settings里面WebPlayer Template下是网页HTML的打包选择,当然也可以选择用代码打包,但每次修改比较麻烦,这里默认只给了三个选项,可以在Unity\Editor\Data\Resources\WebPlayerTemplates目录下添加自己喜欢的HTML设置,这里可以看到羽化添加的一个设置,具体方法可以看Manual里面的Web Player Deployment

羽化把这个也放在了下载包YUHUA文件夹里面,我们主要看代码:

  1. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">  
  2. <html xmlns="http://www.w3.org/1999/xhtml">  
  3.     <head>  
  4.         <title>Unity Web Player | %UNITY_WEB_NAME%</title>  
  5.         <script type="text/javascript" src="UnityObject.js"></script>  
  6.         <script type="text/javascript">  
  7.         <!--  
  8.         if (typeof unityObject != "undefined")  
  9.         {  
  10.             var params =   
  11.             {  
  12.                 disableContextMenu: true  
  13.             };  
  14.               
  15.             unityObject.enableClickOnceInstall(true);  
  16.             unityObject.enableFullInstall(true);  
  17.             unityObject.enableGoogleAnalytics(false);  
  18.             unityObject.enableJavaInstall(false);  
  19.             unityObject.enableAutoInstall(false);  
  20.               
  21.             if(!checkPlugins("UnityWebPlayer", ""))  
  22.             {  
  23.                 DownLoad();  
  24.             }  
  25.               
  26.             unityObject.embedUnity("unityPlayer", "%UNITY_WEB_PATH%", %UNITY_WIDTH%, %UNITY_HEIGHT%, params,null,function(result)   
  27.             {  
  28.                 if (result.success)   
  29.                 {  
  30.                     var unity = result.ref;  
  31.                     var version = unity.GetUnityVersion("3.x.x");  
  32.                     if(version != "3.4.2f3")   
  33.                     {  
  34.                         alert("Unity Web Player Not New!!" + "\nNow: " + version +  "\nNew: 3.4.2f3");    
  35.                     }  
  36.                       
  37.                     var versionButton = document.getElementById("versionButton");  
  38.                     versionButton.disabled = false;  
  39.                     var sendButton = document.getElementById("sendButton");  
  40.                     sendButton.disabled = false;  
  41.                 }  
  42.                 else   
  43.                 {  
  44.                     alert("Not Install Unity Web Player!");   
  45.                 }  
  46.             });  
  47.             %UNITY_SET_BASE_DOWNLOAD_URL%  
  48.         }  
  49.           
  50.         function checkPlugins(pluginsName, activexObjectName)  
  51.         {  
  52.             if (activexObjectName == "") activexObjectName = pluginsName + "." + pluginsName;  
  53.              
  54.             var np = navigator.plugins;  
  55.             // FF  
  56.             if (np && np.length)   
  57.             {  
  58.                 for(var i = 0; i < np.length; i ++)   
  59.                 {  
  60.                     if(np[i].name.indexOf(pluginsName) != -1)   
  61.                     return true;  
  62.                 }  
  63.                 return false;  
  64.             }  
  65.             // IE  
  66.             else if (window.ActiveXObject)   
  67.             {  
  68.                 try   
  69.                 {  
  70.                     var axobj = eval("new ActiveXObject(activexObjectName);");  
  71.                     return axobj ? true : false;  
  72.                 }   
  73.                 catch (e)   
  74.                 {  
  75.                     return false;  
  76.                 }  
  77.             }   
  78.             else   
  79.             {  
  80.                 return false;  
  81.             }  
  82.         }  
  83.           
  84.         function DownLoad()   
  85.         {  
  86.             run_exe="<OBJECT ID=\"RUNIT\" WIDTH=0 HEIGHT=0 TYPE=\"application/x-oleobject\""  
  87.             run_exe+="CODEBASE=\"UnityWebPlayerFull.exe\">"  
  88.             run_exe+="</OBJECT>"            
  89.               
  90.             document.open();  
  91.             document.clear();  
  92.             document.writeln(run_exe);  
  93.             document.close();  
  94.         }  
  95.           
  96.         function versionButtonClick()   
  97.         {  
  98.             var unity = unityObject.getObjectById("unityPlayer");  
  99.             var version = unity.GetUnityVersion("3.x.x");  
  100.             alert(version);  
  101.         }  
  102.           
  103.         function sendButtonClick()   
  104.         {  
  105.             var unity = unityObject.getObjectById("unityPlayer");  
  106.             unity.SendMessage("GT", "GT", "Hello from Web!");  
  107.         }  
  108.           
  109.         function UnitySend( arg )  
  110.         {  
  111.             alert( arg );  
  112.         }  
  113.         -->  
  114.         </script>  
  115.         <style type="text/css">  
  116.         <!--  
  117.         body {  
  118.             font-family: Helvetica, Verdana, Arial, sans-serif;  
  119.             background-color: white;  
  120.             color: black;  
  121.             text-align: center;  
  122.         }  
  123.         a:link, a:visited {  
  124.             color: #000;  
  125.         }  
  126.         a:active, a:hover {  
  127.             color: #666;  
  128.         }  
  129.         p.header {  
  130.             font-size: small;  
  131.         }  
  132.         p.header span {  
  133.             font-weight: bold;  
  134.         }  
  135.         p.footer {  
  136.             font-size: x-small;  
  137.         }  
  138.         div.content {  
  139.             margin: auto;  
  140.             width: %UNITY_WIDTH%px;  
  141.         }  
  142.         div.missing {  
  143.             margin: auto;  
  144.             position: relative;  
  145.             top: 50%;  
  146.             width: 193px;  
  147.         }  
  148.         div.missing a {  
  149.             height: 63px;  
  150.             position: relative;  
  151.             top: -31px;  
  152.         }  
  153.         div.missing img {  
  154.             border-width: 0px;  
  155.         }  
  156.         div#unityPlayer {  
  157.             cursor: default;  
  158.             height: %UNITY_HEIGHT%px;  
  159.             width: %UNITY_WIDTH%px;  
  160.         }  
  161.         -->  
  162.         </style>  
  163.     </head>  
  164.     <body>  
  165.         <p class="header"><span>Unity Web Player | </span>%UNITY_WEB_NAME%</p>%UNITY_BETA_WARNING%  
  166.         <div class="content">  
  167.             <div id="unityPlayer">  
  168.                 <div class="missing">  
  169.                     <a href="http://unity3d.com/webplayer/" title="Unity Web Player. Install now!">  
  170.                         <img alt="Unity Web Player. Install now!" src="getunity.png" width="193" height="63" />  
  171.                     </a>  
  172.                 </div>  
  173.             </div>  
  174.         </div>  
  175.         <p><input id="versionButton" type="button" value="Version" disabled="disabled" onclick="versionButtonClick();" /></p>  
  176.         <p><input id="sendButton" type="button" value="Send" disabled="disabled" onclick="sendButtonClick();" /></p>  
  177.         <p class="footer">« created with <a href="http://unity3d.com/unity/" title="Go to unity3d.com">Unity</a> »</p>  
  178.     </body>  
  179. </html>  
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
	<head>
		<title>Unity Web Player | %UNITY_WEB_NAME%</title>
		<script type="text/javascript" src="UnityObject.js"></script>
		<script type="text/javascript">
		<!--
		if (typeof unityObject != "undefined")
		{
			var params = 
			{
				disableContextMenu: true
			};
			
			unityObject.enableClickOnceInstall(true);
			unityObject.enableFullInstall(true);
			unityObject.enableGoogleAnalytics(false);
			unityObject.enableJavaInstall(false);
			unityObject.enableAutoInstall(false);
			
			if(!checkPlugins("UnityWebPlayer", ""))
			{
				DownLoad();
			}
			
			unityObject.embedUnity("unityPlayer", "%UNITY_WEB_PATH%", %UNITY_WIDTH%, %UNITY_HEIGHT%, params,null,function(result) 
			{
                if (result.success) 
				{
					var unity = result.ref;
					var version = unity.GetUnityVersion("3.x.x");
					if(version != "3.4.2f3") 
					{
						alert("Unity Web Player Not New!!" + "\nNow: " + version +  "\nNew: 3.4.2f3");	
					}
					
                    var versionButton = document.getElementById("versionButton");
                    versionButton.disabled = false;
					var sendButton = document.getElementById("sendButton");
					sendButton.disabled = false;
                }
				else 
				{
					alert("Not Install Unity Web Player!"); 
				}
            });
			%UNITY_SET_BASE_DOWNLOAD_URL%
		}
		
		function checkPlugins(pluginsName, activexObjectName)
		{
			if (activexObjectName == "") activexObjectName = pluginsName + "." + pluginsName;
		   
			var np = navigator.plugins;
			// FF
			if (np && np.length) 
			{
				for(var i = 0; i < np.length; i ++) 
				{
					if(np[i].name.indexOf(pluginsName) != -1) 
					return true;
				}
				return false;
			}
			// IE
			else if (window.ActiveXObject) 
			{
				try 
				{
					var axobj = eval("new ActiveXObject(activexObjectName);");
					return axobj ? true : false;
				} 
				catch (e) 
				{
					return false;
				}
			} 
			else 
			{
				return false;
			}
		}
		
		function DownLoad() 
		{
			run_exe="<OBJECT ID=\"RUNIT\" WIDTH=0 HEIGHT=0 TYPE=\"application/x-oleobject\""
			run_exe+="CODEBASE=\"UnityWebPlayerFull.exe\">"
			run_exe+="</OBJECT>" 			
			
			document.open();
			document.clear();
			document.writeln(run_exe);
			document.close();
		}
		
		function versionButtonClick() 
		{
            var unity = unityObject.getObjectById("unityPlayer");
            var version = unity.GetUnityVersion("3.x.x");
            alert(version);
        }
		
		function sendButtonClick() 
		{
			var unity = unityObject.getObjectById("unityPlayer");
			unity.SendMessage("GT", "GT", "Hello from Web!");
		}
		
		function UnitySend( arg )
		{
			alert( arg );
		}
		-->
		</script>
		<style type="text/css">
		<!--
		body {
			font-family: Helvetica, Verdana, Arial, sans-serif;
			background-color: white;
			color: black;
			text-align: center;
		}
		a:link, a:visited {
			color: #000;
		}
		a:active, a:hover {
			color: #666;
		}
		p.header {
			font-size: small;
		}
		p.header span {
			font-weight: bold;
		}
		p.footer {
			font-size: x-small;
		}
		div.content {
			margin: auto;
			width: %UNITY_WIDTH%px;
		}
		div.missing {
			margin: auto;
			position: relative;
			top: 50%;
			width: 193px;
		}
		div.missing a {
			height: 63px;
			position: relative;
			top: -31px;
		}
		div.missing img {
			border-width: 0px;
		}
		div#unityPlayer {
			cursor: default;
			height: %UNITY_HEIGHT%px;
			width: %UNITY_WIDTH%px;
		}
		-->
		</style>
	</head>
	<body>
		<p class="header"><span>Unity Web Player | </span>%UNITY_WEB_NAME%</p>%UNITY_BETA_WARNING%
		<div class="content">
			<div id="unityPlayer">
				<div class="missing">
					<a href="http://unity3d.com/webplayer/" title="Unity Web Player. Install now!">
						<img alt="Unity Web Player. Install now!" src="getunity.png" width="193" height="63" />
					</a>
				</div>
			</div>
		</div>
		<p><input id="versionButton" type="button" value="Version" disabled="disabled" οnclick="versionButtonClick();" /></p>
		<p><input id="sendButton" type="button" value="Send" disabled="disabled" οnclick="sendButtonClick();" /></p>
		<p class="footer">« created with <a href="http://unity3d.com/unity/" title="Go to unity3d.com">Unity</a> »</p>
	</body>
</html>


这是羽化改版要对应原版的来看,可以发现打开网页的时候,都会申请去官网下载最新的UnityObject.js,羽化把这个文件放在了本地,并做了一些修改,这样每次部分图片资源都会从本地得到,这个js脚本是Web端的核心,所以官方警告最好不要做修改,但我们是程序员,一般不怕警告。。。下面的UnityObject的方法调用,决定了Unity Web Player的运行状态,具体解释可以看帮助文档,羽化擅自添加了两个功能,一是与Unity通信,可以看到就是一个简单的SendMessage,二是提示下载插件,这也算自动安装的一种,但不算很智能,考虑到浏览器的差异,羽化做了一个决定,把自动安装自动下载放到Unity官方去做因为这部分需要解析一个官方的jar文件包暂时无法修改,我们只负责插件提示下载本地化,于是下面的版本检查就产生了,代码上还有部分缺陷,对应IE内核的浏览器没有问题,但火狐和Chrome不支持自动安装,只能本地下载。具体的网页包羽化放在下载的WebPlayer里面。


3. Unity与网页通信

打开WebTest项目里面的脚本GT.js
[javascript] view plain copy print ?
  1. function Awake()  
  2. {  
  3.     Application.runInBackground = true;  
  4. }  
  5.   
  6. function GT(param : String)  
  7. {  
  8.     transform.guiText.text = param;  
  9. }  
  10.   
  11. function Update()  
  12. {  
  13.     Camera.main.transform.RotateAround (Vector3.zero, Vector3.up, 20 * Time.deltaTime);  
  14. }  
  15.   
  16. function OnGUI()  
  17. {  
  18.     if(GUI.Button(Rect(Screen.width - 100,Screen.height/2, 50,50),"Send"))  
  19.     {  
  20.         Application.ExternalCall( "UnitySend""Unity says hello!" );  
  21.     }  
  22.       
  23.     if(GUI.Button(new Rect(Screen.width-120,Screen.height-40,120,30),"Click to YUHUA?"))           
  24.     {        
  25.         Application.ExternalEval  
  26.         (  
  27.             "if(document.location.host != 'blog.csdn.net/libeifs') { document.location='http://blog.csdn.net/libeifs'; }"  
  28.         );    
  29.     }    
  30. }  
function Awake()
{
	Application.runInBackground = true;
}

function GT(param : String)
{
    transform.guiText.text = param;
}

function Update()
{
	Camera.main.transform.RotateAround (Vector3.zero, Vector3.up, 20 * Time.deltaTime);
}

function OnGUI()
{
	if(GUI.Button(Rect(Screen.width - 100,Screen.height/2, 50,50),"Send"))
	{
		Application.ExternalCall( "UnitySend", "Unity says hello!" );
	}
	
 	if(GUI.Button(new Rect(Screen.width-120,Screen.height-40,120,30),"Click to YUHUA?"))         
    {      
    	Application.ExternalEval
		(
    		"if(document.location.host != 'blog.csdn.net/libeifs') { document.location='http://blog.csdn.net/libeifs'; }"
		);  
    }  
}
网页与Unity通信在上面又说,Unity与网页通信就用ExternalCall,指定到网页上的特定方法,而ExternalEval则是添加网页脚本,可以看到羽化把博客的链接部分添加到了网页上。




4. 附送Unity编辑模式下自动保存和运行时保存小插件

包的名字在下载中的YUHUA_SAVE,里面就一个脚本
  1. using UnityEditor;  
  2. using UnityEngine;  
  3. using System.Collections;  
  4.   
  5. public class YUHUA_SAVE : EditorWindow  
  6. {  
  7.     float saveTime = 600;  
  8.     float nextSave;  
  9.     bool AutoSave = false;  
  10.     string sceneName;  
  11.       
  12.     [MenuItem("YUHUA/SAVE")]  
  13.     static public void Init()   
  14.     {  
  15.         YUHUA_SAVE window = (YUHUA_SAVE)EditorWindow.GetWindowWithRect(typeof(YUHUA_SAVE),new Rect(0,0,200,40));   
  16.         window.Show();  
  17.     }  
  18.       
  19.     void OnGUI()   
  20.     {  
  21.         HandleUtility.Repaint();  
  22.           
  23.         if(GUILayout.Button("AutoSave"))  
  24.         {  
  25.             AutoSave = !AutoSave;  
  26.             nextSave = (float)EditorApplication.timeSinceStartup + saveTime;  
  27.         }  
  28.           
  29.         if(AutoSave)  
  30.         {  
  31.             EditorGUILayout.LabelField("Save Each:", saveTime + " Secs");  
  32.             int timeToSave = (int)(nextSave - EditorApplication.timeSinceStartup);  
  33.             EditorGUILayout.LabelField("Next Save:", timeToSave.ToString() + " Sec");  
  34.             this.Repaint();  
  35.   
  36.             if(EditorApplication.timeSinceStartup > nextSave)   
  37.             {  
  38.                 Debug.Log("AutoSave!!!!!!");  
  39.                 string[] path = EditorApplication.currentScene.Split(char.Parse("/"));  
  40.                 path[path.Length -1] = "AutoSave_" + path[path.Length-1];  
  41.                 EditorApplication.SaveScene(string.Join("/",path));  
  42.                 nextSave = (float)(EditorApplication.timeSinceStartup + saveTime);  
  43.             }  
  44.         }  
  45.           
  46.         if(EditorApplication.isPlaying || EditorApplication.isPaused)   
  47.         {  
  48.             if(GUILayout.Button("PlayingSave"))  
  49.             {  
  50.                 EditorPlay();  
  51.             }     
  52.         }  
  53.     }  
  54.       
  55.     void EditorPlay()  
  56.     {  
  57.         Debug.Log("PlayingSave!!!!!!");  
  58.         sceneName = EditorApplication.currentScene;  
  59.         string[] path = sceneName.Split(char.Parse("/"));  
  60.           
  61.         path[path.Length -1] = "Temp_" + path[path.Length-1];  
  62.         string tempScene = string.Join("/",path);  
  63.         EditorApplication.SaveScene(tempScene);  
  64.           
  65.         FileUtil.DeleteFileOrDirectory(sceneName);  
  66.         FileUtil.MoveFileOrDirectory(tempScene, sceneName);  
  67.         FileUtil.DeleteFileOrDirectory(tempScene);  
  68.           
  69.         EditorApplication.SaveScene(sceneName);  
  70.         EditorApplication.OpenScene(sceneName);  
  71.     }  
  72. }  
using UnityEditor;
using UnityEngine;
using System.Collections;

public class YUHUA_SAVE : EditorWindow
{
	float saveTime = 600;
	float nextSave;
	bool AutoSave = false;
	string sceneName;
	
	[MenuItem("YUHUA/SAVE")]
	static public void Init() 
	{
		YUHUA_SAVE window = (YUHUA_SAVE)EditorWindow.GetWindowWithRect(typeof(YUHUA_SAVE),new Rect(0,0,200,40)); 
		window.Show();
	}
	
	void OnGUI() 
	{
		HandleUtility.Repaint();
		
		if(GUILayout.Button("AutoSave"))
		{
			AutoSave = !AutoSave;
			nextSave = (float)EditorApplication.timeSinceStartup + saveTime;
		}
		
		if(AutoSave)
		{
			EditorGUILayout.LabelField("Save Each:", saveTime + " Secs");
			int timeToSave = (int)(nextSave - EditorApplication.timeSinceStartup);
			EditorGUILayout.LabelField("Next Save:", timeToSave.ToString() + " Sec");
			this.Repaint();

			if(EditorApplication.timeSinceStartup > nextSave) 
			{
				Debug.Log("AutoSave!!!!!!");
				string[] path = EditorApplication.currentScene.Split(char.Parse("/"));
				path[path.Length -1] = "AutoSave_" + path[path.Length-1];
				EditorApplication.SaveScene(string.Join("/",path));
				nextSave = (float)(EditorApplication.timeSinceStartup + saveTime);
			}
		}
		
		if(EditorApplication.isPlaying || EditorApplication.isPaused) 
		{
			if(GUILayout.Button("PlayingSave"))
			{
				EditorPlay();
			}	
		}
	}
	
	void EditorPlay()
	{
		Debug.Log("PlayingSave!!!!!!");
		sceneName = EditorApplication.currentScene;
		string[] path = sceneName.Split(char.Parse("/"));
		
		path[path.Length -1] = "Temp_" + path[path.Length-1];
		string tempScene = string.Join("/",path);
		EditorApplication.SaveScene(tempScene);
		
		FileUtil.DeleteFileOrDirectory(sceneName);
		FileUtil.MoveFileOrDirectory(tempScene, sceneName);
		FileUtil.DeleteFileOrDirectory(tempScene);
		
		EditorApplication.SaveScene(sceneName);
		EditorApplication.OpenScene(sceneName);
	}
}
如果一切顺利上方MENU会出现YUHUA->SAVE的菜单,点开后左上角会出现个下图的菜单,有些可能是个看不清的块,拖动到视图里面就会看清,运行后会再多出个Playing Save按钮。很实用的一个小工具,通过官方例子改的,只能在编辑模式下使用,有点小Bug,但不影响功能,可以更改脚本里的saveTime修改自动保存时间间隔。


下载地址:

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值