unity 脚步没有继承monobehaviour怎么用startcoroutine 参数

unity3d优化总结29799人阅读
Unity3D(10)
本文太乱,推荐的:
Unity中的coroutine是通过来实现的。官方脚本中到处会看到这样的代码。
yield是什么?
Coroutine是什么?
unity的coroutine程序执行流程怎么那么奇怪?
unity中的coroutine原理是什么,怎么实现的?
使用unity的coroutine需要注意什么问题?
一、yield的在几种语言中的程序执行特性:
& & &Lua中的yield是使得协同函数运行-&挂起并且传递参数给resume。resume使得协同函数挂起-&运行并且传递参数给协同函数。
& & &C#中yield return/break是用于函数查询集合生成器里面的值(类似迭代)返回,并记录当前现场,下次查询时从上一次记录的yield现场处,继续往下执行,直到继续往下执行没有了,那么退出这段yield的逻辑。yield break会终止掉yield迭代逻辑并跳出。
YieldImplementation:
& &1).Caller callsfunction
& &2).Caller requestsitem 按需请求一个元素
& &3).Next itemreturned 返回请求的元素
& &4).Goto step #2
& & Python中的yield expression, 有yield的函数就变成了一个生成器,调用该函数返回的是迭代器对象,用迭代器对象调用next方法(或者循环中会自动调用next方法),才开始执行函数,执行到yield expression处则中断,返回迭代器当前的值,并保留现场,下次调用next则从现场处开始执行,迭代完了就停止了。可以看出Python中的yield和C#中的yield是类似的,用于创建生成器,执行时中断返回迭代器值,并记录现场,下次从现场处继续执行。
& &Unity中的yield就是和C#,python中的类似,因为unity是基于.net框架的,且unity脚本开始是用Boo(Python的一个变种)写的。只是unity中多了coroutine特性类型,和StartCoroutine的coroutine管理类。StartCoroutine不是启动了一个新的线程,而是开启一个协同程序,默认unity所有代码都在一个线程中(thread-vs-startcoroutine.html)。
coroutine语言层面的原理:
在两年前,协程似乎是一个很高级的东西,随后大多数语言或多或少都支持协程。我比较熟悉的有Python的gevent,Lua的coroutine,Go的goroutine。尤其是Lua和Go,语言本身就支持协程。协程也被叫做轻量级线程。通俗点讲就是定义一大堆任务,然后通过一个线程轮着对每个任务都执行一下,协作运行。它的厉害之处在于每运行到一个任务的时候,它都可以从这个任务上一次中断的地方开始运行。在我们一般的印象中,只有操作系统对线程进行调度的时候才会干这样的事情,进行各种进栈,保存状态。而协程,总共也只是运行在一个线程中,要是使用线程本身的系统栈,早就暴了。因此在这里,实现的时候是用内存来模拟栈的操作。具体实现,我想复杂度一定会不小。
我们知道,线程比进程轻量级,因此产生一个线程消耗的资源比进程少,上下文切换也比进程节约。而协程比线程更加轻量级,上下文切换更是迅速。于是在服务器编程方面给人无限想象。尽管目前还没有出现一款主流的采用协程的web服务器。但是Go语言开发的的性能已经崭露头角了。
二、Unity的Coroutine执行现象:
第一种方法:&&
&voidStart()
&&&&&&&print(&Starting & +Time.time);----------------------------------------1
&&&&&&&StartCoroutine(WaitAndPrint(2));-------------------------------------2
&&&&&&&print(&Done & +Time.time);-------------------------------------------3
&&&IEnumerator WaitAndPrint(float waitTime)
&&&&&&&yield return new WaitForSeconds(waitTime);------------------------4
&&&&&&&print(&WaitAndPrint & + Time.time);----------------------------------5
该段代码的执行顺序是12435
执行到4协程注册了事件,控制权交给外部线程;外部线程执行到3;事件发生,程序分段执行机制goto到协程处记录了堆栈信息执行5语句。
IEnumerator Start()
&&&&&&&print(&Starting & +Time.time);----------------------------------------1
&&&&&&&yield return StartCoroutine(WaitAndPrint(2.0F));------------------------2
&&&&&&&print(&Done & +Time.time);------------------------------------------3
&&&IEnumerator WaitAndPrint(float waitTime)
&&&&&&&yield return new WaitForSeconds(waitTime);----------------------------4
&&&&&&&print(&WaitAndPrint & + Time.time);-----------------------------------------5
该段代码的执行顺序是12453
Why?这么奇怪的执行方式。
程序执行到4,执行yield return表达式注册事件交出控制权给外部,因为外部还要交出控制权也需要执行yield return后面的表达式语句因此会重入WaitAndPrint函数接着协程当前状态下一步执行所以执行到5,yield return 后面表达式语句执行完毕控制权完全交出,之后才执行3,根本原因是yield return 不能直接嵌套后面需要跟一个表达式(事件)。
三、Unity官方文档对coroutine的解释:
Normal coroutine updates are run after theUpdate function returns. Acoroutine is a function that can suspend its execution (yield) until the givenYieldInstruction finishes. Different
uses of Coroutines:
yield; The coroutine will continue after all Update functionshave been calledon the next frame.
yield WaitForSeconds(2); Continueafter a specified time delay, after all Update functions have been called for
yield WaitForFixedUpdate(); Continue afterall FixedUpdate has been called on all scripts.
yield WWWContinue aftera WWW download has completed
yield StartCoroutine(MyFunc);
Chains the coroutine, and will wait for the MyFunc coroutine to completefirst.
&C#要在yield coroutine之间加上return关键字。
四、Unity中的Coroutine原理猜测:
& & &虚拟机分段执行机制, 同类型嵌套用栈存放实现串行执行:.NET虚拟机在每一帧循环中, 会依次进入每个编译器预定义好的入口。对于Coroutine类型,编译器需要产生一些代码,在Coroutine类型指定的时间或事件完成后(.net的虚拟机用函数指针进行标记管理现场和在流程中每帧检查时间或者事件满足后发送消息,将cpu所有权交给yield中断的现场,或是通过包含不同Coroutine迭代器的多个管理类管理各个coroutine,
每帧用coroutine子类通过多态检查时间或事件到达,将cpu所有权交给coroutine子类中断的现场),从yield中断后的代码处继续往下执行, 这样就形成了我们看到的一个function能分段执行的机制。
& & &而对于嵌套Coroutine类型,会串行的执行而不是并行的,可能.net虚拟机对于同coroutine类型用栈存放,栈顶的先执行,从而实现串行执行,如果外层的不使用yield return,那么不会串行执行,而是并行执行。于是就可以解释上面例子中的执行次序问题。
其实yield WaitForSeconds/null/WaitForEndOfFrame都是通过整个游戏While循环来驱动的,Yield只是交出控制权给外部主线程且Coroutine设置事件挂起Coroutine协程(不是线程只是分段执行机制),当事件发生时候(不用下一帧到达,但是要在固定时间段内Update前或者后或Render后,超过了就会到下一帧)则进入协程里面的代码。
五、Unity中使用Coroutine需要注意的问题:
1.使用的地方和不能使用的地方:
必须在MonoBehaviour或继承于MonoBehaviour的类中调用 yield coroutine。yield不可以在Update或者FixedUpdate里使用。
2.开启协程:
StartCoroutine(string methodName)和StartCoroutine(IEnumeratorroutine)都可以开启一个协程,
使用字符串作为参数时,开启协程时最多只能传递一个参数,并且性能消耗会更大一点; 而使用IEnumerator 作为参数则没有这个限制。
3.删除协程:
1).在Unity3D中,使用StopCoroutine(stringmethodName)来终止该MonoBehaviour指定方法名的一个协同程序,使用StopAllCoroutines()来终止所有该MonoBehaviour可以终止的协同程序。
包括StartCoroutine(IEnumerator routine)的。
2).还有一种方法可以终止协同程序,即将协同程序所在gameobject的active属性设置为false,当再次设置active为ture时,协同程序并不会再开启;
如是将协同程序所在脚本的enabled设置为false则不会生效。
4.js和C#中使用区别:
在C#中要使用 yield return而不是yield。
C#中yield(中断)语句必须要在IEnumerator类型里,C#方法的返回类型为IEnumerator,返回值如(eg:yield return new WaitForSeconds(2); 或者 yield returnnull);
5.协程函数返回值和参数类型,组合的设计模式:
协同程序的返回类型为Coroutine类型。在Unity3D中,Coroutine类继承于YieldInstruction,所以,协同程序的返回类型只能为null、等待的帧数(frame)以及等待的时间。
协同程序的参数不能指定ref、out参数。但是,我们在使用WWW类时会经常使用到协同程序,由于在协同程序中不能传递参数地址(引用),也不能输出对象,
这使得每下载一个WWW对象都得重写一个协同程序,解决这个问题的方法是建立一个基于WWW的类(用组合模式来解决-其实就是不通过函数传参全局关联一个对象了),并实现一个下载方法。如下:
using UnityE
using System.C
public class WWWObject : MonoBehaviour
&public WWW
&public WWWObject(string url)
&if(GameVar.wwwCache)
&&www = WWW.LoadFromCacheOrDownload(url, GameVar.version);
&&www = new WWW(url);
&public IEnumerator Load()
&Debug.Log(&Start loading : & + www.url);
&while(!www.isDone)
&&if(GameVar.gameState == GameState.Jumping || GameVar.gameState ==GameState.JumpingAsync)
&&&LoadScene.progress = www.
&&yield return 1;
&if(www.error != null)
&&Debug.LogError(&Loading error : & + www.url + &\n& +www.error);
&&Debug.Log(&End loading : & + www.url);
&public IEnumerator LoadWithTip(string resourcesName)
&Debug.Log(&Start loading : & + www.url);
&LoadScene.tipStr =&&Downloading& resources&& + resourcesName + && . . .&;
&while(!www.isDone)
&&if(GameVar.gameState == GameState.Jumping || GameVar.gameState ==GameState.JumpingAsync)
&&& LoadScene.progress= www.
&&yield return 1;
&if(www.error != null)
&&Debug.LogError(&Loading error : & + www.url + &\n& +www.error);
&&Debug.Log(&End loading : & + www.url);
using UnityE
using System.C
using System.Collections.G
public class LoadResources : MonoBehaviour
&static string url =&http://61.149.211.88/Package/test.unity3d&;
&public static WWW www =
&IEnumerator Start()
&if(!GameVar.resourcesLoaded)
&&GameVar.gameState = GameState.J
&&WWWObject obj = new WWWObject(url);
&&www = obj.
&&yield return StartCoroutine(obj.LoadWithTip(&Textures&));
&&GameVar.resourcesLoaded =
&&GameVar.gameState = GameState.R
参考文章:
/forum/read.php?tid=13148
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:375083次
积分:6142
积分:6142
排名:第3186名
原创:258篇
转载:57篇
译文:10篇
评论:37条
(5)(4)(7)(14)(14)(6)(27)(1)(8)(2)(18)(32)(15)(12)(6)(21)(26)(40)(1)(4)(9)(22)(3)(4)(1)(1)(1)(1)(2)(1)(18)(1)Unity之Socket&&Http - 龙少 - ITeye技术网站
博客分类:
最近比较忙,有段时间没写博客拉。最近项目中需要使用HTTP与Socket,雨松MOMO把自己这段时间学习的资料整理一下。有关Socket与HTTP的基础知识MOMO就不赘述拉,不懂得朋友自己谷歌吧。我们项目的需求是在登录的时候使用HTTP请求,游戏中其它的请求都用Socket请求,比如人物移动同步坐标,同步关卡等等。
Socket不要写在脚本上,如果写在脚本上游戏场景一旦切换,那么这条脚本会被释放掉,Socket会断开连接。场景切换完毕后需要重新在与服务器建立Socket连接,这样会很麻烦。所以我们需要把Socket写在一个单例的类中,不用继承MonoBehaviour。这个例子我模拟一下,主角在游戏中移动,时时向服务端发送当前坐标,当服务器返回同步坐标时角色开始同步服务端新角色坐标。
Socket在发送消息的时候采用的是字节数组,也就是说无论你的数据是 int float short object 都会将这些数据类型先转换成byte[] , 目前在处理发送的地方我使用的是数据包,也就是把(角色坐标)结构体object转换成byte[]发送, 这就牵扯一个问题, 如何把结构体转成字节数组, 如何把字节数组回转成结构体。请大家接续阅读,答案就在后面,哇咔咔。
直接上代码
JFSocket.cs 该单例类不要绑定在任何对象上
usingUnityEngine;
usingSystem.Collections;
usingSystem;
usingSystem.Threading;
usingSystem.Text;
usingSystem.Net;
usingSystem.Net.Sockets;
usingSystem.Collections.Generic;
usingSystem.IO;
usingSystem.Runtime.InteropServices;
usingSystem.Runtime.Serialization;
usingSystem.Runtime.Serialization.Formatters.Binary;
publicclassJFSocket
//Socket客户端对象
privateSocket clientSocket;
//JFPackage.WorldPackage是我封装的结构体,
//在与服务器交互的时候会传递这个结构体
//当客户端接到到服务器返回的数据包时,我把结构体add存在链表中。
publicList&JFPackage.WorldPackage&worldpackage;
//单例模式
privatestaticJFSocket instance;
publicstaticJFSocket GetInstance()
if(instance==null)
instance=newJFSocket();
returninstance;
//单例的构造函数
JFSocket()
//创建Socket对象, 这里我的连接类型是TCP
clientSocket=newSocket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);
//服务器IP地址
IPAddress ipAddress=IPAddress.Parse("192.168.1.100");
//服务器端口
IPEndPoint ipEndpoint=newIPEndPoint(ipAddress,10060);
//这是一个异步的建立连接,当连接建立成功时调用connectCallback方法
IAsyncResult result=clientSocket.BeginConnect(ipEndpoint,newAsyncCallback(connectCallback),clientSocket);
//这里做一个超时的监测,当连接超过5秒还没成功表示超时
boolsuccess=result.AsyncWaitHandle.WaitOne(5000,true);
if(!success)
Debug.Log("connect Time Out");
//与socket建立连接成功,开启线程接受服务端数据。
worldpackage=newList&JFPackage.WorldPackage&();
Thread thread=newThread(newThreadStart(ReceiveSorket));
thread.IsBackground=true;
thread.Start();
privatevoidconnectCallback(IAsyncResult asyncConnect)
Debug.Log("connectSuccess");
privatevoidReceiveSorket()
//在这个线程中接受服务器返回的数据
while(true)
if(!clientSocket.Connected)
//与服务器断开连接跳出循环
Debug.Log("Failed to clientSocket server.");
clientSocket.Close();
//接受数据保存至bytes当中
byte[]bytes=newbyte[4096];
//Receive方法中会一直等待服务端回发消息
//如果没有回发会一直在这里等着。
inti=clientSocket.Receive(bytes);
clientSocket.Close();
//这里条件可根据你的情况来判断。
//因为我目前的项目先要监测包头长度,
//我的包头长度是2,所以我这里有一个判断
if(bytes.Length&2)
SplitPackage(bytes,0);
Debug.Log("length is not
catch(Exceptione)
Debug.Log("Failed to clientSocket error."+e);
clientSocket.Close();
privatevoidSplitPackage(byte[]bytes,intindex)
//在这里进行拆包,因为一次返回的数据包的数量是不定的
//所以需要给数据包进行查分。
while(true)
//包头是2个字节
byte[]head=newbyte[2];
intheadLengthIndex=index+2;
//把数据包的前两个字节拷贝出来
Array.Copy(bytes,index,head,0,2);
//计算包头的长度
shortlength=BitConverter.ToInt16(head,0);
//当包头的长度大于0 那么需要依次把相同长度的byte数组拷贝出来
if(length&0)
byte[]data=newbyte[length];
//拷贝出这个包的全部字节数
Array.Copy(bytes,headLengthIndex,data,0,length);
//把数据包中的字节数组强制转换成数据包的结构体
//BytesToStruct()方法就是用来转换的
//这里需要和你们的服务端程序商量,
JFPackage.WorldPackage wp=newJFPackage.WorldPackage();
wp=(JFPackage.WorldPackage)BytesToStruct(data,wp.GetType());
//把每个包的结构体对象添加至链表中。
worldpackage.Add(wp);
//将索引指向下一个包的包头
headLengthIndex+length;
//如果包头为0表示没有包了,那么跳出循环
//向服务端发送一条字符串
//一般不会发送字符串 应该是发送数据包
publicvoidSendMessage(stringstr)
byte[]msg=Encoding.UTF8.GetBytes(str);
if(!clientSocket.Connected)
clientSocket.Close();
//int i = clientSocket.Send(msg);
IAsyncResult asyncSend=clientSocket.BeginSend(msg,0,msg.Length,SocketFlags.None,newAsyncCallback(sendCallback),clientSocket);
boolsuccess=asyncSend.AsyncWaitHandle.WaitOne(5000,true);
if(!success)
clientSocket.Close();
Debug.Log("Failed to SendMessage server.");
Debug.Log("send message error");
//向服务端发送数据包,也就是一个结构体对象
publicvoidSendMessage(objectobj)
if(!clientSocket.Connected)
clientSocket.Close();
//先得到数据包的长度
shortsize=(short)Marshal.SizeOf(obj);
//把数据包的长度写入byte数组中
byte[]head=BitConverter.GetBytes(size);
//把结构体对象转换成数据包,也就是字节数组
byte[]data=StructToBytes(obj);
//此时就有了两个字节数组,一个是标记数据包的长度字节数组, 一个是数据包字节数组,
//同时把这两个字节数组合并成一个字节数组
byte[]newByte=newbyte[head.Length+data.Length];
Array.Copy(head,0,newByte,0,head.Length);
Array.Copy(data,0,newByte,head.Length,data.Length);
//计算出新的字节数组的长度
intlength=Marshal.SizeOf(size)+Marshal.SizeOf(obj);
//向服务端异步发送这个字节数组
IAsyncResult asyncSend=clientSocket.BeginSend(newByte,0,length,SocketFlags.None,newAsyncCallback(sendCallback),clientSocket);
//监测超时
boolsuccess=asyncSend.AsyncWaitHandle.WaitOne(5000,true);
if(!success)
clientSocket.Close();
Debug.Log("Time Out !");
catch(Exceptione)
Debug.Log("send message error: "+e);
//结构体转字节数组
publicbyte[]StructToBytes(objectstructObj)
intsize=Marshal.SizeOf(structObj);
IntPtr buffer=
Marshal.AllocHGlobal(size);
Marshal.StructureToPtr(structObj,buffer,false);
newbyte[size];
Marshal.Copy(buffer,bytes,0,size);
Marshal.FreeHGlobal(buffer);
//字节数组转结构体
publicobjectBytesToStruct(byte[]bytes,
strcutType)
intsize=Marshal.SizeOf(strcutType);
IntPtr buffer=Marshal.AllocHGlobal(size);
Marshal.Copy(bytes,0,buffer,size);
Marshal.PtrToStructure(buffer,
strcutType);
Marshal.FreeHGlobal(buffer);
privatevoidsendCallback(IAsyncResult asyncSend)
//关闭Socket
publicvoidClosed()
if(clientSocket!=null&&clientSocket.Connected)
clientSocket.Shutdown(SocketShutdown.Both);
clientSocket.Close();
clientSocket=null;
为了与服务端达成默契,判断数据包是否完成。我们需要在数据包中定义包头 ,包头一般是这个数据包的长度,也就是结构体对象的长度。正如代码中我们把两个数据类型 short 和 object 合并成一个新的字节数组。
然后是数据包结构体的定义,需要注意如果你在做IOS和Android的话数据包中不要包含数组,不然在结构体转换byte数组的时候会出错。
Marshal.StructureToPtr () error : Attempting to JIT compile method
JFPackage.cs
usingUnityEngine;
usingSystem.Collections;
usingSystem.Runtime.InteropServices;
publicclassJFPackage
//结构体序列化
[System.Serializable]
//4字节对齐 iphone 和 android上可以1字节对齐
[StructLayout(LayoutKind.Sequential,Pack=4)]
publicstructWorldPackage
publicbytemEquipID;
publicbytemAnimationID;
publicbytemHP;
publicshortmPosx;
publicshortmPosy;
publicshortmPosz;
publicshortmRosx;
publicshortmRosy;
publicshortmRosz;
publicWorldPackage(shortposx,shortposy,shortposz,shortrosx,shortrosy,shortrosz,byteequipID,byteanimationID,bytehp)
mPosx=posx;
mPosy=posy;
mPosz=posz;
mRosx=rosx;
mRosy=rosy;
mRosz=rosz;
mEquipID=equipID;
mAnimationID=animationID;
在脚本中执行发送数据包的动作,在Start方法中得到Socket对象。
publicJFSocket mJFsorket;
voidStart()
mJFsorket=JFSocket.GetInstance();
让角色发生移动的时候,调用该方法向服务端发送数据。
voidSendPlayerWorldMessage()
//组成新的结构体对象,包括主角坐标旋转等。
Vector3 PlayerTransform=transform.localPosition;
Vector3 PlayerRotation=transform.localRotation.eulerAngles;
//用short的话是2字节,为了节省包的长度。这里乘以100 避免使用float 4字节。当服务器接受到的时候小数点向前移动两位就是真实的float数据
(short)(PlayerTransform.x*100);
(short)(PlayerTransform.y*100);
(short)(PlayerTransform.z*100);
(short)(PlayerRotation.x*100);
(short)(PlayerRotation.y*100);
(short)(PlayerRotation.z*100);
byteequipID=1;
byteanimationID=9;
JFPackage.WorldPackage wordPackage=newJFPackage.WorldPackage(px,py,pz,rx,ry,rz,equipID,animationID,hp);
//通过Socket发送结构体对象
mJFsorket.SendMessage(wordPackage);
接着就是客户端同步服务器的数据,目前是测试阶段所以写的比较简陋,不过原理都是一样的。哇咔咔!!
//上次同步时间
privatefloatmSynchronous;
voidUpdate()
mSynchronous+=Time.deltaTime;
//在Update中每0.5s的时候同步一次
if(mSynchronous&0.5f)
intcount=mJFsorket.worldpackage.Count;
//当接受到的数据包长度大于0 开始同步
if(count&0)
//遍历数据包中 每个点的坐标
foreach(JFPackage.WorldPackage wp inmJFsorket.worldpackage)
floatx=(float)(wp.mPosx/100.0f);
floaty=(float)(wp.mPosy/100.0f);
floatz=(float)(wp.mPosz/100.0f);
Debug.Log("x = "+x+" y = "+y+" z = "+z);
//同步主角的新坐标
mPlayer.transform.position=newVector3(x,y,z);
//清空数据包链表
mJFsorket.worldpackage.Clear();
mSynchronous=0;
主角移动的同时,通过Socket时时同步坐标喔。。有没有感觉这个牛头人非常帅气 哈哈哈。
对于Socket的使用,我相信没有比MSDN更加详细的了。 有关Socket 同步请求异步请求的地方可以参照MSDN
链接地址给出来了,好好学习吧,嘿嘿。
上述代码中我使用的是Thread() 没有使用协同任务StartCoroutine() ,原因是协同任务必需要继承MonoBehaviour,并且该脚本要绑定在游戏对象身上。问题绑定在游戏对象身上切换场景的时候这个脚本必然会释放,那么Socket肯定会断开连接,所以我需要用Thread,并且协同任务它并不是严格意义上的多线程。
HTTP请求在Unity我相信用的会更少一些,因为HTTP会比SOCKET慢很多,因为它每次请求完都会断开。废话不说了, 我用HTTP请求制作用户的登录。用HTTP请求直接使用Unity自带的www类就可以,因为HTTP请求只有登录才会有, 所以我就在脚本中来完成, 使用 www 类 和 协同任务StartCoroutine()。
usingUnityEngine;
usingSystem.Collections;
usingSystem.Collections.Generic;
publicclassLoginGlobe:MonoBehaviour{
voidStart()
StartCoroutine(GET("/"));
voidUpdate()
voidOnGUI()
publicvoidLoginPressed()
//登录请求 POST 把参数写在字典用 通过www类来请求
Dictionary&string,string&dic=newDictionary&string,string&();
dic.Add("action","0");
dic.Add("usrname","xys");
dic.Add("psw","123456");
StartCoroutine(POST("http://192.168.1.12/login.php",dic));
publicvoidSingInPressed()
//注册请求 POST
Dictionary&string,string&dic=newDictionary&string,string&();
dic.Add("action","1");
dic.Add("usrname","xys");
dic.Add("psw","123456");
StartCoroutine(POST("http://192.168.1.12/login.php",dic));
//POST请求
IEnumerator POST(stringurl,Dictionary&string,string&post)
WWWForm form=newWWWForm();
foreach(KeyValuePair&string,string&post_arg inpost)
form.AddField(post_arg.Key,post_arg.Value);
WWW www=newWWW(url,form);
yield returnwww;
if(www.error!=null)
//POST请求失败
Debug.Log("error is :"+www.error);
//POST请求成功
Debug.Log("request ok : "+www.text);
IEnumerator GET(stringurl)
WWW www=newWWW(url);
yield returnwww;
if(www.error!=null)
//GET请求失败
Debug.Log("error is :"+www.error);
//GET请求成功
Debug.Log("request ok : "+www.text);
如果想通过HTTP传递二进制流的话 可以使用 下面的方法。
WWWForm wwwForm=newWWWForm();
byte[]byteStream=System.Text.Encoding.Default.GetBytes(stream);
wwwForm.AddBinaryData("post",byteStream);
www=newWWW(Address,wwwForm);
本文固定链接:
转载请注明:
longerdewo
浏览: 3361 次
来自: 北京

我要回帖

更多关于 startcoroutine 参数 的文章

 

随机推荐