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适用于键值表。


new 发布于 2016-9-19 08:06

skynet研究001——启动流程 Skynet笔记

一篇比较初级的skynet入门教程,见附件。

Skynet框架之菜鸟手册-2.pdf


new 发布于 2016-7-25 09:26

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


标签: skynet

new 发布于 2016-7-25 08:55

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里接收到

 

 

 

 

 

 

 

 

 

 


new 发布于 2016-4-19 03:25

写点什么 人生杂谈

有时候总感觉得写点什么,却又不知道该写什么,觉得没什么可写,然后就不了了之了。

曾有多次思如泉涌的瞬间,有很多想表达的东西,关于人生,关于感悟,关于梦想,以为众多的思绪可以变成华丽的诗文,以为可以信手拈来,提笔即是篇章,却奈何腹中只剩零零散散的几个词语,越漂越远。

写点什么无非缅怀过去要么想想未来又或者只是一时冲动,很多时候开始都是想写点什么,然后什么都应该写点,到最后也不知道写的什么。人生又何偿不如是呢?有人说人生这条长河里,左岸是无法忘怀的记忆,右岸是可以憧憬的美好未来,中间流淌着的是值得奋斗的青春和隐隐的伤感。已过弱冠之年,人生正处于急流中间,有很多孩童时的快乐想去找回,却发现面对快步入而立的人生时,只有无能为力和伤感。曾经我一直在想什么是人生,生不带来死不带去的,人生又有什么意义?

过去是美好的。人却总喜欢在失去了的时候才发现曾经的美好,才去怀念。其实,每个人都是第一次做人,没有彩排,每天都不知道会发生什么,每天都是未知,走过那么多的岁月,会发现有很多没有把握的青春,也留下了不少的遗憾,同时也经历风雨变得成熟果敢。后来才想明白,原来人生本没有任何意义,而我们要做的则给人生添加意义。过去的每一天都是积累,是以后丰富人生的度量,。。。

有人说二十五是人生的一个转折,在这个尴尬的年纪,年经又不年经,懂又不懂,一无所有的时候,总以为自己有足够的资本去拼搏,仔细算来却发现还有很多事情没有去尝试,很多儿时的梦想尚未开始,回想当初的踌躇满志,个性与张扬,终究还是年少轻狂。


new 发布于 2016-4-18 02:28

使用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);
}
}
标签: Android Tab

new 发布于 2016-3-18 00:40

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、造成LightmapPCiosandroid上表现不同的原因。 

在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,如下:

原文:http://www.ceeger.com/forum/read.php?tid=24457&fid=2


new 发布于 2016-3-11 09:24

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;
  }
 }
}
标签: uGUI

new 发布于 2016-3-3 05:51

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


new 发布于 2016-3-1 01:50

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



1.定义地图节点,及初始化地图数据

using UnityEngine;
using System.Collections.Generic;

public class Map
{
    /// <summary>
    /// 初始化地图
    /// </summary>
    /// <returns></returns>
    public static Dictionary<string, MapInfo> GetMap()
    {
        Dictionary<string, MapInfo> temp = new Dictionary<string, MapInfo>();

        for (int i = 0; i < 10; i++)
        {
            string s = "";
            for (int j = 0; j < 10; j++)
            {
                int tt = 0;
                if (i > 1 && i < 8 && j == 5)
                {
                    tt = 1;
                }
                MapInfo mi = new MapInfo(i, j, tt);
                temp.Add(i + "-" + j, mi);
                s += mi.tag + " ";
            }
            Debug.Log(s);
        }
        return temp;
    }
}

/// <summary>
/// 地图节点
/// </summary>
public class MapInfo
{
    /// <summary>
    /// X
    /// </summary>
    public int x;
    /// <summary>
    /// Y
    /// </summary>
    public int y;
    /// <summary>
    /// 是否可行走
    /// </summary>
    public int tag;
    /// <summary>
    /// G
    /// </summary>
    public int gValue;
    /// <summary>
    /// H
    /// </summary>
    public int hValue;
    /// <summary>
    /// 父节点
    /// </summary>
    public MapInfo parent;

    public MapInfo()
    { }

    /// <summary>
    /// 构造
    /// </summary>
    /// <param name="x"></param>
    /// <param name="y"></param>
    /// <param name="tag"></param>
    public MapInfo(int x, int y,int tag)
    {
        this.x = x;
        this.y = y;
        this.tag = tag;
        this.gValue = 0;
        this.hValue = 0;
        this.parent = null;
    }
}

2.由起点终点寻路,有注释,知道原理的话,应该很容易懂

using UnityEngine;
using System.Collections.Generic;

public class AStar : MonoBehaviour
{
    /// <summary>
    /// 地图
    /// </summary>
    Dictionary<string, MapInfo> map;
    /// <summary>
    /// open列表
    /// </summary>
    Dictionary<string, MapInfo> openList = new Dictionary<string, MapInfo>();
    /// <summary>
    /// close列表
    /// </summary>
    Dictionary<string, MapInfo> closeList = new Dictionary<string, MapInfo>();

    /// <summary>
    /// 当前点
    /// </summary>
    MapInfo currentV;
    /// <summary>
    /// 当前点的相邻节点列表
    /// </summary>
    Dictionary<string, MapInfo> adjancentMap;

    // Use this for initialization
    void Start () 
    {
        map = Map.GetMap();
        MapInfo st = map["5-2"];//start
        MapInfo end = map["6-8"];//end

        FindPath(st, end);
    }

    /// <summary>
    /// 寻路
    /// </summary>
    /// <param name="start">起点</param>
    /// <param name="end">终点</param>
    public void FindPath(MapInfo start,MapInfo end)
    {
        openList.Add(start.x + "-" + start.y, start);

        do
        {
            currentV = GetTheLowestFrom(openList);

            closeList.Add(currentV.x + "-" + currentV.y, currentV);
            openList.Remove(currentV.x + "-" + currentV.y);

            if (closeList.ContainsKey(end.x + "-" + end.y))
            {
                Debug.Log("FindPath");

                PrintThePath(end);
                break;
            }

            adjancentMap = AdjacentList(currentV);

            foreach (string k in adjancentMap.Keys)
            {
                if (closeList.ContainsKey(k))
                {
                    continue;
                }

                if (!openList.ContainsKey(k))
                {
                    adjancentMap[k].parent = currentV;
                    adjancentMap[k].gValue = currentV.gValue + 1;
                    adjancentMap[k].hValue = GetManhattanDistance(adjancentMap[k], end);
                    openList.Add(k, adjancentMap[k]);
                }
                else
                {
                    int g = currentV.gValue + 1;
                    if (g < adjancentMap[k].gValue)
                    {
                        adjancentMap[k].gValue = g;
                        adjancentMap[k].parent = currentV;
                    }
                }
            }

        } while (openList.Count > 0);
    }

    /// <summary>
    /// 获取openlist中F最小的节点
    /// </summary>
    /// <param name="open"></param>
    /// <returns></returns>
    public MapInfo GetTheLowestFrom(Dictionary<string, MapInfo> open)
    {
        MapInfo result=null;
        int min = 10000;
        foreach (MapInfo m in open.Values)
        {
            if (m.gValue + m.hValue < min)
            {
                result = m;
                min = m.gValue + m.hValue;
            }
        }
        return result;
    }

    /// <summary>
    /// 获取当前节点的相邻节点
    /// </summary>
    /// <param name="m">当前节点</param>
    /// <returns></returns>
    public Dictionary<string, MapInfo> AdjacentList(MapInfo m)
    {
        Dictionary<string, MapInfo> resultDic=new Dictionary<string,MapInfo>();

        string left = (m.x - 1) + "-" + m.y;
        string right = (m.x + 1) + "-" + m.y;
        string top = m.x + "-" + (m.y - 1);
        string bot = m.x + "-" + (m.y + 1);

        if (map.ContainsKey(left))
        {
            if(map[left].tag==0)
                resultDic.Add(left, map[left]);
        }

        if (map.ContainsKey(right))
        {
            if (map[right].tag == 0)
                resultDic.Add(right, map[right]);
        }

        if (map.ContainsKey(top))
        {
            if (map[top].tag == 0)
                resultDic.Add(top, map[top]);
        }

        if (map.ContainsKey(bot))
        {
            if (map[bot].tag == 0)
                resultDic.Add(bot, map[bot]);
        }
        return resultDic;
    }

    /// <summary>
    /// 获得两个点的曼哈顿距离
    /// 作为估值函数
    /// </summary>
    /// <param name="st"></param>
    /// <param name="end"></param>
    /// <returns></returns>
    public int GetManhattanDistance(MapInfo st, MapInfo end)
    {
        int result = 0;
        result = Mathf.Abs(st.x - end.x) + Mathf.Abs(st.y - end.y);
        return result;
    }

    /// <summary>
    /// 输出路径
    /// </summary>
    /// <param name="end">终点</param>
    public void PrintThePath(MapInfo end)
    {
        string s = "";
        MapInfo m = end;
        while (m.parent != null)
        {
            s += "("+m.parent.x + "," + m.parent.y + ")->";            
            m = m.parent;
        }
        Debug.Log(s);
    }
}


标签: A Star A*

new 发布于 2016-3-1 01:37