<code>UIPanel.alpha is a property, and Unity is not able to animate properties. What you are animating instead is "MAlpha", I'm guessing -- which is a private variable. The fact that Unity lets you do that is a bug in Unity that has existed for ages. You need to use an intermediate script -- AnimatedAlpha. Attach it to your panel (or a widget) and animate its alpha instead of the panel when using the Unity's animation system.</code>
分类存档: 未分类 - 第2页
animation修改ngui widget alpha无效的问题
Unity中扩展GameObject类
今天看代码时看到一个之前不知道的技巧,可以扩展Unity的GameObject类,为GameObject添加自己定义的方法:
using UnityEngine; using System.Collections; public static class GameObjectEx { public static T MakeSureComponent<T>(this GameObject gameObject) where T : Component { T t = gameObject.GetComponent<T>(); if (t == null) { t = gameObject.AddComponent<T>(); } return t; } }
这个类添加在工程中后,所以的gameObject上都可以直接调用MakeSureCompoent这个方法,真是超级便捷.
this.m_footstepHandler = base.gameObject.MakeSureComponent<FootstepHandler>();
同理,Unity自带的其它类应该也是可以进行扩展的。
查找了下是哪个天才想到的这个办法,google找到最早的一篇是这个:
https://forum.unity3d.com/threads/howto-add-method-to-the-gameobject-class-ie-add-custom-variables-to-every-instance.89791/
c/c++ 与 lua之前互调的性能测试
完整测试代码如下:
测试目标主要是看看c与lua之前互调的性能如何。
测试结论:c调用lua与lua调用c基本只有一个数量级的性能损失。
从c中调用lua,使用缓存ref的方式,可以提升30%的性能。
#include <lua.h> #include <lauxlib.h> #include <stdlib.h> #include <stdio.h> #include <sys/time.h> #include "skynet.h" // 取当前毫秒值 static int ltime(lua_State *L) { struct timeval tv; gettimeofday(&tv,NULL); lua_pushinteger(L,tv.tv_sec*1000+tv.tv_usec/1000); return 1; } // 供lua调用,内部无业务逻辑 static int ltest1(lua_State *L) { return 0; } // 供lua调用, 内部int相加并返回 static int ltest2(lua_State *L) { int a1=luaL_checkinteger(L,1); int a2=luaL_checkinteger(L,2); lua_pushinteger(L,a1+a2); return 1; } // 内部调用lua中方法 static int ltest3(lua_State *L) { lua_getglobal(L,"global_test_func1"); lua_call(L,0,0); return 0; } // 内部调用lua中方法,并取得lua中返回值 static int ltest4(lua_State *L) { lua_getglobal(L,"global_test_func2"); lua_pushinteger(L,1); lua_pushinteger(L,2); lua_call(L,2,1); int sum = (int)lua_tointeger(L, -1); lua_pop(L, 1); lua_pushinteger(L,sum); return 1; } // 内部调用lua方法10000次 static int ltest5(lua_State *L) { int sum=0; for(int m=0;m<10000000;m++){ lua_getglobal(L,"global_test_func2"); lua_pushinteger(L,1); lua_pushinteger(L,2); lua_call(L,2,1); sum=(int)lua_tointeger(L, -1); lua_pop(L, 1); } lua_pushinteger(L,sum); return 1; } // 和test5一起对比 static int ltest6(lua_State *L) { for(int m=0;m<10000000;m++){ lua_getglobal(L,"global_test_func2"); lua_pushinteger(L,1); lua_pushinteger(L,2); lua_call(L,2,1); lua_pop(L, 1); } lua_pushinteger(L,3); return 1; } // 和test5一起做对比 static int ltest7(lua_State *L) { int func2_handler; lua_getglobal(L,"global_test_func2"); func2_handler=luaL_ref(L,LUA_REGISTRYINDEX); for(int m=0;m<10000000;m++){ lua_rawgeti(L,LUA_REGISTRYINDEX,func2_handler); lua_pushinteger(L,1); lua_pushinteger(L,2); lua_call(L,2,1); lua_pop(L,1); } //luaL_unref(L,LUA_REGISTRYINDEX); lua_pushinteger(L,3); return 1; } // 和test5一起做对比一下 int add(int a,int b){ return a+b; } static int ltest8(lua_State *L) { for(int m=0;m<10000000;m++){ add(1,2); } return 0; } // full userdata // light userdata int luaopen_perf(lua_State *L) { luaL_checkversion(L); luaL_Reg l[] = { { "time", ltime }, { "test1", ltest1 }, // 从lua中直接调用c,内部无逻辑 { "test2", ltest2 }, { "test3", ltest3 }, { "test4", ltest4 }, { "test5", ltest5 }, { "test6", ltest6 }, { "test7", ltest7 }, { "test8", ltest8 }, { NULL, NULL} }; luaL_newlib(L,l); return 1; }
lua代码:
require "common" local perf = require "perf" function global_test_func1() -- print("global_test_func1") end function global_test_func2(a,b) return a+b end local t1 local t2 t1=perf.time() for i=1,10000000 do perf.test1() end t2=perf.time() print("test1:"..(t2-t1)) t1=perf.time() for i=1,10000000 do perf.test2(1,2) end t2=perf.time() print("test2:"..(t2-t1)) t1=perf.time() for i=1,10000000 do perf.test3() end t2=perf.time() print("test3:"..(t2-t1)) t1=perf.time() for i=1,10000000 do perf.test4() end t2=perf.time() print("test4:"..(t2-t1)) t1=perf.time() perf.test5() t2=perf.time() print("test5:"..(t2-t1)) t1=perf.time() perf.test6() t2=perf.time() print("test6:"..(t2-t1)) t1=perf.time() perf.test7() t2=perf.time() print("test7:"..(t2-t1)) t1=perf.time() perf.test8() t2=perf.time() print("test8:"..(t2-t1))
运行结果:
test1:470 test2:777 test3:1619 test4:1941 test5:1490 test6:1437 test7:675 test8:40
一个hashmap算法
阅读云风开源的AOI实现时,看到里面有一个hashmap算法实现。
https://github.com/cloudwu/aoi
这里记录下分享下其实现
map内部存储是使用数组实现即 map_slot,初始分配16个。容量不足时,以翻倍容量增加,并将对象重新进行分配至新的内存空间。
这里画图举例时以初始容量为8进行原理说明:
1、初始状态,所有slot处于未分配
2、插入A,使用hash算法计算出应该分配在哪个slot上(注:可以考虑添加扰动函数避免比较差的hash算法,这里针对aoi的情况,直接使用了对size取模)
假设对A取模后将其放入第三个slot
3、继续插入B和C,其中B和A取模后 不在相同的slot中。
然后是取模后分配到相同的slot的情况:
实际上两个对象不会存在相同的slot中。
这里如果出现分配的slot中已经存在对象了,比如此时,C分配的第三个slot已经存在A了。
则从数组最尾部向前查找第一个为空的slot,将C放入,并将A.next指向C所在的slot
4、继续插入一个和A相同slot的对象时,继续从尾部向前查找一个空的slot,并将A.next指向新分配的slot,新分配的slot.next指向原A.next ( 即C)
5、如果遇到分配的slot被其它slot的对象占用如何处理。
比如,我这里想分配E,取模后应该分配在第七个格子,但第七个格子已经被D占用。
这里采用的方式,是将D取出( 因为D取模不应该分配在第七个格子,只是因为第三个格子被占用了,所以才从尾部查找的一个空闲的格子放D),取出D后将E放后,如下图:
这里D被取出应该如何处理,再执行一个第1步,将D放hashmap即可。
游戏中重构了网络模块
我们游戏中断线和超时这一块出问题非常多。
这一次我专门抽出了一周时间,了解了下c#下的socket相关函数重写了网络模块。
首要目标是避免另开线程,使用nio。然后是内部处理超时,断线和其它IO异常,重连3次失败后,才提交给游戏自己处理。重连时,自动登陆并续发消息。
这里本来还需要添加一个补发消息的机制(断线后网络传输中导致丢失的消息),但是测试只有续发消息,已经解决掉了原来99%问题。所以补发消息先放一下,先再重构其它地方。
重构后测试的结果非常好,以前各种网络问题都没有复现,断线对玩家来说是不可见的,只要长时间断线(三次重连失败)才会给玩家一个提示框,让玩家手动点击去重连。
//---------------------------------------------- // NET : NetManager // AUTHOR: zhu kun qian //---------------------------------------------- using System.IO; public class NetMsg { // 有必要用id吗? // public cmd.CmdType cmdType; public uint loop;// 唯一的循环id public byte[] data;// protobuf二进制数据 public byte[] totalData;//完整的消息二进制数据 public MemoryStream netdata; // 这里能避免一次array copy不? // TODO:暂不考虑这避免arry copy的消耗,以后有时间时,可以考虑处理下。 }
//---------------------------------------------- // NET : NetManager // AUTHOR: zhu kun qian //---------------------------------------------- using System.Net; using System.Net.Sockets; using System.Runtime.Remoting.Messaging; using UnityEngine; using System; using System.Collections; using System.Collections.Generic; using System.IO; /* * 没有使用任何阻塞函数。 * * connect是block函数,所以改为使用ConnectAsync, beginConnect也是异步,也可以使用 * * 连接成功后,socket修改为non-blocking */ public class NetManagerSocket { // 如果断开连接,直接new socket public string ip; public int port; private Socket socket; private byte[] readBuf = new byte[64 * 1024];// 最高缓存接收64k数据。 private int readBufIndex = 0;//已经从readBuf中读取的字节数 private int available = 0;// readbuf已经从socket中接收的字节数 public SocketError socketError = SocketError.Success;// 这里应该是传递到上层,还是在这里处理? // --------------------------------------- // -- decoder相关 private int length = 0;// protobuf消息体中的长度 private int needRead = 0;// protobuf消息体中剩余需要读取的长度 // --------------------------------------- public void connect() { socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true); socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.SendTimeout, 5000);// 设置5秒发送超时 socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, false); socket.NoDelay = true; // socket.Blocking = false; socket.Blocking = true;//设置为非阻塞 socketError = SocketError.Success; Debug.Log("dontLinger:" + socket.GetSocketOption(SocketOptionLevel.Socket, SocketOptionName.DontLinger)); try { // 这里需要修改为异步connect // http://msdn.microsoft.com/en-us/library/d7ew360f%28v=vs.110%29.aspx // Connect method will block, unless you specifically set the Blocking property to false prior to calling Connect. // If you are using a connection-oriented protocol like TCP and you do disable blocking, Connect will throw a SocketException because it needs time to make the connection // 结论:很奇怪,并没有按文档上描述的执行,设置为blocking,并没有抛出异常。 // socket.Connect(ip, port); // The asynchronous BeginConnect operation must be completed by calling the EndConnect method. // IAsyncResult result= socket.BeginConnect(ip, port, new AsyncCallback(connectCallback), socket); // Debug.Log("asyncResult is completed:"+result.IsCompleted); // 异步处理必须设置为blocking,why? //* SocketAsyncEventArgs eventArgs = new SocketAsyncEventArgs(); eventArgs.RemoteEndPoint = new IPEndPoint(IPAddress.Parse(ip), port); eventArgs.Completed += new EventHandler<SocketAsyncEventArgs>(connectCallback2); eventArgs.UserToken = socket; socket.ConnectAsync(eventArgs); // */ // 这里需要添加超时处理吗? } catch (Exception ex) { Debug.LogError("socket connection exception:" + ex); socketError = SocketError.ConnectionRefused; } } private void connectCallback2(object src, SocketAsyncEventArgs result) { Debug.Log("connectCallback2, isCompleted:" + result + " " + result.SocketError); if (result.SocketError != SocketError.Success) { socketError = result.SocketError; } else { Socket socket = (Socket)src; socket.Blocking = false; } } void connectCallback(IAsyncResult result) { Debug.Log("connectCallback22, isCompleted:" + result.IsCompleted); // connected = true; try { Socket socket = (Socket)result.AsyncState; socket.EndConnect(result); Debug.Log("socket is connected:" + socket.Connected); socket.Send(new byte[] { }); } catch (Exception e) { Debug.LogError("error:" + e); socketError = SocketError.ConnectionRefused; } } public void disconnect() { if (socket != null) { socket.Close(); socket = null; } } // public NetMsg read() { // 这里同步读也可以,但只读数据接收到足够一个消息的情况 // 使用availed预判进行同步读,不会阻塞主线程 // 解析消息放在这里。 if (socket != null && socket.Available > 0) { if (available == 0) { if (socket.Available < 12) { // 一个数据包,最小为12字节 return null; } // 开始从socket中读入一条数据 // 如果足够,就直接解析为消息返回 // 如果不够,就将数据放在cache中 socketRead(2); if (socketError != SocketError.Success) { return null; } length = readUshort(); if (length == 0) { socketRead(4); if (socketError != SocketError.Success) { return null; } length = readInt(); } int socketAvailable = socket.Available; needRead = length; if (socketAvailable < needRead) { // 不足时,socket有多少缓存数据就读多少 socketRead(socketAvailable); if (socketError != SocketError.Success) { return null; } needRead = needRead - socketAvailable; return null; } else { // 数据足够,解析数据 socketRead(needRead); if (socketError != SocketError.Success) { return null; } return readMsg(); } } else { // 继续从socket中接收数据 int socketAvailable = socket.Available; if (socketAvailable < needRead) { // 数据依旧不足 socketRead(socketAvailable); if (socketError != SocketError.Success) { return null; } needRead = needRead - socketAvailable; return null; } else { // 数据足够,解析数据 socketRead(needRead); if (socketError != SocketError.Success) { return null; } return readMsg(); } } } return null; } private void readReset() { // 读入一个完整消息后,重置数据 available = 0; readBufIndex = 0; length = 0; needRead = 0; } private NetMsg readMsg() { NetMsg netMsg = new NetMsg(); UInt32 loop = readUInt(); short cmdId = readShort(); byte[] protoData = null; if (cmdId > 0) { protoData = new byte[length - 10]; Array.Copy(readBuf, readBufIndex, protoData, 0, length - 10); } else { // 有压缩 MemoryStream inms = new MemoryStream(readBuf, readBufIndex, length - 10); MemoryStream outms = new MemoryStream(); SevenZipTool.Unzip(inms, outms); protoData = outms.ToArray(); cmdId = (short)-cmdId; } netMsg.loop = loop; netMsg.cmdType = (cmd.CmdType)cmdId; netMsg.data = protoData; netMsg.netdata=new MemoryStream(protoData); readReset(); return netMsg; } private short readShort() { short ret = BitConverter.ToInt16(readBuf, readBufIndex); readBufIndex += 2; return Endian.SwapInt16(ret); } private ushort readUshort() { ushort ret = BitConverter.ToUInt16(readBuf, readBufIndex); readBufIndex += 2; return Endian.SwapUInt16(ret); } private int readInt() { int ret = BitConverter.ToInt32(readBuf, readBufIndex); readBufIndex += 4; return Endian.SwapInt32(ret); } private uint readUInt() { uint ret = BitConverter.ToUInt32(readBuf, readBufIndex); readBufIndex += 4; return Endian.SwapUInt32(ret); } private void socketRead(int readLen) { //从socket中读入数据入在readBuf中 socket.Receive(readBuf, available, readLen, SocketFlags.None, out socketError); if (socketError != SocketError.Success) { Debug.LogError("socket Read error:" + socketError); } available += readLen; } public int send(NetMsg netMsg, int offset) { if (netMsg.totalData == null) { encode(netMsg); } int sendNum = socket.Send(netMsg.totalData, offset, netMsg.totalData.Length - offset, SocketFlags.None, out socketError); if (socketError != SocketError.Success) { Debug.LogError("socket send error:" + socketError); return 0; } if (sendNum + offset == netMsg.totalData.Length) { return -1;//标志,全部发送完成 } return sendNum; } private void encode(NetMsg netMsg) { MemoryStream outstream = new MemoryStream(); byte[] _t = null; int totalLength = netMsg.data.Length + 10; if (totalLength > 65535) { _t = BitConverter.GetBytes(Endian.SwapInt16((short)0)); outstream.Write(_t, 0, _t.Length); _t = BitConverter.GetBytes(Endian.SwapInt32(totalLength)); outstream.Write(_t, 0, _t.Length); } else { _t = BitConverter.GetBytes(Endian.SwapInt16((short)totalLength)); outstream.Write(_t, 0, _t.Length); } _t = BitConverter.GetBytes(Endian.SwapUInt32(netMsg.loop)); outstream.Write(_t, 0, _t.Length); _t = BitConverter.GetBytes(Endian.SwapInt16((short)netMsg.cmdType)); outstream.Write(_t, 0, _t.Length); outstream.Write(netMsg.data, 0, netMsg.data.Length); _t = BitConverter.GetBytes(Endian.SwapInt32((int)0)); outstream.Write(_t, 0, _t.Length); _t = outstream.ToArray(); netMsg.totalData = _t; } public bool isConnected() { return socket != null && (socket.Connected); } }
//---------------------------------------------- // NET : NetManager // AUTHOR: zhu kun qian //---------------------------------------------- using System; using System.Linq; using System.Net.Sockets; using UnityEngine; using System.Collections.Generic; using System.IO; public class NetManager { public uint loop;// 永不重复,一直加1 public string ip = ""; public int port = 0; private NetManagerSocket socket = null; private int maxQuerySize = 100;//接收和发送最多cache 100条消息 private int maxReconnectTimes = 3;//重连最多重试3次 // 发送相关 public Queue<NetMsg> msgQuery = new Queue<NetMsg>(); // 发送消息队列 public NetMsg reconnectTokenLogin = null;//重连发送的登陆消息 public bool loginSuccess = false; private int sendBytes = 0; private float sendBytesTimeout = 0f; // 发送消息超时 // 接收的消息队列 private Queue<NetMsg> receviedMsgQueue = new Queue<NetMsg>();// 从服务器接收到的消息 private int reconnectTryTimes = 0; // 重连次数 private float connectTimeout = 0f; // 连接超时 public EventDelegate.Callback reconnectErrorCallback; // 如果出现内部无法处理的得连(1、连试3次无法重连成功 2、累积的消息数量过量,需要重启游戏客户端) // 如果断线后,是使用原socket重连,还是使用新的socket?新new出来 public static NetManager Instance = null; public NetManager() { Instance = this; } public bool isConnected() { return socket != null && socket.isConnected(); } public void connect() { if (socket != null) { Debug.LogError("socket is not closed,try close"); socket.disconnect(); } Debug.Log("start connect ip:" + ip + " port:" + port); socket = new NetManagerSocket(); socket.ip = ip; socket.port = port; socket.connect(); sendBytes = 0; sendBytesTimeout = 0f; connectTimeout = 0f; } public void disconnect() { if (socket == null) { Debug.LogError("socket is null"); return; } socket.disconnect(); socket = null; } public void onUpdate() { // 每祯执行,没有阻塞 if (socket != null) { // 改为在socket中处理呢 if (socket.socketError != SocketError.Success) { // 如果遇到sokcet错误,不需要等等超时,立即重连 Debug.LogError("socket error:" + socket.socketError); tryReconnect(); return; } if (socket.isConnected()) { NetMsg msg = socket.read(); if (msg != null) { receviedMsgQueue.Enqueue(msg); } NetMsg netMsg = null; if (reconnectTokenLogin != null) { netMsg = reconnectTokenLogin; } else { if (loginSuccess) { lock (msgQuery) { if (msgQuery.Count > 0) { netMsg = msgQuery.First(); } } } } if (netMsg != null) { socketSend(netMsg); } } else { if (connectTimeout == 0f) { connectTimeout = Time.realtimeSinceStartup; } else if (Time.realtimeSinceStartup - connectTimeout > 5) { // 连接5秒超时,处理重连 tryReconnect(); } } } } private void tryReconnect() { if (reconnectTryTimes >= 3) { // 跳出错误处理回调,交给外部处理 if (reconnectErrorCallback != null) { reconnectErrorCallback(); } disconnect(); return; } Debug.LogError("socket connect timeout, try reconnect:" + reconnectTryTimes + " " + socket.socketError); reconnectTryTimes++; disconnect(); connect(); // 重试需要,重新发送登陆消息505 LoginState.Instance.loginWithTokenSub(true); } public NetMsg readMsg() { if (receviedMsgQueue.Count == 0) { return null; } return receviedMsgQueue.Dequeue(); } // true:超时 private void socketSend(NetMsg netMsg) { // 发送数据 bool newMsg = false;// 新发送的消息 if (sendBytes == 0) { newMsg = true; } int num = socket.send(netMsg, sendBytes); if (num > 0) { sendBytes += num; } if (num == -1) { // 全部发送完成 if (cmd.CmdType.tokenLogin == netMsg.cmdType) { reconnectTokenLogin = null; } else { lock (msgQuery) { msgQuery.Dequeue(); } } sendBytes = 0; sendBytesTimeout = 0f; } else { // 未发送完成,处理超时逻辑 if (newMsg) { sendBytesTimeout = Time.realtimeSinceStartup; } else { // 检查时间是否超时 if (Time.realtimeSinceStartup - sendBytesTimeout > 5) { // 超过5秒 Debug.LogError("socket timeout.try reconnect"); // 重连重发 if (socket.socketError != SocketError.Success) { Debug.LogError("socket error:" + socket.socketError); } socket.socketError = SocketError.TimedOut; } } } } public void SendCmd<T>(cmd.CmdType cmdType, T protoObj) { send(cmdType,protoObj); } public void send<T>(cmd.CmdType cmdType, T protoObj) { NetMsg netMsg = new NetMsg(); netMsg.loop = ++loop; netMsg.cmdType = cmdType; MemoryStream outms = new MemoryStream(); ProtoBuf.Serializer.Serialize(outms, protoObj); netMsg.data = outms.ToArray(); // todo:因为放在onupdate中,感觉这个lock也是可以避免掉的。暂时先加上,以后测试后再考虑去掉。 // 只要能确认不会多线程操作,就可以去掉这个lock if (cmdType == cmd.CmdType.tokenLogin) { reconnectTokenLogin = netMsg; loginSuccess = false; return; } lock (msgQuery) { msgQuery.Enqueue(netMsg); // 在onupdate中发送,这样只差3ms,是可以接受的 } if (msgQuery.Count > maxQuerySize) { Debug.LogError("msgQuery more than max size:" + msgQuery.Count); } } }
2015.01.19记:我重构时,未添加断线补发未送达的消息,我们客户端写的逻辑不严谨,在登陆游戏按钮上连续多次点击,会导致卡住登陆。我这里只是使用禁止多次点击来避免这个问题,如果使用有断线补发未送达的消息也可以不会出现这个问题。总之,不要依赖客户端代码很强壮,最好还是添加上断线补发消息。
opengles中画四边型
opengles中仅支持以下几种模型:
/* BeginMode */
#define GL_POINTS 0x0000
#define GL_LINES 0x0001
#define GL_LINE_LOOP 0x0002
#define GL_LINE_STRIP 0x0003
#define GL_TRIANGLES 0x0004
#define GL_TRIANGLE_STRIP 0x0005
#define GL_TRIANGLE_FAN 0x0006
所以如果需要画一个四边型,需要借助GL_TRIANGLES_STRIP
static const GLfloat vertices[] = { -1.0, 1.0, -0.0, 1.0, 1.0, -0.0, -1.0,
-1.0, -0.0, 1.0, -1.0, -0.0 };
static const GLfloat texCoords[] =
{ 0.0, 1.0, 1.0, 1.0, 0.0, 0.0, 1.0, 0.0 };
glBindTexture(GL_TEXTURE_2D, 1);
glVertexPointer(3, GL_FLOAT, 0, vertices);
glTexCoordPointer(2, GL_FLOAT, 0, texCoords);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
如此即可画出一个四边型
java.io.IOException: error=12, Cannot allocate memory 解决方案
java调用本地指令报以上错误。
执行:
echo 1 > /proc/sys/vm/overcommit_memory
后,错误消失。
js调用flash需要注意地方
获取flash对象的方法。
在网上查找的很多js获取flash对象的方法,不兼容IE9,这里提供一个能兼容IE9的方法。同时兼容其它浏览器。
function thisMovie(movieName) {
if (navigator.appName.indexOf(“Microsoft”) != -1) {
//alert(“IE”);
if (typeof (window[movieName].qqBuyUpdate) == ‘function’) {
// < IE9
return window[movieName];
}
else if (typeof (document[movieName].qqBuyUpdate) == ‘function’) {
// >= IE9
return document[movieName];
}
}
else {
// NON IE
return document[movieName];
}
}
在js里面调用flash:
thisMovie(“client”).qqBuyUpdate();
mingw下cdt中console不输出
To add this flag in Eclipse, go to Project->Properties. Under “C++ Build”, select “Settings”. Under “MinGW C++ Linker”, select “Miscellaneous”. Add “-static-libgcc” to the “Linker flags” field. You may have to do this for your other build configurations and projects.
参考:
http://www.eclipse.org/forums/index.php/mv/tree/156519/
近期评论