Lua pairs ipairs区别 Lua笔记
ipairs (t)
Returns three values: an iterator function, the table t
, and 0, so that the construction
for i,v in ipairs(t) do body end
will iterate over the pairs (1,t[1]
), (2,t[2]
), ···, up to the first integer key absent from the table.
pairs (t)
Returns three values: the next
function, the table t
, and nil, so that the construction
for k,v in pairs(t) do body end
will iterate over all key–value pairs of table t
.
See function next
for the caveats of modifying the table during its traversal.
pairs可以遍历表中所有的key,并且除了迭代器本身以及遍历表本身还可以返回nil;
ipairs则不能返回nil,只能返回数字0,如果遇到nil则退出。
ipairs适用于数组,pairs适用于键值表。
skynet研究001——skynet Skynet笔记
一个由国内大神云风开发的基于C+lua的开源服务器框架(https://github.com/cloudwu/skynet)。
底层核心用c编写,上层逻辑由lua实现。
入门文档 http://skynetdoc.com/book/index.html
源码下载
git clone https://github.com/cloudwu/skynet.git
安装编译
cd skynet
make macosx
运行服务器demo
./skynet ./examples/config

运行客户端demo
./3rd/lua/lua ./examples/client.lua

输入hello 返回world
Unity与Photon通信简单文档 游戏服务器
Unity与Photon通信简单文档
主要的常用相关术语
Application
Application指的是游戏逻辑应用,由C#语言书写同时由Photon引擎负责启动运行。所有的应用均从Application继承。
Deploy Folder
即发布目录,在服务端SDK中,deploy目录包含了Photon引擎运行的所有需要的文件:Photon核心文件和应用程序文件。
Peer
即连接到Photon引擎的客户端,另一方面Photon服务器端也是Peer,且只有一个。
Channel
在Photon引擎中channel主要用于分割通信用,在同一channel中所有的operation和event都是顺序执行的。
Disconnect (Connect连接)
即服务器和客户端断开操作。通常发生在客户端断开连接或连接超时时候;服务器也可以根据需要断开和客户端之间的连接。
Event
Event是异步发送给客户端的事件消息。可以由操作(operations,如
sideeffect)触发或引发(这是operation的主要目的)。事件由事件代码(Eventcode)标识,事件来源则是ActorNumber。
EvCode
即EventCode简称,标识事件的类型以及事件所附带的信息。
Operation
对在Photon服务器端上远程方法调用的另外一种叫法。客户端使用operation可以在服务器上做任何事情,甚至可以发送event给其他客户端。
OpCode
“Operation Code”的简称。byte类型,用于触发服务器端操作,客户端获取操作返回结果,用opCodes判断返回动作类型。
PhotonControl
Photon的管理工具,打开PhotonControl.exe文件即可开启一个托盘应用。
PhotonServer.config
Photon引擎的配置文件,主要用于IP、应用以及性能检测设置。以前叫PhotonSocketServer.xml,目前刚刚改为PhotonSocketServer.config。
Timeout
使用eNet方式,客户端和服务器端都监视对方消息是否可靠,如果检测到长时间没有回应,则会断开连接。
Unreliable
不可靠的命令则不需要对方回应,它顺序发送数据,可能会有数据丢失,数据序列有“漏洞”。
通信过程
服务器端
1.在VS2010环境下建立一个空项目
2.添加引用
ExitGames.dll;
Photon.SocketServer.dll;
PhotonHostRuntimeInterfaces.dll;
3.创建一个类命名为Program.cs,添加Using
4.Program继承于ApplicationBase类,并实现其抽象类方法
5.添加一个类GamePeer.cs,同上添加Using,该Peer继承PeerBase类,实现其抽象类方法
6.生成项目保存到SimpleDemo/bin文件夹下,把SimpleDemo文件夹放到Photon 的deploy文件夹内(具体路径:../你的Photon解压文件夹/deploy)
7.配置Photon,根据你的系统,win7 64位打开deploy/bin_Win64文件夹下的PhotonServer.config文件,用txt打开,找到节点<Applications></Applications>,在此之内添加配置
<Application
Name="SimpleDemo"
BaseDirectory="SimpleDemo"
Assembly="SimpleDemo"
Type="SimpleDemo.Program"
ForceAutoRestart="true"
WatchFiles="dll;config"
ExcludeFiles="log4net.config">
</Application>
保存。 其中Name是应用程序(ServerApp)名字,BaseDirectory是应用程序(SimpleDemo/bin)所在文件夹,Assembly是应用程序集名称(在VS项目属性可以看到),Type指应用程序主程序名(相当于C#中Main函数所在文件名,本例中指Program.cs)(即继承于ApplicationBase类的),后边的是配置文件信息。
8.配置好后,打开同级目录下PhotonControl.exe程序即开启Photon程序,然后在任务栏旁边的Photon图标上右键Default/Start as application启动服务器,如果没有问题,Photon图标由灰色变成蓝色,表示启动成功,也可以右键Open Logs打开Log界面,看到Log信息“Server is running”则服务器启动了。
客户端(unity3d)
1.首先导入Photon SDK(Photon3Unity3D.dll)到unity工程,
2.创建客户端Peer类(ClientPeer.cs),添加Using,并继承IPhotonPeerListener类,而且实现其抽象类方法
3.连接到服务器,设置好服务器地址(包括端口号,一般使用Udp是5055)和服务器名称;然后创建Peer进行连接;
本地可以写成(“localhost:5055”),ServerApp指SimpleDemo
在Start()方法里连接服务器
在Update()方法里保持连接
4.实现ClientPeer中public void OnStatusChanged(StatusCode statusCode)方法,获取连接状态。
运行Unity3d,如果连接畅通,则Debug(“Connected”)信息。
通信操作
1.客户端向服务器发送数据
ClientPeer使用OpCustom方法向服务器发送数据
带三个参数 opCode:操作数,Parameters:内容(字典类型),SendReliable:是否可靠传输;
如:按下B,向服务器发送代号为201的操作;
2.服务端处理客户端请求
客户端发出的所有服务器请求都会在GamePeer类中的OnOperationRequest方法里接收到(丢包除外),接收到的参数operationRequest包括OpCode和Parameters,通过Opcode判断操作类型;
接收到代号为201的操作后,服务器向客户端发送一个Response(代号为99,带一个字符串数据),该Response只有发送201的Peer才能接收到。服务端也可以向客户端发送一个事件:
该事件所有连接上的Peer都能收到代码为100的消息事件。
3.客户端处理服务端发来的消息
所有服务端发来的Response消息都会在OnOperationResponse里接收,
4.所有服务端发来的Events事件都会在OnEvent里接收到
写点什么 人生杂谈
有时候总感觉得写点什么,却又不知道该写什么,觉得没什么可写,然后就不了了之了。
曾有多次思如泉涌的瞬间,有很多想表达的东西,关于人生,关于感悟,关于梦想,以为众多的思绪可以变成华丽的诗文,以为可以信手拈来,提笔即是篇章,却奈何腹中只剩零零散散的几个词语,越漂越远。
写点什么无非缅怀过去要么想想未来又或者只是一时冲动,很多时候开始都是想写点什么,然后什么都应该写点,到最后也不知道写的什么。人生又何偿不如是呢?有人说人生这条长河里,左岸是无法忘怀的记忆,右岸是可以憧憬的美好未来,中间流淌着的是值得奋斗的青春和隐隐的伤感。已过弱冠之年,人生正处于急流中间,有很多孩童时的快乐想去找回,却发现面对快步入而立的人生时,只有无能为力和伤感。曾经我一直在想什么是人生,生不带来死不带去的,人生又有什么意义?
过去是美好的。人却总喜欢在失去了的时候才发现曾经的美好,才去怀念。其实,每个人都是第一次做人,没有彩排,每天都不知道会发生什么,每天都是未知,走过那么多的岁月,会发现有很多没有把握的青春,也留下了不少的遗憾,同时也经历风雨变得成熟果敢。后来才想明白,原来人生本没有任何意义,而我们要做的则给人生添加意义。过去的每一天都是积累,是以后丰富人生的度量,。。。
有人说二十五是人生的一个转折,在这个尴尬的年纪,年经又不年经,懂又不懂,一无所有的时候,总以为自己有足够的资本去拼搏,仔细算来却发现还有很多事情没有去尝试,很多儿时的梦想尚未开始,回想当初的踌躇满志,个性与张扬,终究还是年少轻狂。
使用Fragment实现底部Tab标签切换界面功能 安卓应用开发
使用Fragment实现底部Tab标签切换界面功能
主界面布局
<?xml version="1.0" encoding="utf-8"?> <android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:fitsSystemWindows="true" tools:context="com.loccy.loccy.MainActivity"> <RelativeLayout android:id="@+id/rl_main" android:layout_width="match_parent" android:layout_height="match_parent"> <!--<RelativeLayout--> <!--android:id="@+id/top_tab"--> <!--android:layout_width="match_parent"--> <!--android:layout_height="50dip"--> <!--android:background="#948a8a">--> <!--<ImageView--> <!--android:id="@+id/logo"--> <!--android:layout_width="match_parent"--> <!--android:layout_height="match_parent"--> <!--android:layout_centerInParent="true"--> <!--android:background="#f00"/>--> <!--</RelativeLayout>--> <LinearLayout android:id="@+id/ll_bottom_tab" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:gravity="center_vertical" android:orientation="horizontal" android:baselineAligned="true" android:background="#dadada"> <RelativeLayout android:id="@+id/rl_tab_homepage" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1"> <ImageView android:id="@+id/iv_tab_homepage" android:layout_width="26dp" android:layout_height="26dp" android:paddingTop="5dp" android:layout_centerHorizontal="true" android:src="@drawable/tab_homepage_checked" android:contentDescription="@null"/> <TextView android:id="@+id/tv_tab_homepage" android:layout_width="wrap_content" android:layout_height="wrap_content" android:paddingBottom="3dp" android:layout_below="@+id/iv_tab_homepage" android:layout_centerHorizontal="true" android:text="@string/tab_homepage" android:textColor="@color/tab_item_checked" android:textSize="14sp"/> </RelativeLayout> <RelativeLayout android:id="@+id/rl_tab_activity" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1"> <ImageView android:id="@+id/iv_tab_activity" android:layout_width="26dp" android:layout_height="26dp" android:paddingTop="5dp" android:layout_centerHorizontal="true" android:src="@drawable/tab_me_normal" android:contentDescription="@null"/> <TextView android:id="@+id/tv_tab_activity" android:layout_width="wrap_content" android:layout_height="wrap_content" android:paddingBottom="3dp" android:layout_below="@+id/iv_tab_activity" android:layout_centerHorizontal="true" android:text="@string/tab_activity" android:textColor="@color/tab_item_normal" android:textSize="14sp"/> </RelativeLayout> <RelativeLayout android:id="@+id/rl_tab_message" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1"> <ImageView android:id="@+id/iv_tab_message" android:layout_width="26dp" android:layout_height="26dp" android:paddingTop="5dp" android:layout_centerHorizontal="true" android:src="@drawable/tab_message_normal" android:contentDescription="@null"/> <TextView android:id="@+id/tv_tab_message" android:layout_width="wrap_content" android:layout_height="wrap_content" android:paddingBottom="3dp" android:layout_below="@+id/iv_tab_message" android:layout_centerHorizontal="true" android:text="@string/tab_message" android:textColor="@color/tab_item_normal" android:textSize="14sp"/> </RelativeLayout> <RelativeLayout android:id="@+id/rl_tab_me" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1"> <ImageView android:id="@+id/iv_tab_me" android:layout_width="26dp" android:layout_height="26dp" android:paddingTop="5dp" android:layout_centerHorizontal="true" android:src="@drawable/tab_me_normal" android:contentDescription="@null"/> <TextView android:id="@+id/tv_tab_me" android:layout_width="wrap_content" android:layout_height="wrap_content" android:paddingBottom="3dp" android:layout_below="@+id/iv_tab_me" android:layout_centerHorizontal="true" android:text="@string/tab_me" android:textColor="@color/tab_item_normal" android:textSize="14sp"/> </RelativeLayout> </LinearLayout> <View android:id="@+id/line" android:layout_width="match_parent" android:layout_height="1dp" android:layout_above="@id/ll_bottom_tab" android:background="#cfcece"> </View> <LinearLayout android:id="@+id/content_layout" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_above="@+id/line" android:orientation="vertical"> </LinearLayout> </RelativeLayout> </android.support.design.widget.CoordinatorLayout>
主Activity控制切换
package com.loccy.loccy; import android.app.FragmentTransaction; import android.os.Bundle; import android.support.v4.app.Fragment; import android.support.v7.app.AppCompatActivity; import android.view.View; import android.view.Menu; import android.view.MenuItem; import android.widget.ImageView; import android.widget.RelativeLayout; import android.widget.TextView; public class MainActivity extends AppCompatActivity implements View.OnClickListener{ private RelativeLayout tab_homepage_lt,tab_activity_lt,tab_message_lt,tab_me_lt; private Fragment homepage_fm,activity_fm,message_fm,me_fm,curFragment; private static final int TABCOUNT = 4; private ImageView[] tab_item_imgs = new ImageView[TABCOUNT]; private TextView[] tab_item_txts = new TextView[TABCOUNT]; private int[] img_ids = new int[]{R.id.iv_tab_homepage,R.id.iv_tab_activity,R.id.iv_tab_message,R.id.iv_tab_me}; private int[] txt_ids = new int[]{R.id.tv_tab_homepage,R.id.tv_tab_activity,R.id.tv_tab_message,R.id.tv_tab_me}; private int[] img_nor_ids = new int[]{R.drawable.tab_homepage_normal,R.drawable.tab_me_normal,R.drawable.tab_message_normal,R.drawable.tab_me_normal}; private int[] img_chd_ids = new int[]{R.drawable.tab_homepage_checked,R.drawable.tab_me_checked,R.drawable.tab_message_checked,R.drawable.tab_me_checked}; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); InitUI(); InitTab(); } void InitUI(){ tab_homepage_lt = (RelativeLayout)findViewById(R.id.rl_tab_homepage); tab_activity_lt = (RelativeLayout)findViewById(R.id.rl_tab_activity); tab_message_lt = (RelativeLayout)findViewById(R.id.rl_tab_message); tab_me_lt = (RelativeLayout)findViewById(R.id.rl_tab_me); tab_homepage_lt.setOnClickListener(this); tab_activity_lt.setOnClickListener(this); tab_message_lt.setOnClickListener(this); tab_me_lt.setOnClickListener(this); for(int i=0;i<TABCOUNT;i++){ tab_item_imgs[i] = (ImageView)findViewById(img_ids[i]); tab_item_txts[i] = (TextView)findViewById(txt_ids[i]); } } void InitTab() { if (homepage_fm == null) homepage_fm = new HomeFragment(); if(!homepage_fm.isAdded()){ getSupportFragmentManager().beginTransaction().add(R.id.content_layout,homepage_fm).commit(); curFragment = homepage_fm; for(int i=0;i<TABCOUNT;i++){ if(i==0){ tab_item_imgs[i].setImageResource(img_chd_ids[i]); tab_item_txts[i].setTextColor(getResources().getColor(R.color.tab_item_checked)); } else { tab_item_imgs[i].setImageResource(img_nor_ids[i]); tab_item_txts[i].setTextColor(getResources().getColor(R.color.tab_item_normal)); } } } } @Override public void onClick(View v) { switch (v.getId()){ case R.id.rl_tab_homepage:onClickTab(0);break; case R.id.rl_tab_activity:onClickTab(1);break; case R.id.rl_tab_message:onClickTab(2);break; case R.id.rl_tab_me:onClickTab(3);break; } } void onClickTab(int index){ switch (index){ case 0:{ if (homepage_fm == null) homepage_fm = new HomeFragment(); addOrShowFragment(homepage_fm); } break; case 1:{ if (activity_fm == null) activity_fm = new ActivityFragment(); addOrShowFragment(activity_fm); } break; case 2:{ if (message_fm == null) message_fm = new MessageFragment(); addOrShowFragment(message_fm); } break; case 3:{ if (me_fm == null) me_fm = new MeFragment(); addOrShowFragment(me_fm); } break; default:break; } for(int i=0;i<TABCOUNT;i++){ if(i==index){ tab_item_imgs[i].setImageResource(img_chd_ids[i]); tab_item_txts[i].setTextColor(getResources().getColor(R.color.tab_item_checked)); } else { tab_item_imgs[i].setImageResource(img_nor_ids[i]); tab_item_txts[i].setTextColor(getResources().getColor(R.color.tab_item_normal)); } } } private void addOrShowFragment(Fragment fragment){ if(curFragment==fragment) return; if(!fragment.isAdded()) { getSupportFragmentManager().beginTransaction().hide(curFragment).add(R.id.content_layout, fragment).commit(); } else { getSupportFragmentManager().beginTransaction().hide(curFragment).show(fragment).commit(); } curFragment = fragment; } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.menu_main, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { // Handle action bar item clicks here. The action bar will // automatically handle clicks on the Home/Up button, so long // as you specify a parent activity in AndroidManifest.xml. int id = item.getItemId(); //noinspection SimplifiableIfStatement if (id == R.id.action_settings) { return true; } return super.onOptionsItemSelected(item); } }
Fragment布局
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <RelativeLayout android:id="@+id/top_tab" android:layout_width="match_parent" android:layout_height="50dip" android:background="#948a8a" android:layout_weight="1"> <ImageView android:id="@+id/logo" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_centerInParent="true" android:background="#837a7a"/> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" android:text="@string/tab_homepage" android:textColor="@color/white" android:textSize="24sp"/> <Button android:id="@+id/locate_btn" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentLeft="true" android:background="#0000" android:text="深圳" android:textSize="24sp"/> </RelativeLayout> </LinearLayout>
Fragment代码
package com.loccy.loccy;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.Toast;
/**
* Created by Loccy on 16/3/17.
*/
public class HomeFragment extends Fragment{
private Button search_btn,locate_btn;
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
//return super.onCreateView(inflater, container, savedInstanceState);
View view = inflater.inflate(R.layout.fragment_homepage,container,false);
locate_btn = (Button)view.findViewById(R.id.locate_btn);
locate_btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(getContext(), "Locate", Toast.LENGTH_SHORT).show();
}
});
return view;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
}
Lightmap在PC上与android和ios的区别以及解决方法 Unity游戏研究
原文:http://www.ceeger.com/forum/read.php?tid=24457&fid=2
Lightmap在PC上与android和ios的区别以及解决方法
1、 问题描述
相信很多人碰到过Lightmap的一些问题:
烘培好Lightmap之后,在PC上看起来相当给力,而打包成ios或android之后,就傻眼了,Lightmap往往就出现了改变,例如灯光曝光度不够、光照颜色偏冷色调、有时候甚至黄色光也能变成绿色光等等。
2、造成Lightmap在PC、ios和android上表现不同的原因。
在u3d里,Lightmap的格式是.exr(openEXR),exr格式的储存方式是使用4*16Bit RGBA来储存数据的,即是说,它使用四个通道分别为RGB和alpha,每个通道占16位储存空间,每个像素占48位储存空间来储存数据。所以EXR格式的图片颜色值域范围就达到了[-65504,65504],远大于8bit(颜色值域[0,255],用浮点数表示就是[0,1])格式所能储存的数值范围。
但是EXR格式的Lightmap打包成 android或ios之后,就变成LDR格式(可能是单通道8bit)的了,这就丢失的很多光照信息。例如在PC上烘培出的灯光亮度值是2000,转变成LDR格式后,亮度值就变成了255,这就是为什么打包成android或ios后灯光曝光度不够、光照颜色偏冷色调的原因。
3、 解决方法。
HDR有几种比较常见的编码格式,这里用的编码格式是LogLuv,就是将RGBA_FP32bit(每个通道32bit或16bit)的数据编码到RGBA32(每个通道8bit)的图片中。LogLuv算法几乎能100%还原unity切换平台后导致Lightmap丢掉的精度信息,算法如下:
//FP32(RGB) to LogLUV fixed4 EncodeLogLuv(fixed3 vRGB) { fixed3x3 M = fixed3x3( 0.2209, 0.3390, 0.4184, 0.1138, 0.6780, 0.7319, 0.0102, 0.1130, 0.2969 ); fixed4 vResult; fixed3 Xp_Y_XYZp = mul(vRGB, M); Xp_Y_XYZp = max(Xp_Y_XYZp, fixed3(1e-6, 1e-6, 1e-6)); vResult.xy = Xp_Y_XYZp.xy / Xp_Y_XYZp.z; fixed Le = 2 * log2(Xp_Y_XYZp.y) + 127; vResult.w = frac(Le); vResult.z = (Le - (floor(vResult.w*255.0f)) / 255.0f) / 255.0f; return vResult; } //LogLuv to FP32(RGB) fixed3 DecodeLogLuv(in fixed4 vLogLuv) { fixed3x3 InverseM = fixed3x3( 6.0014, -2.7008, -1.7996, -1.3320, 3.1029, -5.7721, 0.3008, -1.0882, 5.6268 ); fixed Le = vLogLuv.z * 255 + vLogLuv.w; fixed3 Xp_Y_XYZp; Xp_Y_XYZp.y = exp2((Le - 127) / 2); Xp_Y_XYZp.z = Xp_Y_XYZp.y / vLogLuv.y; Xp_Y_XYZp.x = vLogLuv.x * Xp_Y_XYZp.z; fixed3 vRGB = mul(Xp_Y_XYZp, InverseM); return max(vRGB, 0); }
4、 实现步骤
1、 在PC平台烘培好光照贴图Lightmap_PC(.exr格式)。
2、 通过Lightmap_PC生成新的光照贴图Lightmap_LogLuv(.png格式,RGBA32bit,单通道是8bit)。生成过程就用上面提到的LogLuv算法进行编码。这里用GPU来进行生成,有类似GPGPU的思想。如下:
//用LogLuv算法生成的Lightmap输出到temp上,然后就将temp保存到一张.png格式的图片。 public bool SaveRenderTextureToPNG(Texture inputTex,Shader outputShader, string contents, string pngName) { RenderTexture temp = RenderTexture.GetTemporary(inputTex.width, inputTex.height, 0, RenderTextureFormat.ARGB32); Material mat = new Material(outputShader); Graphics.Blit(inputTex, temp, mat); bool ret = SaveRenderTextureToPNG(temp, contents,pngName); RenderTexture.ReleaseTemporary(temp); return ret; } //将RenderTexture保存成一张png图片 public bool SaveRenderTextureToPNG(RenderTexture rt,string contents, string pngName) { RenderTexture prev = RenderTexture.active; RenderTexture.active = rt; Texture2D png = new Texture2D(rt.width, rt.height, TextureFormat.ARGB32, false); png.ReadPixels(new Rect(0, 0, rt.width, rt.height), 0, 0); byte[] bytes = png.EncodeToPNG(); if (!Directory.Exists(contents)) Directory.CreateDirectory(contents); FileStream file = File.Open(contents + "/" + pngName + ".png", FileMode.Create); BinaryWriter writer = new BinaryWriter(file); writer.Write(bytes); file.Close(); Texture2D.DestroyImmediate(png); png = null; RenderTexture.active = prev; return true; }
3、 用新生成的光照贴图Lightmap_LogLuv替换原来的光照贴图Lightmap_PC。因为Lightmap_PC在切换android或ios会自动将Lightmap_PC压缩为LDR格式,这就丢失了精度。
5、编写生成工具
我已经写好了一个简单的工具,可以将当前的场景下所有用Diffuse Shader的模型自动替换成新的Shader,改新的Shader将不再使用Unity原来.EXR格式的光照贴图,而是使用新生成的光照贴图。
将会在” Assets/Data/Lightmap/当前场景名字”目录下生成对应的光照贴图,如下:
将当前的场景下所有用Diffuse Shader的模型自动替换成新的Shader,如下:
UGUI不规则形状按钮 各种技巧
using UnityEngine; using System; using System.Collections; using UnityEngine.UI; public class RaycastFilter : MonoBehaviour, ICanvasRaycastFilter { private RectTransform rectTransform; private Image image; public void Awake() { collider2D = GetComponent<BoxCollider2D>(); image = GetComponent<Image>(); } public bool IsRaycastLocationValid(Vector2 screenPosition, Camera raycastEventCamera) //uGUI callback { if (image == null) return true; Vector2 localPoint; RectTransformUtility.ScreenPointToLocalPointInRectangle(rectTransform, screenPosition, raycastEventCamera, out localPoint); var normalized = new Vector2( (localPoint.x + rectTransform.pivot.x*rectTransform.rect.width)/rectTransform.rect.width, (localPoint.y + rectTransform.pivot.y*rectTransform.rect.height)/rectTransform.rect.width); Rect rect = image.sprite.textureRect; var x = Mathf.FloorToInt(rect.x + rect.width * normalized.x); var y = Mathf.FloorToInt(rect.y + rect.height * normalized.y); try { return image.sprite.texture.GetPixel(x,y).a > 0.2f; } catch (UnityException e) { Debug.LogError("Mask texture not readable, set your sprite to Texture Type 'Advanced' and check 'Read/Write Enabled'"); Destroy(this); return false; } } }
11步让你成为更优秀的程序员 各种技巧
1.永远不要复制代码
不惜任何代价避免重复的代码。如果一个常用的代码片段出现在了程序中的几个不同地方,重构它,把它放到一个自己的函数里。重复的代码会导致你的同事在读你的代码时产生困惑。而重复的代码如果在一个地方修改,在另外一个地方忘记修改,就会产生到处是bug,它还会使你的代码体积变得臃肿。现代的编程语言提供了很好的方法来解决这些问题,例如,下面这个问题在以前很难解决,而如今使用lambdas却很好实现:

现在我们重构含有部分相同代码的函数,用delegate模式重写它们:

2. 留意你开始分心的时候
当你发现自己在浏览facebook或微博、而不是在解决问题,这通常是一种你需要短暂休息的信号。离开办公桌,去喝一杯咖啡,或去跟同事聊5分钟。尽管这样做看起来有点反直觉,但长久去看,它会提高你的工作效率。
3. 不要匆忙赶任务而放弃原则
当带着压力去解决一个问题或修改一个bug,你很容易失去自制,发现自己匆匆忙忙,甚至完全忘了一直坚持的重要的测试过程。这通常会导致更多的问题,会让你在老板或同事眼里显得很不专业。
4. 测试你完成的代码
你知道你的代码能做什么,而且试了一下,它确实好用,但你实际上需要充分的验证它。分析所有可能的边界情况,测试在所有可能的条件下它都能如期的工作。如果有参数,传递一些预期范围外的值。传递一个null值。如果可能,让同事看看你的代码,问他们能否弄坏它。单元测试是到达这种目的的常规方法。
5. 代码审查
提交你的代码之前,找个同事一起坐下来,向他解释你做了哪些修改。通常,这样做的过程中你就能发现代码中的错误,而不需要同事说一句话。这比自己审查自己的代码要有效的多得多。
6. 让代码更少
如果你发现写了大量的代码来解决一个简单的问题,你很可能做错了。下面的boolean用法是一个很好的例子:

这时你应该写成这样:

代码越少越好。这会使bug更少,重构可能性更小,出错的几率更小。要适度。可读性同等重要,你可不能这样做而使代码丧失可读性。
7. 为优雅的代码而努力
优雅的代码非常的易读,只用手边很少的代码、让机器做很少的运算就能解决问题。在各种环境中都做到代码优雅是很难的,但经过一段时间的编程,你会对优雅的代码是个什么样子有个初步的感觉。优雅的代码不会通过重构来获得。当你看到优雅的代码是会很高兴。你会为它自豪。例如,下面就是一个我认为是优雅的方式来计算多边形面积的方法:

8. 编写不言自明的代码
勿庸置疑,注释是编程中很重要的一部分,但能够不言自明的代码跟胜一筹,因为它能让你在看代码时就能理解它。函数名变量名要慎重选择,好的变量/方法名字放到语言语义环境中时,不懂编程的人都能看懂。例如:

能自我说明的代码不能代替注释。注释是用来解释“为什么”的,而自我说明的代码是来描述“是什么”的。
9. 不要使用纯数字
直接把数字嵌入代码中是一种恶习,因为无法说明它们是代表什么的。当有重复时更糟糕——相同的数字在代码的多个地方出现。如果只修改了一个,而忘记了其它的。这就导致bug。一定要用一个命名常量来代表你要表达的数字,即使它在代码里只出现一次。
10. 不要做手工劳动
当做一系列动作时,人类总是喜欢犯错误。如果你在做部署工作,并且不是一步能完成的,那你就是在做错事。尽量的让工作能自动化的完成,减少人为错误。当做工作量很大的任务时,这尤其重要。
11. 避免过早优化
当你要去优化一个已经好用的功能代码时,你很有可能会改坏它。优化只能发生在有性能分析报告指示需要优化的时候,通常是在一个项目开发的最后阶段。性能分析之前的优化活动纯属浪费时间,并且会导致bug出现。
来源:http://www.manew.com/thread-47665-1-1.html
Unity A*寻路 C# Unity游戏研究
首先看了这篇翻译外国人的文章http://www.raywenderlich.com/zh-hans/21503/a%E6%98%9F%E5%AF%BB%E8%B7%AF%E7%AE%97%E6%B3%95%E4%BB%8B%E7%BB%8D